Basic Pytorch

  • 模型构造
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import torch 
from torch import nn
net=nn.Sequential(nn.Linear(20,256),nn.ReLU(),nn.Linear(256,10))
X=torch.normal(0,1,size=(1,20))
print(net(X))

class MLP(nn.Module):
def __init__(self):
super().__init__()
self.rand_weight=torch.randn((20,64),requires_grad=False,dtype=torch.float32)
self.hidden=nn.Sequential(nn.Linear(64,128),nn.ReLU(),nn.Linear(128,256))
self.out=nn.Linear(256,10)

def forward(self,X):
X=X@self.rand_weight+1
X=nn.ReLU()(self.hidden(X))
X=self.out(X)
# 下面这个过程流不会计入计算图
with torch.no_grad():
while torch.abs(X).sum()>1:
X/=2
return X.sum()

net=MLP()
print(net(X))
  • 参数管理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import torch
from torch import nn

net=nn.Sequential(nn.Linear(4,8),nn.ReLU(),nn.Linear(8,1))
X=torch.rand(size=(2,4))

# 访问参数
# 访问网络中每一层,以及如何访问层中的参数
print(net[0].state_dict(),net[1],net[2].bias.data)
# 网络中的参数包括data和grad两部分,在这没做反向传播呢,所以梯度为None
print(net[2].weight.grad==None)
# 将整个网络信息打印
print(net)

# 初始化参数
# pytorch已经为我们做了比较好的默认初始化
def init_xavier(m):
if(type(m)==nn.Linear):
nn.init.xavier_normal_(m.weight)
nn.init.zeros_(m.bias)
def init_42(m):
nn.init.constant_(m.weight,42)
nn.init.constant_(m.bias,42)
# 将初始化函数应用到net每一个子层,不止可以用在初始化上
net[0].apply(init_xavier)
print([i for i in net[0].parameters()])
net[2].apply(init_42)
print(net[2].weight,net[2].bias)

# 更暴力的方法
net[0].weight.data[:]+=100
print(net[0].weight.data)

# 参数绑定
# 让某几层共享同样的参数
shared=nn.Linear(8,8)
net=nn.Sequential(nn.Linear(4,8),nn.ReLU(),shared,nn.ReLU(),shared,nn.Sigmoid(),nn.Linear(8,1))
print(net[2]==shared)
print(net[2].weight.data==net[4].weight.data)
  • 自定义层
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import torch
from torch import nn

# 自定义层和自定义模型没本质区别
class CenteredLayer(nn.Module):
def __init__(self):
super().__init__()

def forward(self,X):

return X-X.mean()

layer=CenteredLayer()
print(layer(torch.tensor([1,2,3,4],dtype=torch.float32)))

# 带有参数的层
class PrameterizedLayer(nn.Module):
def __init__(self,in_dim,out_dim):
super().__init__()
self.w=nn.Parameter(torch.randn((in_dim,out_dim)))
self.b=nn.Parameter(torch.randn((out_dim)))

def forward(self,X):

return X@self.w.data+self.b.data

net=PrameterizedLayer(2,8)
print(net(torch.tensor([[1,2],[2,3],[3,4]],dtype=torch.float32)))
  • 读写文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import torch
from torch import nn

x=torch.arange(4)
# 加载和保存张量
torch.save(x,'x_file')
y=torch.load('x_file')
print(x==y)

# 加载和保存张量组成的数据结构
a=torch.arange(5)
b=torch.arange(5)
torch.save([a,b],"list")
torch.save({'a':a,'b':b},"dict")
# 读取到内存会保持原数据结构
print(torch.load("list"))
print(torch.load("dict"))

# 加载和保存模型的参数
net=nn.Sequential(nn.Conv2d(1,2,5),nn.Flatten(),nn.Linear(288,64))
print(net(torch.normal(0,0.5,size=(1,1,16,16))))
print(net.state_dict())
torch.save(net.state_dict(),'net.params')
new_net=nn.Sequential(nn.Conv2d(1,2,5),nn.Flatten(),nn.Linear(288,64))
new_net.load_state_dict(torch.load('net.params'))
print(new_net==net)

X=torch.normal(0,0.5,size=(1,1,16,16))
print(new_net(X)==net(X))