nn.moduleList 和Sequential的理解
目录
1.nn.ModuleList
1.1 when
1.2 what
1.3与list的区别
1.4 extend和append方法
2.nn.Sequential
2.1 模型建立方式
2.2 查看模型
2.3调用模型
3.nn.Sequential与nn.ModuleList的区别
不同点1:
不同点2:
不同点3:
4.使用场景
5.总结
1.nn.ModuleList
1.1 when
如果在构造函数__init__
中用到list、tuple、dict等对象时,一定要思考是否应该用ModuleList或ParameterList代替。
如果你想设计一个神经网络的层数作为输入传递。
1.2 what
nn.ModuleList,它是一个储存不同 module,并自动将每个 module 的 parameters 添加到网络之中的容器。所有 nn.ModuleList 内部的 nn.Module 的 parameter 也被添加作为 我们的网络的 parameter。
1.3与list的区别
你可以把任意 nn.Module 的子类 (比如 nn.Conv2d, nn.Linear 之类的) 加到这个 list 里面,方法和 Python 自带的 list 一样,无非是 extend,append 等操作。但不同于一般的 list,加入到 nn.ModuleList 里面的 module 是会自动注册到整个网络上的,同时 module 的 parameters 也会自动添加到整个网络中。若使用python的list,则会出问题。下面看一个例子:
class net_modlist(nn.Module):def __init__(self):super(net_modlist, self).__init__()self.modlist = nn.ModuleList([nn.Conv2d(1, 20, 5),nn.ReLU(),nn.Conv2d(20, 64, 5),nn.ReLU()])def forward(self, x):for m in self.modlist:x = m(x)return xnet_modlist = net_modlist()
print(net_modlist)
#net_modlist(
# (modlist): ModuleList(
# (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()
# )
#)for param in net_modlist.parameters():print(type(param.data), param.size())
#<class 'torch.Tensor'> torch.Size([20, 1, 5, 5])
#<class 'torch.Tensor'> torch.Size([20])
#<class 'torch.Tensor'> torch.Size([64, 20, 5, 5])
#<class 'torch.Tensor'> torch.Size([64])
可以看到,这个网络权重 (weithgs) 和偏置 (bias) 都在这个网络之内。接下来看看另一个作为对比的网络,它使用 Python 自带的 list:
class net_modlist(nn.Module):def __init__(self):super(net_modlist, self).__init__()self.modlist = [nn.Conv2d(1, 20, 5),nn.ReLU(),nn.Conv2d(20, 64, 5),nn.ReLU()]def forward(self, x):for m in self.modlist:x = m(x)return xnet_modlist = net_modlist()
print(net_modlist)
#net_modlist()
for param in net_modlist.parameters():print(type(param.data), param.size())
#None
显然,使用 Python 的 list 添加的卷积层和它们的 parameters 并没有自动注册到我们的网络中。当然,我们还是可以使用 forward 来计算输出结果。但是如果用其实例化的网络进行训练的时候,因为这些层的parameters不在整个网络之中,所以其网络参数也不会被更新,也就是无法训练。普通list中的子module并不能被主module所识别,而ModuleList中的子module能够被主module所识别。这意味着如果用list保存子module,将无法调整其参数,因其未加入到主module的参数中。
1.4 extend和append方法
nn.moduleList定义对象后,有extend和append方法,用法和python中一样,extend是添加另一个modulelist append是添加另一个module
class LinearNet(nn.Module):def __init__(self, input_size, num_layers, layers_size, output_size):super(LinearNet, self).__init__()self.linears = nn.ModuleList([nn.Linear(input_size, layers_size)])self.linears.extend([nn.Linear(layers_size, layers_size) for i in range(1, self.num_layers-1)])self.linears.append(nn.Linear(layers_size, output_size)
除ModuleList之外还有ParameterList,其是一个可以包含多个parameter的类list对象。在实际应用中,使用方式与ModuleList类似。
2.nn.Sequential
2.1 模型建立方式
第一种:nn.Sequential()对象.add_module(层名,层class的实例)
net1 = nn.Sequential()net1.add_module('conv', nn.Conv2d(3, 3, 3))net1.add_module('batchnorm', nn.BatchNorm2d(3))net1.add_module('activation_layer', nn.ReLU())
第二种:nn.Sequential(*多个层class的实例)
net2 = nn.Sequential(nn.Conv2d(3, 3, 3),nn.BatchNorm2d(3),nn.ReLU())
第三种:nn.Sequential(OrderedDict([*多个(层名,层class的实例)]))
from collections import OrderedDictnet3= nn.Sequential(OrderedDict([('conv', nn.Conv2d(3, 3, 3)),('batchnorm', nn.BatchNorm2d(3)),('activation_layer', nn.ReLU())]))
2.2 查看模型
print对象即可
print('net1:', net1)print('net2:', net2)print('net3:', net3)net1: Sequential((conv): Conv2d (3, 3, kernel_size=(3, 3), stride=(1, 1))(batchnorm): BatchNorm2d(3, eps=1e-05, momentum=0.1, affine=True)(activation_layer): ReLU()
)
net2: Sequential((0): Conv2d (3, 3, kernel_size=(3, 3), stride=(1, 1))(1): BatchNorm2d(3, eps=1e-05, momentum=0.1, affine=True)(2): ReLU()
)
net3: Sequential((conv): Conv2d (3, 3, kernel_size=(3, 3), stride=(1, 1))(batchnorm): BatchNorm2d(3, eps=1e-05, momentum=0.1, affine=True)(activation_layer): ReLU()
)
2.3调用模型
可以直接网络对象(输入数据),也可以使用上面的Module子对象分别传入(input)。
input = V(t.rand(1, 3, 4, 4))output = net1(input)output = net2(input)output = net3(input)output = net3.activation_layer(net1.batchnorm(net1.conv(input)))
nn.Sequential里面的模块按照顺序进行排列的,所以必须确保前一个模块的输出大小和下一个模块的输入大小是一致的。如下面的例子所示:
#首先导入torch相关包
import torch
import torch.nn as nn
import torch.nn.functional as F
class net_seq(nn.Module):def __init__(self):super(net2, 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...)。例子如下:
from collections import OrderedDictclass 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()
# )
#)
3.nn.Sequential与nn.ModuleList的区别
不同点1:
nn.Sequential内部实现了forward函数,因此可以不用写forward函数。而nn.ModuleList则没有实现内部forward函数。对于nn.Sequential:
#例1:这是来自官方文档的例子
seq = nn.Sequential(nn.Conv2d(1,20,5),nn.ReLU(),nn.Conv2d(20,64,5),nn.ReLU())
print(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()
# )#对上述seq进行输入
input = torch.randn(16, 1, 20, 20)
print(seq(input))
#torch.Size([16, 64, 12, 12])#例2:或者继承nn.Module类的话,就要写出forward函数
class net1(nn.Module):def __init__(self):super(net1, 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)#注意:按照下面这种利用for循环的方式也是可以得到同样结果的#def forward(self, x):# for s in self.seq:# x = s(x)# return x#对net1进行输入
input = torch.randn(16, 1, 20, 20)
net1 = net1()
print(net1(input).shape)
#torch.Size([16, 64, 12, 12])
#例1:若按照下面这么写,则会产生错误
modlist = nn.ModuleList([nn.Conv2d(1, 20, 5),nn.ReLU(),nn.Conv2d(20, 64, 5),nn.ReLU()])
print(modlist)
#ModuleList(
# (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()
#)input = torch.randn(16, 1, 20, 20)
print(modlist(input))
#产生NotImplementedError#例2:写出forward函数
class net2(nn.Module):def __init__(self):super(net2, self).__init__()self.modlist = nn.ModuleList([nn.Conv2d(1, 20, 5),nn.ReLU(),nn.Conv2d(20, 64, 5),nn.ReLU()])#这里若按照这种写法则会报NotImplementedError错#def forward(self, x):# return self.modlist(x)#注意:只能按照下面利用for循环的方式def forward(self, x):for m in self.modlist:x = m(x)return xinput = torch.randn(16, 1, 20, 20)
net2 = net2()
print(net2(input).shape)
#torch.Size([16, 64, 12, 12])
如果完全直接用 nn.Sequential,确实是可以的,但这么做的代价就是失去了部分灵活性,不能自己去定制 forward 函数里面的内容了。一般情况下 nn.Sequential 的用法是来组成卷积块 (block),然后像拼积木一样把不同的 block 拼成整个网络,让代码更简洁,更加结构化。
不同点2:
nn.Sequential可以使用OrderedDict对每层进行命名,上面已经阐述过了;
不同点3:
nn.Sequential里面的模块按照顺序进行排列的,所以必须确保前一个模块的输出大小和下一个模块的输入大小是一致的。而nn.ModuleList 并没有定义一个网络,它只是将不同的模块储存在一起,这些模块之间并没有什么先后顺序可言。见下面代码:
class net3(nn.Module):def __init__(self):super(net3, self).__init__()self.linears = nn.ModuleList([nn.Linear(10,20), nn.Linear(20,30), nn.Linear(5,10)])def forward(self, x):x = self.linears[2](x)x = self.linears[0](x)x = self.linears[1](x)return xnet3 = net3()
print(net3)
#net3(
# (linears): ModuleList(
# (0): Linear(in_features=10, out_features=20, bias=True)
# (1): Linear(in_features=20, out_features=30, bias=True)
# (2): Linear(in_features=5, out_features=10, bias=True)
# )
#)input = torch.randn(32, 5)
print(net3(input).shape)
#torch.Size([32, 30])
根据 net5 的结果,可以看出来这个 ModuleList 里面的顺序不能决定什么,网络的执行顺序是根据 forward 函数来决定的。若将forward函数中几行代码互换,使输入输出之间的大小不一致,则程序会报错。此外,为了使代码具有更高的可读性,最好把ModuleList和forward中的顺序保持一致。
4.使用场景
有的时候网络中有很多相似或者重复的层,我们一般会考虑用 for 循环来创建它们,而不是一行一行地写,比如:
layers = [nn.Linear(10, 10) for i in range(5)]
那么这里我们使用ModuleList:
class net4(nn.Module):def __init__(self):super(net4, self).__init__()layers = [nn.Linear(10, 10) for i in range(5)]self.linears = nn.ModuleList(layers)def forward(self, x):for layer in self.linears:x = layer(x)return xnet = net4()
print(net)
# net4(
# (linears): ModuleList(
# (0): Linear(in_features=10, out_features=10, bias=True)
# (1): Linear(in_features=10, out_features=10, bias=True)
# (2): Linear(in_features=10, out_features=10, bias=True)
# )
当我们需要之前层的信息的时候,比如 ResNets 中的 shortcut 结构,或者是像 FCN 中用到的 skip architecture 之类的,当前层的结果需要和之前层中的结果进行融合,一般使用 ModuleList 比较方便,一个非常简单的例子如下:
class net8(nn.Module):def __init__(self):super(net8, self).__init__()self.linears = nn.ModuleList([nn.Linear(10, 20), nn.Linear(20, 30), nn.Linear(30, 50)])self.trace = []def forward(self, x):for layer in self.linears:x = layer(x)self.trace.append(x)return xnet = net8()
input = torch.randn(32, 10) # input batch size: 32
output = net(input)
for each in net.trace:print(each.shape)
# torch.Size([32, 20])
# torch.Size([32, 30])
# torch.Size([32, 50])
我们使用了一个 trace 的列表来储存网络每层的输出结果,这样如果以后的层要用的话,就可以很方便地调用了。
5.总结
ModuleList 和 Sequential 这两种 nn containers,ModuleList 就是一个储存各种模块的 list,这些模块之间没有联系,没有实现 forward 功能,但相比于普通的 Python list,ModuleList 可以把添加到其中的模块和参数自动注册到网络上。而Sequential 内的模块需要按照顺序排列,要保证相邻层的输入输出大小相匹配,内部 forward 功能已经实现,可以使代码更加整洁。
nn.moduleList 和Sequential的理解相关推荐
- nn.moduleList 和Sequential由来、用法和实例 —— 写网络模型
对于cnn前馈神经网络如果前馈一次写一个forward函数会有些麻烦,在此就有两种简化方式,ModuleList和Sequential.其中Sequential是一个特殊的module,它包含几个子M ...
- PyTorch之深入理解list、ModuleList和Sequential。
文章目录 list Sequential ModuleList 总结 import torch import torch.nn as nn list class a(nn.Module):def __ ...
- nn.Sequential与nn.ModuleList
1.nn.Sequential 模块按照顺序进行排列的,确保输入与输出模块的通道数相同(实际上是feature map数量). nn.Sequential写法有3种: 第一种写法: 创建nn.Sequ ...
- pytorch模型容器Containers nn.ModuleDict、nn.moduleList、nn.Sequential
模型容器Containers之nn.ModuleDict.nn.moduleList.nn.Sequential nn.Sequential()对象 建立nn.Sequential()对象,必须小心确 ...
- nn.Sequential nn.ModuleList
在介绍nn.Sequential和nn.ModuleDict之前,我们需要知道在pytorch构建的model核心是nn.Module模块,下面举个例子 class model(nn.Module): ...
- 详解PyTorch中的ModuleList和Sequential
点击上方"视学算法",选择加"星标"或"置顶" 重磅干货,第一时间送达 作者丨小占同学@知乎(已授权) 来源丨https://zhuanla ...
- 收藏 | 详解PyTorch中的ModuleList和Sequential
点上方计算机视觉联盟获取更多干货 仅作学术分享,不代表本公众号立场,侵权联系删除 转载于:作者丨小占同学@知乎(已授权) 来源丨https://zhuanlan.zhihu.com/p/7520666 ...
- ModuleList和Sequential
一.官方文档 首先看官方文档的解释,仅列出了容器(Containers)中几个比较常用的CLASS. CLASS torch.nn.Module Base class for all neural n ...
- Did you forget add @script or @script_method annotation? If this is a nn.ModuleList, add it to __con
参考:https://github.com/pytorch/pytorch/issues/16123 Did you forget add @script or @script_method anno ...
最新文章
- 知识图谱、深度学习、AutoML,推荐系统与新技术结合将碰撞出怎样的火花?
- 不能查看隐藏文件夹的对策
- python实习做什么工作-面试python实习工作需要注意哪些事项???
- 第7章:MapReduce编程
- 《HTTP权威指南》学习笔记——HTTP报文
- 从M2M迁移到IIoT工业物联网
- android 桌面视频播放器,ZY-Player ,一款跨平台桌面端视频资源播放器
- linux运算_linux中的计算【转】
- eclipse中导入maven项目:org.apache.maven.archiver.MavenArchiver.getManifest(org.apache.maven.proje...
- lintcode 627 最长回文串Python版本
- 计算机信息技术会考操作题,信息技术会考操作题整理.doc
- 「镁客·请讲」Site24×7李飞:云服务是大势所趋,云监控生意又要怎么做?...
- 文件上传下载——sz和rz
- 2021-06-10 JUC01DAY
- python中chardet库的安装和导入
- 宝峰BF-888S对讲机写频!Android下的对讲机写频工具!
- 在vscode中配置和使用sass
- dubbo分布式服务框架(高级特性篇)
- 江苏援沪“大白”们,用手绘漫画为上海加油
- Qt可拖拽排序表格(类似QQ好友分组排序)
热门文章
- Linux下通过bonding技术实现网络负载均衡及冗余
- Linux -- 如何下载可用的 deb 包
- 计算机毕业设计基于asp.net在线音乐网站
- 【十二】【vlc-anroid】视频图像display展示层模块源码分析-OpenGL ES2交互渲染
- Linux命令进阶-cpu监控内存监控文件IO网络IO性能分析
- CS61A 20fall hw01
- 多卡聚合设备 疫情检查站视频传输应用解决方案
- Behavior Designer插件解析
- 使用hiredis报错LNK2005
- [进阶] list 过滤 stream 的lambda进阶操作, 这一篇就够了