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.ModuleList 或 nn.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 用于"手动装配线"。

相关推荐
Dawson Zhu4 小时前
【CUDA编程入门②】CUDA性能优化基础:内存访问、Warp Shuffle与Occupancy调优
人工智能·语言模型·架构·aigc·agi
DFT计算杂谈4 小时前
基于大语言模型的用户画像提取与修正操作
人工智能·语言模型·自然语言处理
长不大的杨瑞杰21 小时前
给 OpenCode v2 接入大模型:Provider、模型选择与 API Key 安全配置实战
人工智能·安全·ai·语言模型
m0_敲代码的彭于晏1681 天前
OpenCode 2.0 智能编程效果全景展示
人工智能·python·语言模型
江屿风1 天前
【Plain Language Large Model】【大语言模型底层原理全解析:从Token生成到智能体演进】流食般投喂
人工智能·笔记·语言模型·llm·json·token·聊天模板
硅谷秋水1 天前
VLMeg:把 VLM 从奖励回归器变成成功检测器
人工智能·机器学习·语言模型·数据挖掘·机器人
隔窗听雨眠1 天前
小模型大分工:小语言模型如何重塑RAG系统的架构逻辑
人工智能·语言模型·架构
跟我学机器学习2 天前
拥有短期记忆的RAG Agent:记忆增强检索实战
人工智能·深度学习·语言模型·数据挖掘·rag
云上工程笔记2 天前
2026年企业如何根据Token用量评估大模型服务成本?计费公式与预算模型指南
人工智能·语言模型
BD_Marathon2 天前
【RAG开发】LangChain调用大语言模型
人工智能·语言模型·langchain