為什麼在數據量較小的時候CPU計算會快於GPU?

在 Torch 2011年的論文《Torch7: A Matlab-like Environment for Machine Learning》4.2節在講述Torch對CUDA的支持時作者提到:

Once understood, these concepts were sufficient to allow us to write our own 2D convolutions, which are computed at about 200GFLOP/s on a GTX580, for large enough inputs. For smaller inputs, our OpenMP+SSE implementation remains more efficient.

也就是說在數據量較小的時候,在CUDA進行計算並沒有OpenMP+SSE快,為什麼在這種情況下CPU計算會快於GPU呢?

參考文獻:Torch7: A Matlab-like Environment for Machine Learning


先不說CPU &<--&> GPU傳輸問題,只說計算時間的話,CPU也是可能比GPU快的。

現在的Intel CPU是有AVX的,一條指令可以做512bit的浮點操作,換算成32位浮點的話就是16個OPs,然後CPU每個時鐘周期可以做一次浮點乘加,相當於兩個浮點運算,所以一個時期周期就是32個FLOP,然後再乘以CPU頻率,乘以核數,一個12核,3GHz的Intel CPU的峰值運算性能大概是:

12 * 32 * 3G = 1152GFLOPS

所以你看,CPU並不慢。論文里說GPU能跑到200GFLOPS,所以性能瓶頸並不在計算單元上,而在於訪存。

說到訪存,CPU的cache比GPU大多了,所以只要CPU cache能放得下的東西(大概幾十MB量級),CPU是完全可能比GPU快的。當然,再大的話,cache放不下,就要拼內存帶寬了,這點上GPU還是比CPU快不少的。所以小規模的CPU會快,大規模的GPU會快。


訪存的延遲(注意是延遲而不是帶寬)確實是這個問題的瓶頸

以下是硬體訪問的時間數量級:

來自 https://gist.github.com/understeer/4d8ea07c18752989f6989deeb769b778

L1 cache 一級緩存一般非常小,KB級別所以異常小的數據量高頻訪問的話L1是整個架構內最優秀的1納秒級別,大致相當於CPU內部單元之間數據交換速度,但是1KB只夠存幾百個數,在計算力有個雞毛用。 對於稍微大一些的,CPU的三級緩存和GPU的shared memory差不多,都是屬於中量存儲不是太高的延遲,然後是大量數據這個時候GPU訪問顯存延遲比CPU訪問內存慢。所以總的來說只看延遲,就是CPU比GPU優秀。

但是,延遲並不是全部,訪存帶寬其實更重要,尤其是在並行的情況下:

以下是cpu的主存帶寬:

以下是GPU顯存帶寬:

這裡區別就可以說非常明顯了,GPU優秀的GDDR5X以及HBM顯存性能遠遠優於CPU的DDR3,DDR4。但是這裡需要良好的並行訪存邏輯。也就是軟體可能是這裡制約

再回到原題,定睛一看原題GTX580....如此老的卡,現在已經淘寶50包郵了。

這裡部分反對 @洪春濤 答案。。。 講到【現在的intel】 CPU 而且計算FLOPS用時鐘步進算,而不是實際測量值。。。。是不準確的

可以來這裡看下實際的 CPU performance

同時代的志強cpu大致單核性能是不到3GFlops,總能力大概是18GFlops,所以計算性能差別其實是顯著存在的

我猜測實際原因是演算法上的差異以及當時GPU計算的架構比較落後導致的,回到第一張圖,cuda core 的啟動需要10000ns,所以如果數據量小,頻繁的啟動終止cuda core也有可能導致大量時間消耗。也可能是計算量小的時候GPU所啟動的線程數和CPU大致相當而CPU單線程比GPU優秀等等此類原因


一些題外話:

比較老的版本的GPU計算很依賴CPU,比較渣的CPU會是計算中的瓶頸,因為GPU的線程管理強烈依賴於CPU,CPU不行的話會嚴重拖慢GPU線程的分配和管理

而NVIDIA從cuda 8.0 開始推行一種叫做dynamic parallelism的東西,就是從從GPU線程內啟動GPU線程,也就是說線程可以派生,這樣,理論上CPU的工作只剩下最開始啟動一個GPU線程

