迁移Donut模型至PyTorch Lightning遇未用参数RuntimeError求助
错误原因
DDP(分布式数据并行)模式下,PyTorch Lightning会严格检查模型的所有可训练参数是否都参与了损失计算。如果存在参数未产生梯度(即未被用于前向传播和损失计算),DDP的梯度同步机制会出现异常,因此抛出该错误。开启find_unused_parameters=True会让DDP跳过这些参数的梯度同步,从而绕过错误,但会带来一定的性能开销。
代码排查方向
从你提供的training_step来看,问题可能出在以下几点:
1. 模型参数是否被意外冻结或未加载
Donut模型包含图像编码器(如Swin Transformer)和文本解码器(如类BERT结构)两部分。检查模型初始化代码,确认所有参数的requires_grad都设置为True(除非你故意冻结部分层)。可以在训练前添加代码打印参数状态:
for name, param in self.model.named_parameters(): print(f"{name}: requires_grad={param.requires_grad}")
如果发现关键层(如编码器卷积层、解码器注意力层)的requires_grad为False,这些参数就不会参与损失计算,触发DDP错误。
2. 模型前向传播是否正确触发所有参数
你调用self.model(image_tensors, decoder_input_ids, decoder_labels),需要确认Donut模型的前向函数签名是否匹配。部分Donut实现的前向传播可能需要额外参数(如attention_mask),或者返回的loss是否确实由所有模型分支共同计算。
可以在训练几步后,检查参数的梯度,定位未被使用的参数:
for name, param in self.model.named_parameters(): if param.requires_grad and param.grad is None: print(f"参数 {name} 未产生梯度")
3. 批量数据拼接是否存在问题
你通过循环拼接batch数据,需要确认拼接后的张量形状是否符合模型要求:
image_tensors的形状应为[batch_size, channels, height, width],检查是否和模型输入要求一致;decoder_input_ids和decoder_labels的形状应为[batch_size, seq_len],确认切片操作[:, :-1]和[:, 1:]是否正确生成了符合模型要求的输入序列。
如果形状错误,可能导致模型部分层(如注意力层)未被激活,进而参数无梯度。
解决方案选择
- 如果确实需要冻结部分参数:开启
find_unused_parameters=True是合理的,虽然会损失一点性能,但能保证训练正常进行。 - 如果所有参数都应该参与计算:按照上述排查方向找到未使用参数的根源,修复模型初始化、前向传播或数据处理的问题,之后可以关闭该设置,恢复DDP的最佳性能。
建议先在单GPU模式下测试(不设置strategy参数),如果单GPU训练时没有未使用参数的警告,说明问题出在DDP的参数同步逻辑,但更可能是模型或数据处理存在隐藏问题。
内容的提问来源于stack exchange,提问作者lte__

