nn.Sequential 是 PyTorch 中用于顺序容器的一个类,它接受一系列模块作为输入,并按照这些模块被添加的顺序来构建计算图。nn.Sequential 的主要参数是一个模块列表,这些模块可以是任何 nn.Module 的子类实例,如卷积层、线性层、激活函数等。
参数
- modules (iterable, optional): 一个包含模块的迭代对象。这些模块将按顺序被添加到
nn.Sequential中。如果没有提供此参数,则nn.Sequential将是一个空容器。
用法
1. 直接传递模块列表
你可以直接将一个模块列表传递给 nn.Sequential 的构造函数。
import torch.nn as nn
model = nn.Sequential(
nn.Conv2d(1, 20, 5),
nn.ReLU(),
nn.Conv2d(20, 50, 5),
nn.ReLU()
)
2. 使用 * 解包
如果你有一个模块的可迭代对象(比如列表或元组),你可以使用 * 操作符来解包它,并将其传递给 nn.Sequential。
layers = [
nn.Conv2d(1, 20, 5),
nn.ReLU(),
nn.Conv2d(20, 50, 5),
nn.ReLU()
]
model = nn.Sequential(*layers)
在这个例子中,*layers 会将 layers 列表中的每个模块解包出来,并作为独立的参数传递给 nn.Sequential 的构造函数。这样,model 就成为了一个包含这些模块的顺序容器,数据会按照这些模块的顺序进行前向传播。
3. 使用 OrderedDict
当 nn.Sequential 中的模块需要命名时(例如,为了调试或保存/加载模型时保持参数名称的一致性),你可以使用 collections.OrderedDict。注意,从 PyTorch 0.4.1 开始,nn.Module 本身就支持有序注册子模块,因此直接使用 nn.Module 和 add_module 方法可能更加灵活。不过,OrderedDict 仍然是一个有效的选择。
from collections import OrderedDict
model = nn.Sequential(OrderedDict([
('conv1', nn.Conv2d(1, 20, 5)),
('relu1', nn.ReLU()),
('conv2', nn.Conv2d(20, 50, 5)),
('relu2', nn.ReLU())
]))
# 现在可以通过名称访问子模块,例如:model.conv1
4. 添加自定义模块
nn.Sequential 也可以包含自定义的模块。假设我们有一个名为 MyCustomModule 的自定义模块类:
class MyCustomModule(nn.Module):
def __init__(self, ...):
super(MyCustomModule, self).__init__()
# 初始化模块内部的层和其他组件
def forward(self, x):
# 定义前向传播逻辑
return x
# 创建Sequential模型,并包含自定义模块
model = nn.Sequential(
MyCustomModule(...),
# 其他层...
)
5.拆解 self.m = nn.Sequential(*(Bottleneck(c_, c_, shortcut, g, e=1.0) for _ in range(n))) # Bottleneck模块,重复n次
当您想要将一行复杂的代码拆分成多行以提高可读性时,可以使用列表推导式(list comprehension)先生成一个模块列表,然后再将这个列表传递给 nn.Sequential。以下是将您提供的代码行拆分成多行的示例:
# 创建一个空的列表,用于存储Bottleneck模块
bottleneck_modules = []
# 使用列表推导式生成n个Bottleneck模块,并将它们添加到列表中
for _ in range(n):
module = Bottleneck(c_, c_, shortcut, g, e=1.0)
bottleneck_modules.append(module)
# 使用nn.Sequential将列表中的模块按顺序包装成一个模型
self.m = nn.Sequential(*bottleneck_modules)
注意事项
nn.Sequential中的模块会按照它们被添加的顺序进行前向传播。nn.Sequential不支持在模块之间插入额外的控制流(如条件语句或循环)。对于这样的场景,你应该使用nn.Module子类。- 当需要命名模块时,虽然可以使用
OrderedDict,但直接使用nn.Module子类并调用add_module方法通常更加灵活和强大。 nn.Sequential中的每个模块都应该接受前一个模块的输出作为输入,并返回一个新的输出。这意味着你不能直接在nn.Sequential中使用具有多个输入的模块(除非这些输入是通过某种方式在前向传播中合并的)。
2万+




被折叠的 条评论
为什么被折叠?