進一步降低cpu管理gpu所消耗的資源,使得很渣的GPU可以管理很多GPU,削弱CPU在計算中的地位

大致意思是,花更多的錢買GPU吧,CPU湊合就行了

所以講到這裡,考慮大量計算,還是毫不猶豫GPU吧


1 把數據傳輸到GPU上再從GPU上把數據傳回來都要耗費時間。而且cuda在host和gpu之間傳數據可以同時進行,如果數據少只能傳完再算,而如果數據量大,那麼就可以合理安排演算法和數據傳輸,傳輸下一小批數據和計算上一小批次的數據同時進行節省時間。

2 GPU的工作主頻是低於CPU的。GPU勝在線程賊多。

3 以cuda為例,32個線程捆綁為一個WARP共享同一個program counter執行同一個指令序列,也就是這32個線程要執行一個判斷就都執行這個判斷,要進入一個循環就都進入這個循環,如果因為判斷條件要執行不同路徑代碼,兩條路徑的執行時間都要經歷,互相等。GPU演算法里怎麼寫if和循環的學問不小。

4 存取數據也是要對齊成塊成塊取,(好像是32位元組為單位),如果不夠32位元組,那也是直接讀進來32位元組,還有對齊,儘管數據不超過32位元組,但是在存儲地址上跨越了32位元組地址,那這小塊數據還要取兩次。GPU演算法優化里怎麼擺放數據的學問很大。

所以,簡單不說,在數據量很小時,做不到上面這些針對GPU的優化,那,高主頻的CPU也更有優勢。


又丟人了,LINPACK算CPU都是算雙精度性能。對於CPU來說,基本可以簡單的認為雙精度性能=1/2單精度性能。所以下面CPU的浮點性能數據,大家看的時候請雙倍計算。雙倍來源於FMADD算2個操作,但只用了一個時鐘周期。謝評論區 @高洋 指正。


打個比方說,同樣從A地到B地,假設不限速,運50個人,肯定是一輛只能跑80的56座旅遊大巴比能跑200的跑車快。但如果只要運1個人,大巴連跑車的尾燈都看不到;如果距離短一點的,這50人還沒上完車,那邊跑車已經到達目的地了。

從理論浮點性能來說,GTX580的CUDA處理器速度是1.5G,同期的i7 980X是睿頻3.6G。單個CUDA處理器性能是2FLOPS/cycle,同期的6核i7 980X,單核性能是4FLOPs/cycle。算下來,單個CPU核心的浮點性能是單個CUDA處理器的4.8倍左右。


評論區說上面的數據舊了,貼一下新的:

1080 Ti:3584 CUDA核心,頻率1582MHz,2FLOPS/cycle,浮點性能3584*1582*2=11.3 TFLOPS。

8700K沒有AVX512,只有256位的AVX2,但是有2個FMA單元,所以應該是8*2=16 FLOPS/cycle,浮點拷機沒有睿頻,按照3.7G主頻算的話,應該是6*16*3.7=355 GFLOPS左右。和實測361.3 GFLOPS基本吻合。

8700K數據來源:https://www.pugetsystems.com/labs/hpc/Skylake-X-7800X-vs-Coffee-Lake-8700K-for-compute-AVX512-vs-AVX2-Linpack-benchmark-1068/

i9-7980XE:AVX512是512位,不過7980XE的AVX512是把Sky lake的兩個FMA單元融合二來,所以還是512/32=16 FLOPS/cycle。18核滿載能跑3.35~3.4G,按照3.4算是18*16*3.4=979 GLOPS,和測試結果977 GLOPS基本吻合。

7980XE數據來源:https://www.pugetsystems.com/labs/hpc/Intel-Core-i9-7900X-and-7980XE-Skylake-X-Linux-Linpack-Performance-1059/

此外,和i9-7980XE相同架構的可擴展至強高端型號(Gold 6XXX、Platinum)和至強-W還有半個AVX512單元,之所以說半個是這個單元並不完整。性能可以算24 FLOPS/cycle。於是28核2.5G的白金8180理論計算為:28*24*2.4*2.5=1.68 TFLOPS,報道數據是兩個8180是3.0078 TFLOPS。相差11.7%,可能是因為散熱和雙路效率的原因吧。

