pytorch:nn.ModuleList和nn.Sequential、list的用法以及区别

news2024/11/18 3:46:51

文章目录

在构建网络的时候,pytorch有一些基础概念很重要,比如nn.Module,nn.ModuleList,nn.Sequential,这些类我们称为为容器(containers),可参考containers。本文中我们主要学习nn.ModuleList和nn.Sequential,并判断在什么时候用哪一个比较合适。

1. nn.ModuleList和nn.Sequential简介

nn.ModuleList

nn.ModuleList,它是一个存储不同module,并自动将每个module的parameters添加到网络之中的容器。你可以把任意nn.Module的子类(如nn.Conv2d,nn.Linear等)加到这个list里面,方法和python自带的list一样,无非是extend,append等操作,但不同于一般的list,加入到nn.ModuleList里面的module是会自动注册到整个网络上的,同时module的parameters也会自动添加到整个网络中。若使用python的list,则会出问题。


 
 
  1. class net 1(nn.Module):
  2. def __init__( self):
  3. super(net 1, self).__init__()
  4. self.linears = nn.ModuleList([nn.Linear( 10,10) for i in range( 2)])
  5. def forward( self, x):
  6. for m in self.linears:
  7. x = m(x)
  8. return x
  9. net = net 1()
  10. print(net)
  11. # net 1(
  12. # (modules): ModuleList(
  13. # ( 0): Linear( in_features = 10, out_features = 10, bias = True)
  14. # ( 1): Linear( in_features = 10, out_features = 10, bias = True)
  15. # )
  16. # )
  17. for param in net.parameters():
  18. print( type(param. data), param. size())
  19. # < class 'torch.Tensor' > torch. Size([ 10, 10])
  20. # < class 'torch.Tensor' > torch. Size([ 10])
  21. # < class 'torch.Tensor' > torch. Size([ 10, 10])
  22. # < class 'torch.Tensor' > torch. Size([ 10])

可以看到,这个网络权重(weights)和偏置(bias)都在这个网络之内。而对于使用python自带list的例子如下:
 


 
 
  1. class net 2(nn.Module):
  2. def __init__( self):
  3. super(net 2, self).__init__()
  4. self.linears = [nn.Linear( 10,10) for i in range( 2)]
  5. def forward( self, x):
  6. for m in self.linears:
  7. x = m(x)
  8. return x
  9. net = net 2()
  10. print(net)
  11. # net 2()
  12. print(list(net.parameters()))
  13. # []

显然,使用python的list添加的卷积层和它们的parameters并没有自动注册到我们的网络中。当然,我们还是可以使用forward来计算输出结果。但是如果用其实例化的网络进行训练的时候,因为这些层的parameters不在整个网络之中,所以其网络参数也不会被更新,也就是无法训练。

 

但是,我们需要注意到,nn.ModuleList并没有定义一个网络,它只是将不同的模块储存在一起,这些模块之间并没有什么先后顺序可言,比如:


 
 
  1. class net 3(nn.Module):
  2. def __init__( self):
  3. super(net 3, self).__init__()
  4. self.linears = nn.ModuleList([nn.Linear( 10,20), nn.Linear( 20,30), nn.Linear( 5,10)])
  5. def forward( self, x):
  6. x = self.linears[ 2](x)
  7. x = self.linears[ 0](x)
  8. x = self.linears[ 1](x)
  9. return x
  10. net = net 3()
  11. print(net)
  12. # net 3(
  13. # (linears): ModuleList(
  14. # ( 0): Linear( in_features = 10, out_features = 20, bias = True)
  15. # ( 1): Linear( in_features = 20, out_features = 30, bias = True)
  16. # ( 2): Linear( in_features = 5, out_features = 10, bias = True)
  17. # )
  18. # )
  19. input = torch.randn( 32, 5)
  20. print(net( input).shape)
  21. # torch. Size([ 32, 30])

根据net3的结果,我们可以看出ModuleList里面的顺序并不能决定什么,网络的执行顺序是根据forward函数来决定的。但是一般设置ModuleList中的顺序和forward中保持一致,增强代码的可读性。

