PyTorch模型参数不更新?检查一下你是不是没用nn.ModuleList
上周在实验室调试一个简单的图像分类模型时,遇到了一个令人抓狂的问题——训练了20个epoch,损失函数纹丝不动。作为PyTorch老手,我检查了数据加载、损失函数、优化器设置,甚至怀疑是不是GPU显存溢出导致计算中断。最后发现,问题出在一个看似微不足道的细节:用普通Python列表存储了nn.Linear层。这个教训让我意识到,PyTorch中模块容器的选择直接影响参数能否被正确注册和更新。
1. 问题重现:为什么参数会"消失"?
让我们通过一个典型错误案例来理解这个陷阱。假设我们要构建一个三层的全连接网络:
python复制import torch.nn as nn
class FaultyModel(nn.Module):
def __init__(self):
super().__init__()
# 错误示范:使用普通Python列表
self.layers = [
nn.Linear(784, 256),
nn.ReLU(),
nn.Linear(256, 10)
]
def forward(self, x):
for layer in self.layers:
x = layer(x)
return x
这个模型看起来完全合理,但在训练时会发现第二层的参数始终不更新。原因在于PyTorch的模块注册机制:
- 参数注册机制:PyTorch通过
nn.Module的__setattr__方法自动追踪子模块 - 普通列表的缺陷:Python列表不会触发PyTorch的模块注册流程
- 后果:
model.parameters()不会包含这些"隐藏"的参数
可以通过以下代码验证问题:
python复制model = FaultyModel()
params = list(model.parameters())
print(f"可训练参数数量:{len(params)}") # 输出为0
