前一篇介绍了pytorch的基本变量、库等知识,这篇着重介绍pytorch的层的功能。
层
层的定义都在torch.nn
中
- 全连接层:
torch.nn.Linear()
- ReLU激活层:
torch.nn.ReLU()
- Drop层:
torch.nn.Dropout(p=0.5)
- 卷积层:
torch.nn.Conv2d(1,64,kernel_size = 3,strid = 1,padding =1)
- 池化层:
torch.nn.MaxPool2d(strid = 2,kernel_size = 2)
- 归一层:
torch.nn.BatchNorm1d(in_channels * A.size(1))
网络的搭建
5.重写Model 类
在Model类中可以实现网络结构以及前向、候选传播函数
1 | class Model(torch.nn.Module): |
Model
Model 类来自package: torch.nn.Module
其中会有定义的网络Sequential参数,比如定义了 conv1
在其下有_modules
参数:可以在着拉看到每一层的data。在该层变量中,可以看到其中包含的参数,其中比较重要的是:
weight
bias
dense
已有模型的加载loadModel
model.load_state_dict(torch.load("checkPoints/LLModel_0708_21:54:25.pth"))
model
的加载是使用.load_state_dict()
torch.load("checkPoints/LLModel_0708_21:54:25.pth")
这个得到的是一个OrderDict
,包含了每一层的参数(有参数的参数层,像Pool层是没有的)1
2
3
4
5
6
7
8model_path = "/home/joey/Documents/models"
# model = models.resnet50(pretrained=True)
# # model_modules = model._modules
# features = model.features
model_name = "vgg16"
load_model_path = os.path.join(model_path,model_name,"Pytorch",model_name+".pth")
model = models.vgg16(pretrained= False)
model.load_state_dict(torch.load(load_model_path))
Pytorch中的模型层的搭建:
- 使用
nn.Sequential()
来搭建
一个时序容器。Modules 会以他们传入的顺序被添加到容器中。当然,也可以传入一个OrderedDict。nn.Sequential()
的输入参数可以是多个torch.nn.对象。
为了更容易的理解如何使用Sequential, 下面给出了一个例子: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
38def __init__(self):
super(Models, self).__init__()
self.Conv = torch.nn.Sequential(
torch.nn.Conv2d(3, 32, kernel_size=3, stride=1, padding=1),
torch.nn.ReLU(),
torch.nn.Conv2d(32, 32, kernel_size=3, stride=1, padding=1),
torch.nn.ReLU(),
torch.nn.MaxPool2d(kernel_size=2, stride=2),
torch.nn.Conv2d(32, 64, kernel_size=3, stride=1, padding=1),
torch.nn.ReLU(),
torch.nn.Conv2d(64, 64, kernel_size=3, stride=1, padding=1),
torch.nn.ReLU(),
torch.nn.MaxPool2d(kernel_size=2, stride=2)
)
self.Classes = torch.nn.Sequential(
torch.nn.Linear(9 * 9 * 64, 1024),
torch.nn.ReLU(), torch.nn.Dropout(p=0.5),
torch.nn.Linear(1024, 1024),
torch.nn.ReLU(),
torch.nn.Dropout(p=0.5),
torch.nn.Linear(1024, 45)
)
# Example of using Sequential
model = nn.Sequential(
nn.Conv2d(1,20,5),
nn.ReLU(),
nn.Conv2d(20,64,5),
nn.ReLU()
)
# Example of using Sequential with OrderedDict
model = nn.Sequential(OrderedDict([
('conv1', nn.Conv2d(1,20,5)),
('relu1', nn.ReLU()),
('conv2', nn.Conv2d(20,64,5)),
('relu2', nn.ReLU())
]))
OrderedDict
可以存储层的名字,输出是这样的1
2
3
4
5
6(ta): Sequential(
(conv1): Conv2d(1, 20, kernel_size=(5, 5), stride=(1, 1))
(relu1): ReLU()
(conv2): Conv2d(20, 64, kernel_size=(5, 5), stride=(1, 1))
(relu2): ReLU()
)
而直接使用Sequential输出是这样的:1
2
3
4
5
6
7
8
9(Classes): Sequential(
(0): Linear(in_features=5184, out_features=1024, bias=True)
(1): ReLU()
(2): Dropout(p=0.5)
(3): Linear(in_features=1024, out_features=1024, bias=True)
(4): ReLU()
(5): Dropout(p=0.5)
(6): Linear(in_features=1024, out_features=45, bias=True)
)
默认从0开始的标号作为其层的名字
使用
nn.ModuleList()
来搭建nn.ModuleList()
的输入参数是一个元组,包含了所有的Module
而st-gcn
中正是使用ModuleList
来wrapst_gcn
这个自定义层的。1
2
3
4
5
6
7
8
9
10
11
12self.st_gcn_networks = nn.ModuleList((
st_gcn(in_channels, 64, kernel_size, 1, residual=False, **kwargs0),
st_gcn(64, 64, kernel_size, 1, **kwargs),
st_gcn(64, 64, kernel_size, 1, **kwargs),
st_gcn(64, 64, kernel_size, 1, **kwargs),
st_gcn(64, 128, kernel_size, 2, **kwargs),
st_gcn(128, 128, kernel_size, 1, **kwargs),
st_gcn(128, 128, kernel_size, 1, **kwargs),
st_gcn(128, 256, kernel_size, 2, **kwargs),
st_gcn(256, 256, kernel_size, 1, **kwargs),
st_gcn(256, 256, kernel_size, 1, **kwargs),
))使用类属性注册搭建:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18for id in range(self.hiden_Num):
inSize = 1 if id ==0 else 10
fc = nn.Linear(inSize,10)
self.feature.add_module('fc_%i' % id, fc)
# setattr(self.feature, 'fc_%i' % id, fc) # 注意! pytorch 一定要你将层信息变成 class 的属性! 我在这里花了2天时间发现了这个 bug
self._set_init(fc) # 参数初始化
self.fcs.append(fc)
if use_Bn:
bn = nn.BatchNorm1d(10,momentum=0.5)
setattr(self.feature,'bn_%i'%id,bn)
self.bns.append(bn)
re = nn.ReLU()
self.feature.add_module('relu_%i' % id, re)
self.predict = nn.Linear(10, 1) # output layer
self._set_init(self.predict) # 参数初始化
setattr(self.feature, ‘fc_%i’ % id, fc) 也可以在序列中添加层,以达到类似于Sequential(OrderDict[])的效果。1
2
3
4
5
6self.feature = nn.Sequential() # 新建一个序列对象。
inSize = 1 if id ==0 else 10
fc = nn.Linear(inSize,10)
setattr(self.feature, 'fc_%i' % id, fc) #向序列中添加层
re = nn.ReLU()
self.feature.addmodule(‘fc%i’ % id, fc)
也可以调用Sequential
的add_module()
函数添加层
损失函数
cost = torch.nn.CrossEntropyLoss()
softmax
损失
定义cost对象,之后计算只用传入数据即可
需要注意的是loss = cost(y_pred,var_y)
输入时有顺序的先写预测,再写label
cost = torch.nn.MSELoss()
欧式损失
优化算法
optimizer = torch.optim.Adam(model.parameters())
定义opt对象,可采用自定义优化算法,需要将model的参数全部传入,以算法进行计算。
需要注意的是:optimizer.zero_grad()
,每次更新w
前,需要将上一次迭代的梯度清理。
关于data_loader_train
、data
的说明:
data_loader_train
是整个数据集
data_loader_train
一次生成batch_size
个数据shape
= (64,1,28,28)所有第二个for是整个batch_size
的矩阵计算
Model的forward()
自定义Model继承了Module后需要重写父类的 forward()函数即计算整个计算图。y_pred = model(var_x)
需要注意的是:model(var_x)
的输入参数必须是Variable
类型,需要转换。
启动GPU模式
- model.cuda()
- variable(x).cuda()
gpu-cpu数据转化
model = Model()
model.cuda() 开启GPU训练模式
如果要使用GPU训练,则所所有数据必须转换成cuda的形式
cuda_var(x).cpu()1
2
3
4
5
6
7x,y = next(iter(dataloader["test"]))
with torch.no_grad():
x, y = Variable(x).cuda(), Variable(y).cuda()
pre = self.model.forward(x)
plt.plot(x.cpu().numpy(),pre.cpu().numpy(),'x')
plt.plot(x.cpu().detach().numpy(),y.cpu().detach().numpy(),'o')
plt.show()
从PyTorch中取出数据进行numpy操作:
如果对象是Variable类型,取出其数据需要注意以下几点:
- 如果是有grad_requires = True的,当前phase又不需要梯度,那么需要with torch.no_grad()来节约显存资源
- 如果不使用with torch.no_grad,也可以使用x.cpu().detach().numpy()来获得
- 如果在gpu上的数据,需要使用data_x.cpu放在cpu上
- 数据得到后Tensor 2 numpy只需要执行 tesnor.numpy即可