我们再来考虑另一种情况,既然ModuleList可以根据序号来调用,那么一个模型可以在forward函数中被调用多次。但需要注意的是,被调用多次的模块,是使用同一组parameters的,也就是它们是参数共享的。


 
 
  1. class net 4(nn.Module):
  2. def __init__( self):
  3. super(net 4, self).__init__()
  4. self.linears = nn.ModuleList([nn.Linear( 5, 10), nn.Linear( 10, 10)])
  5. def forward( self, x):
  6. x = self.linears[ 0](x)
  7. x = self.linears[ 1](x)
  8. x = self.linears[ 1](x)
  9. return x
  10. net = net 4()
  11. print(net)
  12. # net 4(
  13. # (linears): ModuleList(
  14. # ( 0): Linear( in_features = 5, out_features = 10, bias = True)
  15. # ( 1): Linear( in_features = 10, out_features = 10, bias = True)
  16. # )
  17. # )
  18. for name, param in net.named_parameters():
  19. print(name, param. size())
  20. # linears. 0.weight torch. Size([ 10, 5])
  21. # linears. 0.bias torch. Size([ 10])
  22. # linears. 1.weight torch. Size([ 10, 10])
  23. # linears. 1.bias torch. Size([ 10])

 

nn.Sequential

不同于nn.ModuleList,nn.Sequential已经实现了内部的forward函数,而且里面的模块必须是按照顺序进行排列的,所以我们必须确保前一个模块的输出大小和下一个模块的输入大小是一致的。


 
 
  1. class net 5(nn.Module):
  2. def __init__( self):
  3. super(net 5, self).__init__()
  4. self. block = nn. Sequential(nn.Conv 2d( 1,20,5),
  5. nn.ReLU(),
  6. nn.Conv 2d( 20,64,5),
  7. nn.ReLU())
  8. def forward( self, x):
  9. x = self. block(x)
  10. return x
  11. net = net 5()
  12. print(net)
  13. # net 5(
  14. # ( block): Sequential(
  15. # ( 0): Conv 2d( 1, 20, kernel_ size =( 5, 5), stride =( 1, 1))
  16. # ( 1): ReLU()
  17. # ( 2): Conv 2d( 20, 64, kernel_ size =( 5, 5), stride =( 1, 1))
  18. # ( 3): ReLU()
  19. # )
  20. # )

下面给出了两个nn.Sequential初始化的例子,在第二个初始化中我们用到了OrderedDict来指定每个module的名字


 
 
  1. # Example of using Sequential
  2. model 1 = nn. Sequential(
  3. nn.Conv 2d( 1,20,5),
  4. nn.ReLU(),
  5. nn.Conv 2d( 20,64,5),
  6. nn.ReLU()
  7. )
  8. print(model 1)
  9. # Sequential(
  10. # ( 0): Conv 2d( 1, 20, kernel_ size =( 5, 5), stride =( 1, 1))
  11. # ( 1): ReLU()
  12. # ( 2): Conv 2d( 20, 64, kernel_ size =( 5, 5), stride =( 1, 1))
  13. # ( 3): ReLU()
  14. # )
  15. # Example of using Sequential with OrderedDict
  16. import collections
  17. model 2 = nn. Sequential(collections.OrderedDict([
  18. ( 'conv1', nn.Conv 2d( 1,20,5)),
  19. ( 'relu1', nn.ReLU()),
  20. ( 'conv2', nn.Conv 2d( 20,64,5)),
  21. ( 'relu2', nn.ReLU())
  22. ]))
  23. print(model 2)
  24. # Sequential(
  25. # (conv 1): Conv 2d( 1, 20, kernel_ size =( 5, 5), stride =( 1, 1))
  26. # (relu 1): ReLU()
  27. # (conv 2): Conv 2d( 20, 64, kernel_ size =( 5, 5), stride =( 1, 1))
  28. # (relu 2): ReLU()
  29. # )

有同学可能发现了,诶,你这个 model1 和 从类 net5 实例化来的 net 有什么区别吗?是没有的。这两个网络是相同的,因为 nn.Sequential 就是一个 nn.Module 的子类,也就是 nn.Module 所有的方法 (method) 它都有。并且直接使用 nn.Sequential 不用写 forward 函数,因为它内部已经帮你写好了。