8180報道:Intel Forges New Xeon Line Under Scalable Processor Banner

算下來,和1080Ti的CUDA處理器相比,8700K/7980XE/8180的單核浮點性能分別大概是19.7、18.1、20倍。


樓上幾位從各種角度已經回答了該問題。附加個人看法如下:由於GPU需要從Host端取數據然後運算,如果是小數據量、頻繁啟停的,CPU可能會快,因為如果算上數據準備和傳輸時間的話,GPU的加速會被抵消甚至變負。另外看線程數量,如果CPU是8核心的,cuda/opencl等也用8線程來讓GPU算,那估計CPU是要快的,因為CPU的單核心能力、緩存命中率是要高於GPU的,如果代碼中有分支,CPU也要高於GPU。所以,數據量越大,可能需要的線程數量也就越多,GPU可以開幾千線程,如果GPU可以一直不停的算(不會被頻繁啟停,比如頻繁讀寫host端小塊數據)此時CPU這根小水管就不行了,雖然它能以滿負荷出水,但是GPU是個大促水管,會像泄洪一樣秒殺CPU。


舉個比較簡易的例子:

cpu: N個人通過1條可以路;

gpu: N分成n個小組,每個小組的人通過對應 的路;

當N比較小的時候,全部走一條路速度已經很快了; 此時,如果用GPU,還需要考慮N個人分組、排列操作,速度就慢下來了。


假設卷積運算的數組分別為I(input),F(filter),O(output)。假設gpu峰值性能高於cpu。

架構因素

gpu計算的時候每次啟動kernel需要拷貝數據以及代碼到gpu的memory。然而cpu計算的時候,如果數組較小,本身可能就在cache上。因此cpu可能比gpu快。

實驗設計

如果在一個gpu kernel里啟動多次卷積,讓數組本身就在shared memory上,肯定又是不一樣的測量結果。CPU上也是一樣,假設數據和代碼原來不在cache上,就會有冷啟動的影響。現在的torch里的bench就是讓數據塞到l1 cache,測量多次。

實現影響

那個年代,應該還沒有cudnn,用的要麼是多次矩陣乘,或者是直接卷積。即使有也是爛成渣的cudnn,和現在的cudnn不能比,cpu比他快並不奇怪。


就好比有時候走路比自行車更快,自行車比開車更快


多方面原因,我自己感覺也跟CPU裡面的cache有關。尤其數據量比較小的時候,CPU裡面的Cache幫助很大,而對於GPU,本身是靠大量的並行運算來隱藏訪存的延時,當數據量小的時候,可以並行的運算量不夠,導致整體效率不高(受訪存延時制約)。


調用GPU本身比調用CPU去處理多了一些數據轉移的時間,從CPU到GPU,再從GPU回到CPU。數據量小的時候,GPU本身的優勢沒體現出來,而這些時間成本凸顯了,所以CPU更快。數據量大了之後,GPU節省的時間多了,這些時間成本自然就被抵消了。

另外,CPU處理邏輯運算比GPU有優勢,數據量沒大到一定程度,CPU有優勢也算是正常。


謝邀,最主要的原因是各種調用開銷。特別是dma。gpu是躲不開dma時間的,就是將數據從gpu內存傳遞到CPU內存或者反之。這部分開銷比較大,如果得到的加速時間還比不上dma時間,自然總時間不會減少。就算當年amd極力推薦的hsa架構,硬體上內存是一個晶元,但仍然會有相應開銷。總之,如果用古樸節省下來的時間不能對於由此引入的開銷,就無法加速。


gpu快在矩陣運算,如果一個程序中矩陣運算占的比率不大,那麼gpu就可能cpu慢。


推薦閱讀:

PyTorch 有哪些坑/bug?
PyTorch提取中間層特徵?
如何評價 2017 年 12 月 5 日發布的 PyTorch 0.3.0?
如何評價MXNet發布的1.0版本?
PyTorch到底好用在哪裡?

TAG:CUDA | OpenMP | 深度學習DeepLearning | Torch深度學習框架 |