nn.Sequential 与nn.ModuleList 区别

nn.Sequential vs nn.ModuleList

为了帮你快速理解,我将它们的核心区别总结在下表中:

特性 nn.Sequential nn.ModuleList
核心定位 一个可执行的、有序的容器,本身是一个"模型"。 一个存储子模块的Python列表,是"模型部件的集合"。
可调用性 可直接调用,输入会按顺序通过所有子模块。 不可直接调用,只是一个列表,需要手动遍历或索引访问。
前向传播 自动定义。只需调用容器本身,内部顺序即前向逻辑。 手动定义 。你需在forward中明确写出如何使用每个模块。
主要用途 构建简单、线性的模型流水线(如 CNN 的 conv->relu->pool 堆叠)。 组织和管理一组模块 ,以实现灵活、非顺序的连接(如循环、分支、共享层)。
顺序重要性 至关重要,顺序决定了数据流向。 不重要 ,存储顺序不影响模型逻辑,取决于你在forward中如何使用它们。

错误示例

复制代码
from torch import nn
import os

class ASimpleNet(nn.Module):
    def __init__(self, layers=3):
        super(ASimpleNet, self).__init__()
        # 使用 Sequential 替代 ModuleList
        self.linears = nn.Sequential(
            *[nn.Linear(3, 3, bias=False) for _ in range(layers)]
        )
    
    def forward(self, x):
        print("forward batchsize is: {}".format(x.size()[0]))
        x = self.linears(x)  # 正确调用
        x = torch.relu(x)
        return x

[nn.Linear(3, 3, bias=False) for i in range(3)] 中,定义三个完全相同(输入输出均为3维)的线性层,通常有以下几种设计意图:

  1. 构建更深的网络(最常见意图):

    • 想法:通过增加网络深度(层数)来增强模型的表达能力,学习更复杂的特征变换。这是深度学习的基础理念。

    • 你代码中的问题 :纯线性层堆叠(Linear -> Linear -> Linear没有中间非线性激活函数 。根据线性代数,多个线性变换的复合等价于一个线性变换 (即 W3(W2(W1*x)) 等价于 (W3*W2*W1)*x),因此深度没有带来任何好处。

    • 正确做法 :应在每层线性层后加入非线性激活(如ReLU),形成 Linear -> ReLU -> Linear -> ReLU -> Linear 的结构,这样每层才能学习不同的非线性映射。

  2. 实现并行或分支结构

    • 想法:让同一输入同时被多个不同的线性层(可视为不同的"专家"或"视角")处理,然后将结果融合(相加、拼接等)。

    • 这需要 nn.ModuleList:因为你需要分别调用这三个层,然后手动组合它们的输出。

  3. 作为模块复用的示例

    • 想法 :教学演示如何用 nn.ModuleListnn.Sequential 来管理多个相同类型的层。

💡 如何正确使用它们?------ 实例对比

假设我们想构建一个网络,它先将输入投影到三个不同的3维子空间,然后将结果相加 。这必须 使用 nn.ModuleList

复制代码
class ParallelNet(nn.Module):
    def __init__(self):
        super().__init__()
        # 用 ModuleList 存储三个独立的层
        self.branches = nn.ModuleList([nn.Linear(3, 3) for _ in range(3)])
    
    def forward(self, x):
        branch_outputs = [branch(x) for branch in self.branches] # 分别计算
        x = torch.stack(branch_outputs).sum(dim=0) # 堆叠后求和
        return x
复制代码

如果只是想构建一个简单的深度网络,则使用 nn.Sequential 更清晰:

复制代码
class DeepNet(nn.Module):
    def __init__(self):
        super().__init__()
        # 用 Sequential 定义顺序执行的层
        self.net = nn.Sequential(
            nn.Linear(3, 3),
            nn.ReLU(),  # 关键!加入非线性
            nn.Linear(3, 3),
            nn.ReLU(),  # 关键!加入非线性
            nn.Linear(3, 3),
        )
    
    def forward(self, x):
        return self.net(x)  # 调用一次即可
复制代码

总结与选择建议

  1. 关于"三个层" :在层间没有非线性激活 的情况下,堆叠多个Linear层是无效的。你需要明确目标:是构建深度网络 (加非线性,用Sequential),还是并行分支 (用ModuleList手动融合)。

  2. 关于容器选择

    • 当你的模型是 层A -> 层B -> 层C 这种简单、严格的顺序 时,毫不犹豫地选择 nn.Sequential

    • 当你的模型需要循环 (如RNN)、条件判断分支处理自定义连接方式 时,选择 nn.ModuleList 来存储模块,然后在 forward 中实现你的逻辑。

简单记:Sequential 用于"自动流水线",ModuleList 用于"手动装配线"

相关推荐
大鱼>7 小时前
大语言模型+物联网:LLM理解物理世界
物联网·struts·语言模型·多模态·aiot
AndrewHZ8 小时前
【LLM技术全景】大模型能力探秘:In-Context Learning与思维链(CoT)
人工智能·语言模型·大模型·llm·cot·思维链·icl
生成论实验室9 小时前
机器人:一个自主运动的系统
人工智能·算法·语言模型·机器人·自动驾驶·agi·安全架构
Data-Miner9 小时前
大语言模型+智能体AI,122页PPT详解落地应用培训!
人工智能·microsoft·语言模型
枫叶林FYL13 小时前
BRIDGE:多模态查询的强化学习对齐与文本检索重构
人工智能·语言模型
小小工匠13 小时前
拆解大语言模型:从词向量到注意力机制的内部运行原理
人工智能·语言模型·自然语言处理
暮云星影13 小时前
瑞芯微rk3588利用Rockchip NPU运行大语言模型(LLM)
arm开发·人工智能·语言模型·自然语言处理
生成论实验室15 小时前
自动驾驶:一个自主运动的系统
人工智能·算法·机器学习·语言模型·机器人·自动驾驶·安全架构
searchforAI17 小时前
啥是LLM?大语言模型从原理到选型的完整科普
人工智能·科技·深度学习·ai·语言模型·知识图谱·agent
MartinYeung51 天前
[论文学习]重新思考大型语言模型忘却目标:梯度视角与超越
人工智能·学习·语言模型