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

相关推荐
vibag33 分钟前
Parser输出解析器
python·语言模型·langchain·大模型
laplace01231 小时前
Part 4. LangChain 1.0 Agent 开发流程(Markdown 笔记)
前端·javascript·笔记·python·语言模型·langchain
阿正的梦工坊1 小时前
VisualTrap:一种针对 GUI Agent 的隐蔽视觉后门攻击
人工智能·深度学习·机器学习·语言模型·自然语言处理
大模型任我行2 小时前
美团:统一生成理解多模态大模型
人工智能·计算机视觉·语言模型·论文笔记
SmartBrain2 小时前
AI技术进阶之路(系列之一):从函数到深度学习
人工智能·语言模型·架构·cnn
大模型任我行12 小时前
人大:熵引导的LLM有限数据训练
人工智能·语言模型·自然语言处理·论文笔记
独自破碎E13 小时前
解释一下RAG中的Rerank
gpt·语言模型
理心炼丹19 小时前
ubutnu系统关机卡 90s 的原因分析
ubuntu·语言模型·rime·ubuntu 输入法·sougou·雾凇拼音·关机卡90s
大模型任我行19 小时前
Meta:LLM无监督提升科研能力
人工智能·语言模型·自然语言处理·论文笔记
KG_LLM图谱增强大模型20 小时前
NEURO-GUARD:知识引导推理驱动的革命性可解释医学影像多模态大模型诊断框架
语言模型·大模型·知识图谱