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 用于"手动装配线"

相关推荐
小超同学你好31 分钟前
面向 LLM 的程序设计 6:Tool Calling 的完整生命周期——从定义、决策、执行到观测回注
人工智能·语言模型
小敬爱吃饭1 小时前
Ragflow Docker部署及问题解决方案(界面为Welcome to nginx,ragflow上传文件失败,Docker中的ragflow-cpu-1一直重启)
人工智能·python·nginx·docker·语言模型·容器·数据挖掘
数据堂官方账号2 小时前
数据竞赛 | 第二届多语种对话语音语言模型(MLC-SLM)挑战赛正式开启
人工智能·语言模型·自然语言处理·语音语言模型
前进的李工3 小时前
LangChain使用AI工具赋能:解锁大语言模型无限潜力
开发语言·人工智能·语言模型·langchain·大模型
لا معنى له4 小时前
Var-JEPA:联合嵌入预测架构的变分形式 —— 连接预测式与生成式自监督学习 ----论文翻译
人工智能·笔记·学习·语言模型
Elastic 中国社区官方博客5 小时前
使用 Jina-VLM 小型多语言视觉语言模型来和图片对话
大数据·人工智能·elasticsearch·语言模型·自然语言处理·jina
陈天伟教授5 小时前
心电心音同步分析-案例:原型设计一
开发语言·人工智能·python·语言模型·架构
枫叶林FYL7 小时前
【自然语言处理 NLP】大规模语言模型评估协议:MMLU、TruthfulQA与BBQ综合技术手册
人工智能·语言模型·自然语言处理
lifallen7 小时前
Flink Agents:Memory 层级分析 (Sensory, Short-Term, Long-Term)
java·大数据·人工智能·语言模型·flink
lifallen7 小时前
Flink Agents:外部副作用一致性 (ActionStateStore) 演进分析
java·大数据·人工智能·语言模型·flink