You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PyTorch张量求和浮点精度异常问题优化咨询

浮点精度优化:PyTorch与Python列表求和的差异问题

我编写了一个Python测试,用于计算存入PyTorch Tensor的列表元素之和,测试代码如下:

lst = [0.0014, -0.0306,  0.0005,  0.0011,  0.0012,  0.0022,  0.0017,  0.0011,
          0.0017,  0.0011,  0.0012,  0.0017,  0.0014,  0.0015,  0.0010,  0.0006,
          0.0006,  0.0004,  0.0009,  0.0007,  0.0008,  0.0007,  0.0013,  0.0013,
          0.0015,  0.0023,  0.0006]

LEN=27

trch = torch.Tensor([lst])


print('--------------------------------------------------------------')

print(trch.sum(1, keepdim=True))
print(sum(lst))
print(trch @ torch.ones((LEN,1)))
print(torch.mm( trch , torch.ones((LEN,1))))


trch_sum= 0
for num in lst:
    trch_sum += num
print(trch_sum)

初始运行得到的结果较为合理:

tensor([[-0.0001]])
-9.999999999999912e-05
tensor([[-9.9999e-05]])
tensor([[-9.9999e-05]])
-9.999999999999972e-05

但将列表最后一个数值改为0.0007后,各求和方式的结果出现极大差异:

tensor([[-9.3132e-10]])
9.215718466126788e-19
tensor([[1.1642e-09]])
tensor([[1.1642e-09]])
3.2526065174565133e-19

已知这是浮点精度问题,请问有什么方法可以优化这种情况?


优化浮点求和精度的方法
  • 使用更高精度的数据类型
    默认PyTorch的torch.Tensor采用float32(32位单精度浮点数),而Python原生float是float64(64位双精度)。将Tensor转换为双精度类型能大幅减少精度损失:

    # 直接创建双精度Tensor
    trch = torch.tensor(lst, dtype=torch.float64).unsqueeze(0)
    # 或转换已有Tensor
    trch = trch.double()
    

    双精度浮点数的有效位数是单精度的两倍,能显著降低累加过程中的误差累积。

  • 实现Kahan求和算法
    这是一种专门用于减少浮点累加误差的算法,通过跟踪并补偿累加时丢失的小数部分提升精度,适合手动循环求和场景:

    # Python版本Kahan求和
    def kahan_sum(lst):
        total = 0.0
        correction = 0.0
        for num in lst:
            y = num - correction
            temp = total + y
            correction = (temp - total) - y
            total = temp
        return total
    
    # PyTorch版本Kahan求和
    def torch_kahan_sum(tensor):
        total = torch.zeros_like(tensor)
        correction = torch.zeros_like(tensor)
        for num in tensor.flatten():
            y = num - correction
            temp = total + y
            correction = (temp - total) - y
            total = temp
        return total
    

    替代普通循环求和后,误差会明显降低。

  • 调整求和顺序
    浮点求和的误差与累加顺序直接相关,将元素按大小排序或正负分开累加,能避免小数值被大数值“吞没”:

    # 正负分组后分别排序求和
    positives = sorted([x for x in lst if x >= 0])
    negatives = sorted([x for x in lst if x < 0])
    optimized_sum = sum(positives) + sum(negatives)
    
  • 结果后处理:合理截断精度
    如果业务场景不需要极高精度,可对结果进行四舍五入,掩盖无意义的微小误差:

    # 保留8位小数
    print(round(trch.sum(1, keepdim=True).item(), 8))
    print(round(sum(lst), 8))
    

内容的提问来源于stack exchange,提问作者Carmel Gafa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 09:53:21