众力资讯网

AI有梯度,为何参数没动? 训练正常运行,损失也能反向传播,某一层的参数却始终不

AI有梯度,为何参数没动?
训练正常运行,损失也能反向传播,某一层的参数却始终不变。别急着怀疑学习率:在PyTorch里,一个普通Python列表,就可能让网络层漏出优化器的管理范围,。

关键在于区分两套机制。自动求导沿着实际发生的张量运算建立计算图;模型则通过登记好的子模块,查找参数、保存状态、切换模式。某个层参与了计算,并不意味着它已经被父模型登记。算出梯度和交给优化器更新,是两道关。

比如,把若干线性层放进self.layers=[...],再在forward里逐个调用。如果这些层没有通过其他路径登记,普通列表只负责保存Python对象,不会替父模型登记其中的子模块。用model.parameters()创建优化器时,就可能漏掉这些权重。

我在PyTorch 2.8.0里复现了一个网络:前后两个无偏置的单输入单输出线性层,权重都设为1,输入为1,损失是输出的平方。前层只放在普通列表里,后层直接作为模型属性登记;优化器使用SGD,学习率0.1。

反向传播后,前层的梯度确实是2。可是执行一次优化器更新,前层权重仍为1,后层则变成约0.8。检查参数名和state_dict,都只有后层。优化器拿到的参数名单不完整。

把普通列表换成nn.ModuleList,并在创建优化器之前完成模型构建,结果就不同了。两层都出现在参数名单里,一次更新后都变成约0.8。

官方文档说明,ModuleList既支持类似列表的索引,也会正确登记包含的模块。但它不会自动替你设计前向计算。循环、分支、残差连接仍要在forward中明确写出;如果需要简单地一层接一层执行,Sequential才提供这种串联方式。

排查时,别只盯着某个权重有没有grad。还应比较named_parameters中的名称、优化器参数组里的对象,以及state_dict里的键。先用一个批次检查权重更新,再启动长时间训练。

另一个边界是:登记后再新增层,不代表已有优化器会自动接收新参数。两份清单要核对。注册能让框架找到模块,更新是否发生,还取决于参数有没有真正进入当前优化器。

能前向、能求导、能更新、能保存,是不同的检查项。把这些关系查清楚,比仅凭一条下降的损失曲线判断“所有层都在学习”更可靠。

PyTorch 深度学习