赞
踩
卷积神经网络通常由三部分构成。第一部分是输入层。第二部分由n个卷积层和池化层的组合构成。第三部分由一个全连结的多层感知机分类器构成。
在PyTorch里面编写神经网络,所有的层结构和损失函数都来自于torch.nn,所有的模型构建都继承nn.Module这个基类,于是有了下面的这个模板。
import torch.nn as nn import torch.nn.functional as F class Model(nn.Module): def __init__(self, other_arguments=None): super(Model, self).__init__() self.conv1 = nn.Conv2d(1, 20, 5) self.conv2 = nn.Conv2d(20, 64, 5) # other network layer def forward(self, x): x = F.relu(self.conv1(x)) return F.relu(self.conv2(x)) net = Model() print(net)
Model(
(conv1): Conv2d(1, 20, kernel_size=(5, 5), stride=(1, 1))
(conv2): Conv2d(20, 20, kernel_size=(5, 5), stride=(1, 1))
)
这样就建立了一个计算图,并且这个结构可以复用多次,每次调用就相当于用该计算图定义的参数做一次前向传播,这得益于PyTorch的自动求导功能,所以不需要手动编写反向传播,所有的网络层都由nn这个包提供,可参考官方文档查看详细内容。
官方文档链接: https://pytorch.org/docs/stable/nn.html
此外,还可以使用torch.nn.Sequential,更方便进行模块化的定义,torch.nn.Sequential 其实就是Sequential容器,该容器将一系列操作按先后顺序给包起来,方便重复使用,所以必须确保前一个模块的输出大小和下一个模块的输入大小是一致的。
示例如下:
#首先导入torch相关包 import torch import torch.nn as nn class net_seq(nn.Module): def __init__(self): super(net_seq, self).__init__() self.seq = nn.Sequential( nn.Conv2d(1,20,5), nn.ReLU(), nn.Conv2d(20,64,5), nn.ReLU() ) def forward(self, x): return self.seq(x) net_seq = net_seq() print(net_seq)
net_seq(
(seq): Sequential(
(0): Conv2d(1, 20, kernel_size=(5, 5), stride=(1, 1))
(1): ReLU()
(2): Conv2d(20, 64, kernel_size=(5, 5), stride=(1, 1))
(3): ReLU()
)
)
注: nn.Sequential中可以使用OrderedDict来指定每个module的名字,而不是采用默认的命名方式(按序号 0,1,2,3…)。例子如下:
import torch import torch.nn as nn from collections import OrderedDict class net_seq(nn.Module): def __init__(self): super(net_seq, self).__init__() self.seq = nn.Sequential(OrderedDict([ ('conv1', nn.Conv2d(1,20,5)), ('relu1', nn.ReLU()), ('conv2', nn.Conv2d(20,64,5)), ('relu2', nn.ReLU()) ])) def forward(self, x): return self.seq(x) net_seq = net_seq() print(net_seq)
net_seq(
(seq): 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()
)
)
PyTorch中提供了一些便于用户构建神经网络的Containers即容器,比较常见的有Module、 ModuleList、Sequential和ModuleDict等。Module是构建神经网络的基类。一个神经网络模型可以包含PyTorch提供的各种Layer,也可以包含容器,如ModuleList、ModuleDict等。
Containers链接: https://pytorch.org/docs/stable/nn.html#containers
(1)当用于大量重复Layer构建时(常用for循环),推荐使用ModuleList实现网络结构。
(2)当网络中Layer严格按顺序执行(常用于block构建),推荐使用Sequential实现网络结构。
(3)当需要可选择的网络Layer时,推荐使用ModuleDict实现网络结构。
(4)当需要记录每个Layer的输出信息或在Layer之间进行跳跃连接(skip connection),即当需要定制化forward函数中各Layer的数据流入时,推荐使用ModuleList实现网络结构。
ModuleList和ModuleDict中各Layer的参数已被自动注册;
ModuleList中各Layer的顺序并不是网络的执行顺序,网络的执行顺序由forward函数定义的数据流方向决定;
Sequential中Layer的顺序表示网络的执行顺序;
当网络具有“索引”特性时,推荐使用ModuleDict;
当网络具有“顺序”特性时,推荐使用Sequential;
当网络具有“重复”特性时 或 需要定制化forward函数中各Layer的数据流入时或Layer之间存在skip connection时,推荐使用ModuleList。
PyTorch官方提供了常见的开源模型结构,可直接使用,并且提供了预训练模型,可帮助进行迁移学习。
预训练模型: https://github.com/pytorch/vision/tree/master/torchvision/models
预训练模型包括:
AlexNet、DenseNet、GoogleNet、Inception、mnasNet、MobileNet、ResNet、ShuffleNet、SqueezeNet、VGGNet等等。
网络结构Module包含很多属性,可以查看权重、参数等等。迭代训练的过程就是不断更新模型中的权重,来拟合训练数据的分布情况。
迭代model.named_parameters(),将会输出每一次迭代元素的名字和param。
for name, param in model.named_parameters():
print(name,param.requires_grad)
param.requires_grad=False
迭代model.parameters(),将会输出每一次迭代元素的param而不会打印名字,这是它和named_parameters的区别,两者都可以用来改变requires_grad的属性。
for param in model.parameters():
print(param.requires_grad)
param.requires_grad=False
model.state_dict().items() 每次迭代会输出模型的name和param,但是这里的所有的param都是requires_grad=False,没有办法改变requires_grad的属性,所以改变requires_grad的属性只能通过上面的两种方式。
for name, param in model.state_dict().items():
print(name,param.requires_grad)
模型的定义就是先继承,再构建组件,最后组装。
其中基本组件可从 torch.nn中获取,或者从torch.nn.functional中获取,同时为了方便
重复使用组件,可以使用 Sequential 等Containers容器将一系列组件包起来,最后在 forward()函数中将这些组件组装成需要的模型。
至此,基于PyTorch的模型搭建流程已基本完成,可根据官方开源模型进行适当修改或直接使用。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。