这时候有同学该说了,既然 nn.Sequential 这么好,我以后都直接用它了。如果你确定 nn.Sequential 里面的顺序是你想要的,而且不需要再添加一些其他处理的函数 (比如 nn.functional 里面的函数,nn 与 nn.functional 有什么区别? ),那么完全可以直接用 nn.Sequential。这么做的代价就是失去了部分灵活性,毕竟不能自己去定制 forward 函数里面的内容了。

一般情况下 nn.Sequential 的用法是来组成卷积块 (block),然后像拼积木一样把不同的 block 拼成整个网络,让代码更简洁,更加结构化。

 

2.nn.Sequential与nn.ModuleList的区别

不同点1:nn.Sequential内部实现了forward函数,因此可以不用写forward函数,而nn.ModuleList则没有实现内部forward函数。

不同点2:nn.Sequential可以使用OrderedDict对每层进行命名。

不同点3:nn.Sequential里面的模块按照顺序进行排列的,所以必须确保前一个模块的输出大小和下一个模块的输入大小是一致的。而nn.ModuleList 并没有定义一个网络,它只是将不同的模块储存在一起,这些模块之间并没有什么先后顺序可言。

不同点4:有的时候网络中有很多相似或者重复的层,我们一般会考虑用 for 循环来创建它们,而不是一行一行地写,比如:

layers = [nn.Linear(10, 10) for i in range(5)]
 
 

那么这里我们使用ModuleList:


 
 
  1. class net 4(nn.Module):
  2. def __init__( self):
  3. super(net 4, self).__init__()
  4. layers = [nn.Linear( 10, 10) for i in range( 5)]
  5. self.linears = nn.ModuleList(layers)
  6. def forward( self, x):
  7. for layer in self.linears:
  8. x = layer(x)
  9. return x
  10. net = net 4()
  11. print(net)
  12. # net 4(
  13. # (linears): ModuleList(
  14. # ( 0): Linear( in_features = 10, out_features = 10, bias = True)
  15. # ( 1): Linear( in_features = 10, out_features = 10, bias = True)
  16. # ( 2): Linear( in_features = 10, out_features = 10, bias = True)
  17. # )
  18. # )

这个是比较一般的方法,但如果不想这么麻烦,我们也可以用 Sequential 来实现,如 net7 所示!注意 * 这个操作符,它可以把一个 list 拆开成一个个独立的元素。但是,请注意这个 list 里面的模块必须是按照想要的顺序来进行排列的。在 场景一 中,我个人觉得使用 net7 这种方法比较方便和整洁。


 
 
  1. class net 7(nn.Module):
  2. def __init__( self):
  3. super(net 7, self).__init__()
  4. self.linear_list = [nn.Linear( 10, 10) for i in range( 3)]
  5. self.linears = nn. Sequential( * self.linears_list)
  6. def forward( self, x):
  7. self.x = self.linears(x)
  8. return x
  9. net = net 7()
  10. print(net)
  11. # net 7(
  12. # (linears): Sequential(
  13. # ( 0): Linear( in_features = 10, out_features = 10, bias = True)
  14. # ( 1): Linear( in_features = 10, out_features = 10, bias = True)
  15. # ( 2): Linear( in_features = 10, out_features = 10, bias = True)
  16. # )
  17. # )

下面我们考虑 场景二,当我们需要之前层的信息的时候,比如 ResNets 中的 shortcut 结构,或者是像 FCN 中用到的 skip architecture 之类的,当前层的结果需要和之前层中的结果进行融合,一般使用 ModuleList 比较方便,一个非常简单的例子如下:


 
 
  1. class net 8(nn.Module):
  2. def __init__( self):
  3. super(net 8, self).__init__()
  4. self.linears = nn.ModuleList([nn.Linear( 10, 20), nn.Linear( 20, 30), nn.Linear( 30, 50)])
  5. self.trace = []
  6. def forward( self, x):
  7. for layer in self.linears:
  8. x = layer(x)
  9. self.trace.append(x)
  10. return x
  11. net = net 8()
  12. input = torch.randn( 32, 10) # input batch size: 32
  13. output = net( input)
  14. for each in net.trace:
  15. print(each.shape)
  16. # torch. Size([ 32, 20])
  17. # torch. Size([ 32, 30])
  18. # torch. Size([ 32, 50])

