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

如何让TensorFlow在Intel/AMD CPU上fp32计算结果一致

问题背景

我在对比AMD与Intel CPU的fp32(单精度浮点)计算表现时,运行测试脚本分别执行NumPy与TensorFlow的sqrt开方运算并将结果导出为raw文件,再通过对比脚本校验跨架构计算结果一致性。

测试代码1:开方计算脚本

import numpy as np
import tensorflow as tf

# float32 NumPy array
a = np.arange(100, dtype=np.float32)
# The same array with the same dtype in TensorFlow
a_tf = tf.constant(a, dtype=tf.float32)
# Square root with NumPy
sqrt = np.sqrt(a)
sqrt.tofile('../np_exp/sqrt.raw')
# Square root with TensorFlow
with tf.Session() as sess:
    sqrt_tf = sess.run(tf.sqrt(a_tf))
    sqrt_tf.tofile('./sqrt.raw')

测试代码2:raw文件对比脚本

import csv
import os
import argparse
import json
import numpy as np
import math
# import cv2
result_data = ''
tolrence = 0.0000001

np.set_printoptions(precision=17, suppress=True)

def csv_reader(abc1, abc2, ):
    reader1 = np.fromfile(abc1, dtype=np.float32)
    reader2 = np.fromfile(abc2, dtype=np.float32)
    #print(reader1)
    i = 0
    c = 0
    count = 0
    anti_count = 0
    isNan = 0
    try:
       for (index1, index2) in zip(np.nditer(reader1), np.nditer(reader2)):
           i = i + 1
           if math.isnan(index2):
                continue
           if abs(index1 - index2) >= tolrence:
               count = count + 1
               if count != 0:
                 print(str(index1) + " " + str(index2) + " " + str(i))
           else:
                anti_count = anti_count + 1
       if count != 0:
             print(abc1)
             print(abc2)
             print("Total Matches :  ", anti_count, "Mismatches  : ", count)

    except:
        pass
      
def list_files_from_dir(root):
    all_raw_list = list()
    for path, subdirs, files in os.walk(root):
        for name in files:
            if name not in ['model.cpp', 'model.bin', 'model_net.json']:
                 all_raw_list.append(os.path.join(path, name))

    return all_raw_list


def compare_all(dir1, dir2):
    list1 = list_files_from_dir(dir1)
    list2 = list_files_from_dir(dir2)
    list1.sort()
    list2.sort()
    for i in range(len(list1)):
        csv_reader(list1[i], list2[i])


if __name__ == "__main__":
    parser = argparse.ArgumentParser(
        description='Pushes the given JSON file onto Kibana using the Logstash path given, uses ElasticSearch')
    parser.add_argument('-i1', '--input1', help='The path to the JSON file.', required=True)
    parser.add_argument('-i2', '--input2', help='The path to the JSON file.', required=True)
    args = parser.parse_args()

    input1 = args.input1
    input2 = args.input2
    compare_all(input1, input2)

注:运行对比脚本时可通过-i1、-i2参数传入存放raw文件的文件夹路径完成批量对比。

测试结果

设置对比容差为0.0000001(即差值大于等于1e-7时判定为不匹配),对比两类CPU上生成的raw文件发现:NumPy生成的sqrt计算结果在两类CPU上完全一致,无任何差异;但TensorFlow生成的sqrt计算结果共出现46处不匹配,差异值均为fp32最低位的精度偏差,部分差异样例如下:

