深度學習GPU訓練代碼初學者,在寫神經網路代碼時,遇到了GPU計算結果與CPU計算結果不一致的問題?
自己寫的三層神經網路,GPU是k20,數據集是MNIST,激活函數用的是sigmoid,當隱藏層神經元數是2048,4096,8192時,CPU與GPU的計算結果都是一致(通過對比一個epoch後,各層的激活函數值來判斷兩個平台的結果是否一致)。當隱藏層神經元增加到16384時,發現CPU與GPU的結果有一定的誤差。有的誤差很小,但最終影響我在測試集上測試泛化能力。我想問:是我的代碼問題?還是GPU與CPU本身計算精度的問題?
確實有可能,建議:
0. 代碼確實沒有bug?1. 確認cpu和gpu都用的float?
2. gpu代碼編譯的時候沒有使用--use-fast-math這樣的編譯選項?如果還不能確定的話,建議直接做pair test定位出錯位置,然後具體情況具體分析。正常的。因為硬體不同。
您可以讓CUDA的計算結果盡量精確:
(1)多使用double, 少用float(如果可以接受).(2)不使用__開頭的函數(例如__sinf), 而是用它們的慢速版本(例如sinf)(3)不要使用-prec-div=false和-use_fast_math等等。以及,您可以考慮您的演算法,盡量減少運算次數,避免誤差;
以及可以考慮盡量誤差較少的演算法。這是我的建議。畢竟硬體不同,沒有一種方式可以總是100%得到一致的浮點結果。1. GPU和CPU一樣,浮點數也是講究單精度(float)和雙精度(double)的,不一致的話是否和CPU所用的數據類型是否一致?在不考慮performance的情況下,雙精度肯定會帶來更高的準確度
2.GPU是否使用了intrinsic function?? 與傳統的standard arithmetic function不同(如sqrt, exp), GPU的device code可以使用對應同樣功能,但是性能更高的intrinsic function如__dsqrt_rn,__fdividef等進行運算;
intrinsic function會產生更少的指令來完成目的,效率提升了,但是精度也下去了。一些compiler flag可以控制是否使用優化過後的指令,如--ftz --fmc --use_fast_math等等。題主注意下是否開啟了這些選項
3.如果只是精度上有誤差,感覺可以排除因為race condition帶來的內存訪問之類的問題了。建議搜索了解一下 machine precision, conditional number 以及IEEE關於浮點數的標準。
有時間,建議讀一下Prof. Walter Gander 老爺子的書 Scientific Computing - An Introduction using Maple and MATLAB 裡面的 Finite Precision Arithmetic 一章。
鏈接: Scientific Computing浮點數求和,求和次序不同結果都會不一樣。。。其誤差可能會被演算法放大。
之前遇到過一個問題,gpu的debug模式和cpu結果一致,但gpu的release模式計算結果不同,原因在於release模式使用fma技術,而一般CPU是沒有fma的。可以通過設置命令行-fmad=false來禁用fma。這個之前困擾了我好久,希望對你有幫助
看了上面回答,綜合兩點有可能存在的問題:1.CPU GPU固有的精度問題,這一點可以通過增大input在查看誤差,如果誤差增長比較恆定,或者複雜度增加低於input footprint增加,可以懷疑是CPU GPU固有精度存在的問題。但是不排除2.2. data inconsistency的問題,這個問題比較頭疼,GPU會用relax的consistency來計算,檢查方法是跑很多次,看看這個誤差是不是恆定的,因為coherence是GPU不能保證的,如果這個誤差多次出現不一致的情況,比如第一次差幾百,第二次差1000,就有可能是data inconsistency的問題。還有一個就是改一下代碼,讓GPU盡量暴露false sharing的問題,看看會不會誤差增大。
GPU和CPU的計算結果是有可能不一樣的。DL類的演算法我沒比較過結果,不過在最初學習CUDA的時候,我的一個SOR(succesive over relaxation)的練習里,的確GPU與CPU最後的結果不是完全相等的(因為很簡單所以幾乎不可能有程序上的錯誤)。大概有1/4的結果不同,幅度大概是5e-5%左右。原因不明,不知道有沒有大神能解答。
CPU是double,gpu是float?
gpu上的浮點運算和cpu的浮點運算略有不同,記得cuda 5.0的spec里有寫過,那時候用caffe曾經出過這個問題,cpu和gpu有一定差異。不知道現在的gpu架構浮點運算是否能夠和cpu保持一致。
有可能是沒有設計好block之間的內存讀寫操作。block之間的內存讀寫是不能保證一致性的,比如block1讀取數據的時候block2在向同一塊內存寫入數據 這樣block1讀取的數據可能是寫入前的 也可能是寫入後的。
推薦閱讀: