深入浅出 PyTorch 中的 nn.Sequential —— 简洁高效地串联模型层

在 PyTorch 中,nn.Sequential 是一个非常方便的容器,它能让你像搭积木一样,把多个层(Module)按顺序拼接起来,自动管理子模块的注册和调用。本文将带你从原理到实战,全面了解并掌握 nn.Sequential 的用法与注意事项。


一、nn.Sequential 的核心作用

  1. 简化模型定义
    当网络结构仅是线性堆叠(Conv→ReLU→Pool→FC…),用 Sequential 可以少写大量 forward 里的调用语句。
  2. 自动管理子模块
    传入 Sequential 的每个 Module 都会被自动注册,你无需再手动在 __init__ 中用 self.xxx = …。
  3. 统一状态切换
    调用 model.train() 或 model.eval() 时,Sequential 会递归地切换所有子模块的训练/推理状态。

二、两种构造方式

方式一:按顺序传入模块实例

import torch.nn as nn

model = nn.Sequential(
    nn.Conv2d(3, 16, kernel_size=3, padding=1),
    nn.BatchNorm2d(16),
    nn.ReLU(inplace=True),
    nn.MaxPool2d(2),
    nn.Flatten(),
    nn.Linear(16*16*16, 10)
)

方式二:使用有序字典,为模块命名

from collections import OrderedDict
import torch.nn as nn

model = nn.Sequential(OrderedDict([
    ("conv1", nn.Conv2d(3, 16, 3, padding=1)),
    ("bn1",   nn.BatchNorm2d(16)),
    ("relu1", nn.ReLU()),
    ("pool",  nn.MaxPool2d(2)),
    ("flat",  nn.Flatten()),
    ("fc",    nn.Linear(16*16*16, 10)),
]))
  • 按索引访问:model[0], model[3]
  • 按名称访问:model.conv1, model["bn1"]

三、工作原理

调用 output = model(input) 时,Sequential 会依次执行:

x = input
for layer in model:
    x = layer(x)
return x

等价于你手动在 forward 中一层层调用,但更简洁。


四、适用场景

  1. 简单前馈网络
    只有单条数据流,没有残差或并行支路。
  2. 快速原型搭建
    调试、试验新想法时,能快速串联层并测试结果。
  3. 子模块封装
    在复杂模型中,将一段“直线”子结构封装成 Sequential,便于维护和重用。

五、常见误区与局限

  • 不支持分支/跳跃
    对于 ResNet 的 x + F(x)、Inception 模块的多路径并行,都需自定义 nn.Module 并在 forward 中写明逻辑。
  • 无法在中间“取特征”
    若想在中间层同时获取多个中间输出,需要自己在 forward 中拆分。

六、与 ModuleList、ModuleDict 区别

容器自动调用应用场景
Sequential是线性堆叠的层,前向一步到位
ModuleList否存多组子模块,在 forward 中手动迭代或条件调用
ModuleDict否存命名子模块,动态路由或条件分支

七、实战示例:小型卷积分类器

import torch
import torch.nn as nn

class SimpleCNN(nn.Module):
    def __init__(self, num_classes=10):
        super().__init__()
        # 特征提取部分
        self.features = nn.Sequential(
            nn.Conv2d(3, 32, 3, padding=1),   # [B,3,32,32] -> [B,32,32,32]
            nn.ReLU(),
            nn.MaxPool2d(2),                  # -> [B,32,16,16]
            nn.Conv2d(32, 64, 3, padding=1),  # -> [B,64,16,16]
            nn.ReLU(),
            nn.MaxPool2d(2),                  # -> [B,64,8,8]
        )
        # 分类器部分也用 Sequential
        self.classifier = nn.Sequential(
            nn.Flatten(),
            nn.Linear(64*8*8, 256),
            nn.ReLU(),
            nn.Dropout(0.5),
            nn.Linear(256, num_classes)
        )

    def forward(self, x):
        x = self.features(x)
        x = self.classifier(x)
        return x

# 测试
model = SimpleCNN(num_classes=100)
print(model)
# 输出:可直接用 model(torch.randn(4,3,32,32)) 得到 [4,100] 的 logits

八、小结

  • nn.Sequential 就是**“顺序容器”**,让你轻松串联层、自动注册子模块、统一切换状态。
  • 适合线性前馈、快速原型、子模块封装场景;对复杂分支、残差则需自定义 Module。
  • 灵活运用,能让你的 PyTorch 代码更简洁、更可读、更易维护。

更多推荐