1.4142135 1.4142134 3
2.0 1.9999999 5
2.4494898 2.4494896 7
2.828427 2.8284268 9
3.0 2.9999998 10
3.162278 3.1622777 11
3.6055512 3.6055508 14
4.0 3.9999998 17
4.5825763 4.5825753 22
4.6904163 4.6904154 23
4.795831 4.7958307 24
4.8989797 4.898979 25
5.099019 5.0990186 27
5.1961527 5.196152 28
5.385165 5.3851647 30
5.656854 5.6568537 33
5.7445626 5.744562 34
5.830952 5.830951 35
6.0 5.9999995 37
6.0827627 6.0827622 38
6.324556 6.3245554 41
6.557439 6.557438 44
7.0000005 6.9999995 50
7.0710683 7.0710673 51
7.2111025 7.2111015 53
7.2801104 7.280109 54
7.416199 7.4161983 56
8.0 7.9999995 65
8.062258 8.062257 66
8.124039 8.124038 67
8.306624 8.306623 70
8.42615 8.426149 72
8.5440035 8.544003 74
8.6602545 8.660254 76
9.0 8.999999 82
9.055386 9.055385 83
9.110435 9.110433 84
9.165153 9.165151 85
9.273619 9.273618 87
9.380833 9.380831 89
9.486833 9.486834 91
9.539392 9.5393915 92
9.591662 9.591661 93
9.797959 9.797958 97
9.899495 9.899494 99
9.949875 9.949874 100
./AMD/sqrt.raw
./INTEL/sqrt.raw
Total Matches :   54 Mismatches  :  46

(第一列为AMD平台计算值,第二列为Intel平台计算值,第三列为对应数组元素下标)

复现配置

本次测试所用TensorFlow 1.15.5为CPU版本源码编译,编译配置如下:

  • 克隆TensorFlow仓库后切换至r1.15分支;
  • 执行./configure配置时禁用XLA、CUDA等所有可选功能支持;
  • bazel编译时设置--copt、--host_copt参数为"-march=x86-64",开启--config=v1编译选项。
咨询问题

是否存在可行的配置或编译方案,能够让TensorFlow在Intel、AMD不同x86架构CPU上的fp32计算结果完全一致,消除跨平台的微小精度差异?


回答

这种1个ulp(最低有效位)的精度差异是x86平台浮点计算的正常现象,不存在能100%保证所有算子跨AMD、Intel CPU完全位一致的通用编译方案,只能通过配置尽可能收敛差异,核心逻辑和可操作方案如下:

  1. 差异的根本原因
    你编译时指定-march=x86-64仅限制了基础指令集,但TensorFlow的CPU算子后端默认会在运行时动态检测CPU支持的扩展指令集(SSE4.2、AVX、AVX2、FMA等),自动调用对应优化实现。Intel和AMD CPU对同一向量指令的微架构实现不同,FMA等乘加指令的舍入逻辑、浮点运算中间结果的高位暂存行为存在硬件级差异,最终就会出现1个ulp的偏差。NumPy结果一致是因为它默认使用更保守的标量/基础SSE实现,没有调用高阶向量优化,自然不会触发这类硬件差异。
  2. 可落地的差异收敛方案
    • 编译时强制禁用所有高阶向量指令集优化:bazel编译时额外加编译参数--copt=-mno-avx --copt=-mno-avx2 --copt=-mno-fma --copt=-mno-sse4.2 --copt=-mno-sse4.1,强制TensorFlow只使用最基础的x86-64 SSE2指令集实现算子,能消除绝大多数因向量指令实现差异带来的精度偏差,代价是30%~70%不等的性能损失。
    • 关闭运行时指令集动态调度:编译TF时添加编译选项--define tensorflow_x86_enable_dynamic_dispatch=false,禁止运行时根据CPU型号切换优化核,强制所有算子走编译时指定指令集的通用实现,避免不同CPU命中不同优化路径。
    • 禁用快速数学优化:确认编译时没有加--copt=-ffast-math类参数,这类参数会放宽IEEE754浮点合规要求,放大跨平台精度差异。
  3. 校验规则建议
    即便做了上述配置,也无法保证所有算子完全位一致,部分算子的底层实现本身就没有做跨架构位一致设计。工业界做跨平台浮点结果校验时,从来不会用0容差或1e-7这种远小于fp32自然精度误差的阈值,fp32计算的合理校验容差应该设置在1e-5~1e-6量级,或者直接用1ulp作为允许误差范围,你现在用的1e-7阈值本身就不符合fp32浮点计算的误差特性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 15:30:05