同版本TensorFlow/Numpy计算结果因处理器差异不同的原因咨询
不同CPU/GPU设备上Numpy与TensorFlow计算结果差异的原因探究
我们在相同环境(Python 3.10.12、TensorFlow 2.12.0、Numpy 1.23.5)下,在不同CPU及GPU设备上运行相同计算代码,发现计算结果存在差异。
编辑(2023年7月11日)
结合反馈,我们部分理解了结果差异的原因:GPU与CPU计算结果的差异已有相关解释,但不同CPU间的差异仍无法通过现有说明解释。进一步研究发现,问题不仅来自TensorFlow,还涉及Numpy:
- 当操作数完全相同时,TensorFlow与Numpy在不同CPU上执行相同操作会给出相同结果;
- Numpy与TensorFlow的随机生成器输出值均依赖CPU。
示例代码:
np.random.seed(263) print(np.random.randn(1))
在I5-1135G7和I5-5357U上得到:
[1.5188843533672705]
在Google Colab的Xeon和I7-8700上得到:
[1.5188843533672707]
(种子0至262在两类设备上结果完全一致)
由此衍生新问题:为何Numpy与TensorFlow随机生成器的表现会因设备不同而存在差异?
编辑结束
此外,我们运行如下可复现的求和代码:
import tensorflow as tf import numpy as np np.random.seed(0) numpy_numbers = np.random.randn(100000) tensorflow_numbers = tf.convert_to_tensor(numpy_numbers) numpy_sum = np.sum(numpy_numbers) tensorflow_sum = tf.reduce_sum(tensorflow_numbers) print("hash of numpy_numbers : ",np.sum([hash(x) for x in numpy_numbers])) print("hash of tensorflow_numbers : ",np.sum([hash(x.numpy()) for x in tensorflow_numbers])) print("Numpy sum : ",tf.convert_to_tensor(numpy_sum)) print("Tensorflow sum : ",tensorflow_sum)
测试发现:同一设备上结果始终一致,不同设备上结果不同。例如在Google Colab中,CPU(Intel Xeon 2.20GHz)与GPU(Tesla T4)上的求和结果存在细微差异。
我们猜测:TensorFlow处理大求和时,会先缓存部分数据计算局部和,再合并所有局部和,因缓存大小不同导致加法结合性缺失,但这仅为猜测,现咨询该现象的根本原因是什么?
答案
一、随机生成器跨CPU差异的原因
- Numpy底层库的硬件优化:Numpy的随机数生成(如
randn)依赖BLAS/LAPACK类数学库,不同CPU会配备针对性优化版本(如Intel MKL、AMD ACML或OpenBLAS)。这些库会根据CPU架构(AVX、AVX2、AVX-512等)调整运算精度或实现细节,当计算随机数生成的底层步骤时,微小的精度偏差会累积,最终导致输出结果末位不同。 - TensorFlow的硬件适配逻辑:TensorFlow的随机生成器会利用CPU向量指令加速,不同CPU的指令集支持程度不同,TensorFlow会选择对应的优化路径,这也会引发随机数结果的细微差异。你测试中前263个种子仅第263个出现差异,说明是特定运算步骤的精度累积触发了可见差异。
二、求和运算跨设备差异的根本原因
- 浮点数的固有特性:浮点数(
float32/float64)精度有限,加法不满足严格结合律。对大量浮点数求和时,求和顺序不同会导致舍入误差的累积结果不同。 - 跨设备的并行求和策略:
- GPU是大规模并行设备,会将数据拆分成多个块并行求和后合并,拆分逻辑与CPU完全不同;
- 不同CPU的核心数、缓存大小存在差异,TensorFlow会根据硬件调整分块大小和求和顺序,最终导致舍入误差累积结果不同。
- Numpy与TensorFlow的求和实现差异:即使操作数相同,两者的求和算法也有区别。Numpy可能采用CPU缓存优化的分块求和,而TensorFlow会针对GPU SM架构、CPU向量指令等硬件特性选择最优并行路径,这也会引发结果差异。
三、验证与解决方案
- 随机生成器:差异属于浮点数精度累积的正常现象,若需严格一致的随机数,可使用纯Python实现的
random模块,但会牺牲性能; - 求和运算:差异是浮点数特性与设备并行策略共同作用的结果,若需严格一致的结果,可采用Kahan求和等高精度算法,或强制指定求和顺序(但会损失并行性能)。
内容的提问来源于stack exchange,提问作者G.C.
相关产品推荐
相关产品推荐

