目录

背景说明

问题分析

解决方法


背景说明

        使用同一套代码、同一个虚拟环境、同样的输入文件、同一个GPU、固定的随机种子、同一个系统环境。也就是除了pycharm和terminal,其他所有的条件都是一样的。但是发现,在Pycharm中直接点运行,和在terminal中通过python xxx运行,两者的模型的输出结果竟然有差异。虽然差异不同,但可以看出很小 (这时候直觉上就可以怀疑是精度问题了)。

【踩坑】PyCharm和Terminal中模型/卷积的输出结果不一样_ide


快餐时代,先说结论,感兴趣的可再往后看分析过程:

        在两种方式下,对输入数据和模型、权重看dtype虽然都显示float32,但是实际上并非如此。如果在推理之前强制把输入数据明确指定为float32或者float64,那pycharm和terminal的输出就都一样了。猜测可能pycharm中pytorch默认读取数据是float32,terminal中默认是float64。也可能是其他原因导致的实际读取精度不一样,比如模型训练时候保存的权重就有精度问题?欢迎评论区补充~


问题分析

1、对于模型,逐层看一下是哪个层开始出问题的。

def forward(self, x, mode='eval'):
    x = self.layer1(x)
    print(x)
    exit()

如果layer1没问题,那就换成layer2继续看。发现我的情况是在layer1就出问题了。

【踩坑】PyCharm和Terminal中模型/卷积的输出结果不一样_精度_02

2、对于目标层,再挨个看是哪个模块开始出问题的。

print(model.layer1[:1](data_a))
print(model.layer1[:2](data_a))
# ... ... 同上一层一层加

发现是在卷积层出的问题:

nn.Conv2d(3, 32, kernel_size=3, padding=1, bias=is_bias),

由于随机种子已经固定了,卷积的输出应该也不会发生变化才对。

3、检查下输入数据模型的精度

print(data_a.dtype)
print(model.layer1[2].weight.dtype)
print(model.layer1[2].bias.dtype)

显示的默认都是float32类型。看不出来什么差异。

4、尝试强制指定数据类型

# 输入数据指定为double类型(也就是float64)
model(data_a.double())
# 卷积指定为double类型(也就是float64)
nn.Conv2d(3, 32, kernel_size=3, padding=1, bias=is_bias).double(),

再次运行,发现两者的结果一致了。但是发现改为float()时,pycharm运行能变,而terminal的没变(即还是double时候的结果)。暂不清楚为何terminal的改不了float。

【踩坑】PyCharm和Terminal中模型/卷积的输出结果不一样_python_03

【踩坑】PyCharm和Terminal中模型/卷积的输出结果不一样_ide_04

解决方法

那么知道了是pytorch的精度问题,为了统一管理,只需要在代码最开始就指定精度类型。

if __name__ == '__main__':
    torch.set_default_dtype(torch.double)
    # xxxxx
    # xxxxx

或者仅在需要的时候转一下类型:

out_a = model(data_a.double())