我们使用了一个 trace 的列表来储存网络每层的输出结果,这样如果以后的层要用的话,就可以很方便地调用了。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/563432.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

3D模型渲染引擎6大特点解读:助力AR/VR呈现惊叹的视觉效果!

一、用于桌面、移动和 AR/VR 应用程序的2D和3D图形引擎 HOOPS Visualize是一个3D图形SDK&#xff0c;可以快速开发高性能、跨平台的工程应用程序。主要特点包括&#xff1a; HOOPS Visualize的基石是图形内核&#xff0c;这是一种功能齐全、以工程为中心的场景图形技术&#…

项目实战(cloud)--配置中心Config(码云来做一个配置中心)

服务的拆分原则&#xff1a; 单体应用向微服的一个改造&#xff1a; 搭建一个聚合项目 创建一个maven项目 父项目 pom <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"…

uCOSii信号量

uCOSii信号量 主要用来测试使用uCOSii“创建信号量,发送信号量&#xff0c;接收信号量,删除信号量”。 学习uCOSii一定要先了解os_cfg.h文件。 信号量管理函数如下&#xff1a; OSSemAccept() 无条件地等待请求一个信号量函数,中断服务子程序只能用OSSemAccept()而不能用OS…

Docker介绍、常用命令、项目部署

什么是Docker 简单说&#xff1a;Docker就是一个虚拟机&#xff0c;专业说&#xff1a;它是一个开源的容器平台。它和我们常用的VMware有很多相似的地方。 名词解释 镜像/images 由本体打包出来的文件。并不是文件本身&#xff0c;但是具有该文件的功能。举个不太贴切的例子&…

离线安装python、pip和python的第三方库

1.安装python3 1.1下载python3 安装python3的网址为点击这里 选择想要下载的对应版本进行下载&#xff0c;这里使用的是63位的Windows系统&#xff0c;因此下载的选的是&#xff1a; 下载后如图&#xff1a; python-3.7.9-amd64.exe是python3的安装程序 1.2安装python3 1…

5月第3周榜单丨飞瓜数据B站UP主排行榜单(哔哩哔哩)发布!

飞瓜轻数发布2023年5月15日-5月21日飞瓜数据UP主排行榜&#xff08;B站平台&#xff09;&#xff0c;通过充电数、涨粉数、成长指数三个维度来体现UP主账号成长的情况&#xff0c;为用户提供B站号综合价值的数据参考&#xff0c;根据UP主成长情况用户能够快速找到运营能力强的B…

BLE协议栈结构

// 开坑BLE协议栈 0 镇楼图 接下来会自下往上粗略分析各个层级&#xff0c;后续会有对各层的细致解读 1 CONTROLLER 1.1 PHY BLE使用ISM频段&#xff08;频率范围是2.400-2.4835 GHz&#xff09;。将整个频带分为40份&#xff0c;每份的带宽为2MHz&#xff0c;称作RF Chann…

CASAIM与北京体育大学达成合作,高精度三维扫描技术助力体育运动装备仿真分析

近期&#xff0c;CASAIM与北京体育大学开展合作交流&#xff0c;基于高精度三维扫描技术助力体育运动装备仿真分析&#xff0c;为体育运动装备可靠性研究提供准确的数据参考。 北京体育大学是全国重点院校、国家“211工程”重点建设大学、国家首批“双一流”建设高校&#xff0…

基于springboot+vue社区团购系统(分前后台springboot+mybatis+mysql+maven+vue+html)

基于springbootvue社区团购系统 一、项目简介二、技术实现三、开发运行环境四、系统功能五、页面展示六、数据库七、项目结构八、部分代码展示九、源码地址 一、项目简介 本项目是一套基于springboot社区团购系统&#xff0c;主要针对计算机相关专业的正在做毕设的学生与需要项…

【正点原子STM32连载】 第十六章 外部中断实验 摘自【正点原子】STM32F103 战舰开发指南V1.2

1&#xff09;实验平台&#xff1a;正点原子stm32f103战舰开发板V4 2&#xff09;平台购买地址&#xff1a;https://detail.tmall.com/item.htm?id609294757420 3&#xff09;全套实验源码手册视频下载地址&#xff1a; http://www.openedv.com/thread-340252-1-1.html 第十六…

