为何不同batch size下Conv2d输出结果存在差异?
问题描述
向Conv2d输入相同数据但使用不同batch size(通过拼接构造):
a = torch.rand(1, 512, 16, 16) # (1, 512, 16, 16) b = torch.cat([a, a, a], dim=0) # (3, 512, 16, 16) a, b = a.cuda(), b.cuda() net = nn.Conv2d(512, 1024, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1)) net = net.cuda() ay = net(a) by = net(b) print('ay[0], by[0] max diff', torch.max(torch.abs(ay[0] - by[0])).item()) print('ay[0], by[0] allclose', torch.allclose(ay[0], by[0]))
输出结果存在差异:
ay[0], by[0] diff 3.5762786865234375e-06 ay[0], by[0] allclose False
该问题在Linux + V100 + torch1.9.0 + cu111环境下复现,且其他多种配置中也出现此情况。请问这是什么原因?还是我对Conv2d的工作原理存在误解?
在使用batch size为1验证训练集结果时,发现其与训练过程中记录的误差存在显著差异,排查后定位到是Conv2d层导致此问题,按常理这不应发生。
原因分析
这是CUDA卷积实现的数值精度误差导致的,并非对Conv2d原理的误解。具体细节如下:
- 不同batch size的数据送入CUDA核心计算时,PyTorch会调用不同的底层优化实现。比如batch size=1和batch size=3时,CUDA可能采用不同的张量布局、并行计算策略或浮点运算融合方式,这些差异会引入极其微小的浮点舍入误差。
- 你看到的差异量级是
1e-6,属于单精度浮点数(float32)的正常误差范围——float32本身的精度约为6-7位有效数字,这种级别的误差是浮点运算的固有特性。 torch.allclose()默认的绝对误差容差是1e-05,你的误差刚好超过该阈值,所以返回False。调整容差参数,比如torch.allclose(ay[0], by[0], atol=1e-05),就能得到True的结果。
可选解决方案
- 使用双精度浮点数(float64):将模型和数据都转为
double(),浮点误差会大幅降低,但会增加显存占用和计算耗时。 - 强制统一卷积实现路径:通过设置环境变量或PyTorch配置参数,强制不同batch size的卷积使用相同的底层算法,但可能会牺牲部分计算性能。
内容的提问来源于stack exchange,提问作者z1yloo
相关产品推荐
相关产品推荐

