Sequential --- PyTorch 2.11 documentation
1. 什么是 Sequential?
nn.Sequential 是一个顺序容器。模块将按照它们在构造函数中传递的顺序被添加到容器中。
-
核心功能 :它会自动处理数据在各层之间的传递。你不需要手动编写
forward函数里的数据流代码,Sequential会自动将第一层的输出传给第二层,第二层传给第三层,以此类推。 -
角色 :它将多个子模块打包成一个单一的模块。对
Sequential对象进行操作(如移动到 GPU、保存模型)会同时作用于它包含的所有子层。
2. 两种初始化方式
文档介绍了两种创建 Sequential 的方法:
方式 A:直接传递模块(最常用)
这种方式简单快捷,各层会自动命名为数字索引 0, 1, 2...。
python
# 就像把零件一个个扔进流水线
model = nn.Sequential(
nn.Conv2d(1, 20, 5),
nn.ReLU(),
nn.Conv2d(20, 64, 5),
nn.ReLU()
)
方式 B:使用 OrderedDict(有序字典)
如果你希望给每一层起一个有意义的名字(如 "conv1", "relu1"),可以使用这种方式。
python
from collections import OrderedDict
model = nn.Sequential(OrderedDict([
('conv1', nn.Conv2d(1, 20, 5)),
('relu1', nn.ReLU()),
('conv2', nn.Conv2d(20, 64, 5)),
('relu2', nn.ReLU())
]))
3. 文档中的关键属性与方法
在最新版本的文档中,Sequential 变得更加灵活,像 Python 的列表(List)一样支持动态操作:
-
append(module):在末尾追加一个新模块。 -
extend(modules):将另一个序列或模块集合合并进来。 -
insert(index, module):在指定位置插入模块。 -
pop(index):删除并返回指定位置的模块。 -
索引访问 :你可以像访问列表一样访问它,例如
model[0]会返回流水线的第一层。
4. 为什么使用它?(对比 nn.ModuleList)
文档通常会对比这两者:
-
nn.Sequential:内部实现了forward()。调用model(input)时,它会自动按序执行所有层。 -
nn.ModuleList:仅仅是一个存储模块的列表,没有forward()。你需要自己在forward函数里写for循环来遍历它。
5. 局限性
虽然 Sequential 很方便,但它只适用于单输入、单输出且呈线性堆叠的网络。
-
不支持跳跃连接(Skip Connections):例如 ResNet 这种需要将前几层的输出直接加到后面层的情况。
-
不支持多输入/多输出 :如果你的模型需要同时输入两个图片张量,
Sequential无法直接处理。
6. 代码应用示例
在实际开发中,它常被用来简化大型模型的定义:
python
class MyModel(nn.Module):
def __init__(self):
super().__init__()
# 使用 Sequential 定义特征提取部分,代码更整洁
self.features = nn.Sequential(
nn.Conv2d(3, 64, 3),
nn.ReLU(),
nn.MaxPool2d(2)
)
self.classifier = nn.Linear(64, 10)
def forward(self, x):
x = self.features(x) # 一行代码搞定三层计算
x = torch.flatten(x, 1)
return self.classifier(x)
7.如何使用 nn.Sequential 构建一个典型的卷积神经网络(类似 CIFAR-10 分类模型),并使用 TensorBoard 的 add_graph 功能来可视化网络结构。
python
import torch
from torch import nn
from torch.nn import Conv2d, MaxPool2d, Flatten, Linear, Sequential
from torch.utils.tensorboard import SummaryWriter
# --- 第一部分:定义神经网络结构 ---
class Tudui(nn.Module):
def __init__(self):
super(Tudui, self).__init__()
# 使用 Sequential 将多个层封装成一个名为 model1 的流水线
# 这大大简化了 forward 函数的编写
self.model1 = Sequential(
# 第一层卷积:输入通道3(RGB),输出32,卷积核5x5,填充2(为了保持尺寸不变)
# 计算:(32 + 2*2 - 5)/1 + 1 = 32,输出尺寸仍为 32x32
Conv2d(3, 32, 5, padding=2),
# 第一次池化:2x2 核,尺寸减半 -> 16x16
MaxPool2d(2),
# 第二层卷积:输入32,输出32,卷积核5x5,填充2
# 尺寸维持 16x16
Conv2d(32, 32, 5, padding=2),
# 第二次池化:尺寸减半 -> 8x8
MaxPool2d(2),
# 第三层卷积:输入32,输出64,卷积核5x5,填充2
# 尺寸维持 8x8
Conv2d(32, 64, 5, padding=2),
# 第三次池化:尺寸减半 -> 4x4
MaxPool2d(2),
# 展平层:将 (64, 4, 4) 的三维特征图拉直成一维向量
# 计算:64 * 4 * 4 = 1024
Flatten(),
# 全连接层1:将 1024 个特征映射到 64 个节点
Linear(1024, 64),
# 全连接层2:最后映射到 10 个类别(对应 CIFAR-10 的 10 类)
Linear(64, 10)
)
def forward(self, x):
# 数据直接进入定义的 Sequential 流水线
x = self.model1(x)
return x
# --- 第二部分:模型实例化与验证 ---
tudui = Tudui()
# 打印网络结构,你会看到 model1 内部按顺序排列的层
print(tudui)
# 创建一个模拟输入:batch_size=64, 通道=3, 高=32, 宽=32 (全1张量)
input = torch.ones((64, 3, 32, 32))
# 将输入喂入网络,获取输出
output = tudui(input)
# 打印输出形状:应该是 [64, 10],即 64 张图片,每张有 10 个类别的得分
print(output.shape)
# --- 第三部分:TensorBoard 可视化结构 ---
# 创建日志处理器,存放在 "../logs_seq" 目录下
writer = SummaryWriter("../logs_seq")
# 关键步骤:使用 add_graph 将模型的计算图画出来
# 这样你可以在浏览器中直观地看到各层是如何连接的,以及数据的流向
writer.add_graph(tudui, input)
# 关闭写入器
writer.close()