【Sentinel】流控、熔断、热点基本介绍和使用

目录 环境介绍Sentinel的使用可以分为两个部分Sentinel管理控制台客户端接入控制台配置启动参数流控规则名词解释 熔断策略公共字段说明慢调用比例字段说明 异常比例字段说明异常数字段说明 热点规则 环境介绍 开发依赖版本Spring Boot3.0.6Spring Cloud2022.0.2Spring Cloud …

一文搞清RabbitMQ的部署运维及使用

1.通过docker-compose安装RabbitMQ 1.0 初始化yum和Docker yum update yum install epel-release -y yum clean all yum list yum install docker-io -y1.1 dockerfile FROM rabbitmq:management MAINTAINER LCJ # 添加插件到指定目录 可按照此方式自行扩展其他插件 # ADD .…

shopee虾皮跨境电商网站商品数据支持网站后缀(.com.my;.vn;.ph)

作为一名技术爱好者&#xff0c;我们总会遇到各种各样的技术问题&#xff0c;需要寻找合适的技术解决方案。而在互联网时代&#xff0c;我们可以快速通过搜索引擎获取丰富的技术资源和解决方案。然而&#xff0c;在不同的技术分享中&#xff0c;我们常常会遇到质量参差不齐的文…

【新星计划·2023】单臂路由的原理讲解

单臂路由是指在路由器的一个接口上通过配置子接口的方式&#xff0c;实现原来互相隔离的VLAN之间可以互相通信。 一、单臂路由概述 网络中通过VLAN技术来实现隔离广播、方便管理及提高安全性等功能&#xff0c;一旦划分VLAN后&#xff0c;同—VLAN之间可以相互通信&#xff0…

【统计模型】瑞典生育率现状与影响因素分析

目录 瑞典生育率现状与影响因素分析 一、研究目的 二、数据来源和相关说明 三、描述性分析 3.1 样本描述 3.2 数据可视化 四、数学建模 4.1 模型建立 4.2 模型结果 &#xff08;1&#xff09;全模型A &#xff08;2&#xff09;全模型B &#xff08;3&#xff09;全…

传奇手游三职业1.80合击服务端三端互通版搭建教程

传奇手游三职业1.80合击服务端三端互通版搭建教程 大家好&#xff0c;我是驰网艾西。随着时代的发展&#xff0c;以前我们热爱的传奇游戏也越来越没有时间玩了&#xff0c;到了一定的年纪大家都有自己的事业以及生活压力。以前我们总是玩PC端所谓的端游&#xff0c;现在大家都…

highcharts矢量图放在图表的最上方

将矢量图对应的y轴的top和height都设置为0 即可 下面红色标注全是y轴的设置 以上这中图怎么实现 其中top是指图表中每个模块的位置&#xff0c;offset表示偏移的位置&#xff0c;height表示每个模块占据整个图标的高度的百分比&#xff0c;opposite表示该y轴是否在右侧&#xf…

麒麟系统安装HDP【已解决】

麒麟系统安装HDP 麒麟系统安装HDP1、软件版本介绍2、文件替换3 报错解决3.1 解决KeyError: HDP-3.1&#xff08;所有机器&#xff09;3.2 安装smartsense-hst&#xff08;所有机器&#xff09;3.3 解决Non-ASCII character \xe5 in file&#xff08;所有机器&#xff09;3.4 解…

如何解决端口号被占用的方法

在学习JavaWeb的过程中&#xff0c;在运行代码的时候经常会提示端口号被占用的情况&#xff1b;出现这情况的主要原因就是没有正常关闭tomcat。 那么遇到这种情况应该怎么解决呢&#xff1f; 首先第一种方式就是把电脑关机重启&#xff0c;这种方法可谓是百试百灵&#xff1b;另…

分类逻辑回归实例一

一、实例背景 假设根据【推荐分值】来对推荐者类型进行分类&#xff1a;高推荐、中推荐、低推荐 二、任务目标 训练出一个模型&#xff0c;来实现根据【推荐分值】&#xff0c;来预测【推荐类型】的分类 三、机器学习实现 1. 核心步骤 实现全流程&#xff1a; 1. 1 建立…