在调用tensorflow框架的某个算子接口的时候,发现接口的返回值与自己通过naive的c++或者numpy实现的结果不一样。追根溯源发现是这个算子计算过程中有一个累加的步骤,参与累加运算的数据(单精度浮点类型)如下附的代码中:
#include <iostream>
#include <eigen3/Eigen/Eigen>
int main() {
Eigen::VectorXf v(10);
v << 0.0, 2.33559305e-09, 4.00294277e-11, 1.03000897e-08, 5.31838147e-08, 1.12467995e-11, 1.0, 5.30462119e-09, 9.12710463e-11, 3.25927199e-14;
std::cout.precision(15);
std::cout << "eigen sum result:" << std::endl << v.sum() << std::endl;
float result = 0.0;
std::cout << "sum in order: " << std::endl;
for (int i = 0; i < v.size(); i++) {
result += v(i);
std::cout << "step " << i << ": " << result << std::endl;
}
return 0;
}
测试发现将这些数据逐个按顺序累加的结果与直接调用eigen中的vector中的sum方法的结果会有微小区别:前者的结果比1.0大一些,后者的结果为1.0:
eigen sum result:
1
sum in order:
step 0: 0
step 1: 2.33559305229392e-09
step 2: 2.37562258753599e-09
step 3: 1.26757120355592e-08
step 4: 6.58595240565774e-08
step 5: 6.58707719480844e-08
step 6: 1.00000011920929
step 7: 1.00000011920929
step 8: 1.00000011920929
step 9: 1.00000011920929
初步定位是累加顺序不一致导致这种现象,因为累加过程中会引入数据舍入误差,顺序不同会导致最终结果不同。故有了这个提问,后续按照 @赵智源 给出的解答的方法对这组数据进行验证,结果与eigen的结果一致。DL领域中涉及到数据累加的问题,不同的软件框架、硬件架构可能会有不同的实现,导致同一组输入的累加结果不能保持bit级一致,在合理的范围内应该都是可以接受的。但如果仅仅是从数据的来说,累加步骤中引入的微小误差会导致最终计算的结果天差地别。例如上述这组数据不同的累加结果,乍一看相差极小,但如果将这个累加结果先做
l
o
g
log
log 计算,再乘以
i
n
f
inf
inf ,根据 IEEE754的标准:
l
o
g
(
1
)
∗
i
n
f
=
n
a
n
log(1)∗inf=nan
log(1)∗inf=nan
l
o
g
(
1.00000011920929
)
∗
i
n
f
=
i
n
f
log(1.00000011920929)∗inf=inf
log(1.00000011920929)∗inf=inf
一个仍为无穷大,一个却成了非数。