最近写了一个CG解大规模矩阵的程序,没用cublas库,因为矩阵的特殊性有快速算法能大幅度加快矩阵向量积。虽然最后能得到正确的解,但发现CG迭代过程中的中间向量以及2范数之类的值和CPU版本算的只有开始3,4步是一样的,以后的迭代都会有一定误差,感觉是两条收敛路径。想问一下为什么会这样?我的矩阵向量积和范数都是确保正确的
这个问题我无法回答。请ICE上阵吧。
因为ICE今晚被妞狂泡中。可能暂时上不来。
等他醒酒的。
此条信息请ICE阅读后删除。
LZ您好,大家好,我回来了。
浮点计算在不同的硬件设备上,因为一些原因,本身就不能保证结果完全一致的。
1:本身的计算精度,在CPU上如果使用X87指令计算,中间过程是80bit精度的;如果使用SIMD指令,则是单精度或者双精度。GPU上也有单精度和双精度的模式,但无像X87那样的80bit精度计算。
2:每一步对结果的圆整方式。
3:是否使用了低精度的快速计算函数。在CUDA上是fastmath,在CPU上,一些编译器提供了编译选项可以使用精度略差但速度更快的函数。
4:中间计算的精度保留,在支持FMA的硬件上(GPU和最近的X86 CPU),如果使用了FMA,那么乘法结果将被保留更多的有效位数以便之后的加法更准确,加法计算完以后才截断。而一般CPU计算应该没有FMA支持。
5:即便上述几点都可以保证一致,浮点结果也未必一致的,因为浮点数运算并不像实数运算那样满足结合律,例如N个数顺序相加,倒序相加和规约相加,结果一般是不同的,和计算顺序有关。而GPU上并行计算的时候,有时并不能保证和CPU一致的计算顺序,因此,结果依然是不同的。
值得指出的是,两者计算结果不同,并不代表GPU精度不够好,因为CPU的结果也只是一种条件下的浮点运算结果而已,并不是精确结果。
考虑到您的CG算法,最终依然得到了合适的结果,这说明算法还是稳健的,个人觉得请勿纠结CPU和GPU在浮点运算过程中的少量差异,只要保证最终结果的有效性即可。
大致如上,供您参考一二。
祝您编码愉快~
了解~~低精度的函数不太敢用的,因为对精度和速度都有要求,那有可能就是第5条,算范数不停地规约吧~
谢ice版主
不客气的,如果所有的数据都相对比较接近的话,规约相加的精度可能要比从头加到尾精度好一些。因为此时每一步的相加的元素大小是差不多的;而从前往后加,积累的前面若干数的和越来越大,后面加小一些的数可能会损失精度。不过这个影响大小要根据具体情况来看的。
祝您好运~