介绍
nn.ModuleList,是 nn.Module 的一个实用工具类,专门用来管理一组神经网络模块(比如多个卷积层、全连接层)
作用
nn.ModuleList 是 PyTorch 提供的 有序列表容器,用于存储多个 nn.Module 子类实例(比如 nn.Linear、nn.Conv2d)。它的核心作用是:
- 让 PyTorch 能够识别并管理列表中的所有模块参数(这是普通 Python list 做不到的);
- 提供有序的、可索引的模块访问方式,适合需要动态创建/管理多个层的场景。
简单来说:普通 list 装的层,PyTorch 不认(参数不会被收集);nn.ModuleList 装的层,PyTorch 能完整管理(参数可训练、可迁移设备)。
例子
基础使用场景(动态创建多层)
创建一个可配置层数的全连接网络,用 nn.ModuleList 就能灵活实现:
import torch
import torch.nn as nn
class DynamicNet(nn.Module):
def __init__(self, input_size, hidden_sizes, output_size):
super(DynamicNet, self).__init__()
# 1. 初始化 nn.ModuleList(空列表)
self.layers = nn.ModuleList()
# 2. 动态添加层到 ModuleList 中
prev_size = input_size
for hidden_size in hidden_sizes:
# 添加全连接层
self.layers.append(nn.Linear(prev_size, hidden_size))
# 添加激活函数
self.layers.append(nn.ReLU())
prev_size = hidden_size
# 添加输出层
self.layers.append(nn.Linear(prev_size, output_size))
def forward(self, x):
# 3. 遍历 ModuleList 执行前向传播
for layer in self.layers:
x = layer(x)
return x
# ---------------------- 测试使用 ----------------------
# 创建模型:输入10维,隐藏层[20, 15],输出5维
model = DynamicNet(input_size=10, hidden_sizes=[20, 15], output_size=5)
print("模型结构:")
print(model)
# 查看参数(验证 ModuleList 中的层参数被正确收集)
print("\n模型所有可训练参数:")
for name, param in model.named_parameters():
print(f"参数名:{name},形状:{param.shape}")
# 前向传播测试
input_data = torch.randn(2, 10) # 2个样本,10维特征
output = model(input_data)
print("\n输入形状:", input_data.shape)
print("输出形状:", output.shape)
# 设备迁移(ModuleList 中的层会一起迁移)
model = model.to("cpu") # 也可以用 "cuda"(如果有GPU)
print("\n模型设备:", next(model.parameters()).device)
nn.ModuleList vs 普通 Python list
用代码对比,直观看到差异:
import torch
import torch.nn as nn
class TestNet(nn.Module):
def __init__(self):
super(TestNet, self).__init__()
# 用普通 list 存储层
self.normal_list = [nn.Linear(10, 5), nn.ReLU()]
# 用 ModuleList 存储层
self.module_list = nn.ModuleList([nn.Linear(5, 2)])
def forward(self, x):
for layer in self.normal_list:
x = layer(x)
for layer in self.module_list:
x = layer(x)
return x
model = TestNet()
# 查看模型参数:只有 ModuleList 中的层参数被收集
print("模型参数列表:")
for name, param in model.named_parameters():
print(name) # 只输出 "module_list.0.weight" 和 "module_list.0.bias"
# 普通 list 中的层参数未被识别,无法参与训练!
print("\n普通 list 中的层是否在模型参数中?", "normal_list.0.weight" in [n for n, _ in model.named_parameters()])
# 输出:False
常用方法
nn.ModuleList 支持和普通 list 类似的操作,核心方法如下:
| 方法 | 作用 |
|---|---|
append(module) |
向列表末尾添加一个模块(最常用) |
extend(modules) |
批量添加多个模块(如 module_list.extend([nn.ReLU(), nn.Dropout()])) |
insert(idx, module) |
在指定索引位置插入模块 |
__getitem__(idx) |
通过索引访问模块(如 self.layers[0]) |
__len__() |
获取列表长度(如 len(self.layers)) |
使用场景
适合场景
- 动态创建多层(比如根据配置文件的参数决定层数/层维度);
- 需要按索引访问特定层(比如
self.layers[2]取出第3层); - 层的数量不固定,需要灵活增删。
不适合场景
- 只需按固定顺序执行层:优先用
nn.Sequential(更简洁,如nn.Sequential(nn.Linear(10,5), nn.ReLU())); - 层之间有复杂的分支/跳转逻辑:直接在
forward中手动调用层更清晰。
注意事项
nn.ModuleList只是容器,不会自动执行前向传播:必须在forward中手动遍历执行;- 必须在
__init__中初始化nn.ModuleList并添加模块:如果在forward中添加,参数不会被收集; nn.ModuleList中的模块会被model.parameters()收集,参与梯度更新,这是和普通 list 最核心的区别。
总结
nn.ModuleList是管理多个nn.Module的有序容器,核心作用是让 PyTorch 识别并管理列表内模块的参数;- 它和普通 Python list 的关键区别:
ModuleList中的层参数会被收集、可训练,普通 list 不会; - 适用场景:动态创建/管理多层、需要按索引访问层;不适用场景:固定顺序执行层(优先用
nn.Sequential)。