关于加载后的PyTorch模型与原训练模型评估结果存在差异的原因问询
这是PyTorch跨设备(GPU→CPU)评估时很常见的问题,结合你的场景,我整理了几个最可能的原因:
1. 浮点数计算精度的硬件差异
GPU和CPU的浮点数运算硬件实现逻辑不同,哪怕都是32位浮点(FP32),在累积计算(比如均值、求和)环节会产生细微的精度偏差。你提到预测值差异不大,但MAE是所有样本误差的均值,这些微小偏差累加后就会体现为最终loss的差异——GPU的FP32单元是为并行计算优化的,CPU的浮点单元则更侧重串行精度,两者计算结果在小数点后若干位往往存在不同。
2. 设备不匹配导致的隐式张量转换
看你的代码,加载模型后没有显式指定运行设备,却直接把输入张量移到了GPU(x = ...cuda()),但此时模型参数大概率还在CPU上。PyTorch会自动将输入张量转移到模型参数所在的设备(也就是CPU),这个跨设备拷贝过程可能引入极细微的精度损失;反过来,如果手动把模型移到GPU,也要确保所有参数和输入在同一设备上,避免不必要的跨设备传输带来的偏差。
3. DataParallel模块移除后的细微结构差异
虽然你用model = model.module移除了DataParallel包装,但要确认训练时的模型是否是完全被DataParallel包裹的。比如如果训练时模型本身还有嵌套的并行模块,或者DataParallel的某些状态(比如设备列表)在保存时被意外存储,加载后移除module可能导致模型结构有极细微的不一致——不过你说预测值差异不大,这个可能性相对较低,但可以通过打印model.state_dict().keys()和训练时的模型状态键对比来排查。
4. 归一化层(如BatchNorm)的运行统计量精度差异
训练时用DataParallel多GPU训练,BatchNorm层的running_mean和running_var是多GPU同步更新的,这些统计量会被保存到模型文件中。加载到CPU后,虽然这些值理论上是一致的,但GPU到CPU的数据转换可能带来极小的精度偏差,而BatchNorm的推理依赖这些统计量,间接影响最终的预测结果和loss计算。
排查建议
- 同设备验证:把加载后的模型移到GPU上(
model = model.to('cuda')),用和训练时完全相同的输入测试,看loss是否和原结果一致。如果一致,就说明是跨设备的精度问题。 - 参数一致性检查:计算训练时保存的模型参数和加载后模型参数的L2范数差异,如果差异极小(比如1e-6级别),就说明是浮点数精度问题;如果差异较大,那可能是模型加载过程出了问题。
- 逐样本对比:取单个样本,分别在原训练环境和当前环境下计算预测值,对比每个元素的差异,定位是预测值本身的偏差还是loss计算的偏差。
内容的提问来源于stack exchange,提问作者Raghav Arora




