1. 程式人生 > 其它 >深度學習筆記27 深度學習硬體 CPU GPU

深度學習筆記27 深度學習硬體 CPU GPU

舉個例子,為什麼不能用CPU做深度學習?

就拿Intel的i7來說,她每秒鐘的運算是0.15TFLOPS,而NVIDIA的TitanX是12TFLOPS,兩者差出80倍之多。

在實際中,你用GPU訓練一個模型需要1小時的話,用CPU就需要80小時,你還玩個屁。

CPU:

左側是集顯區域,負責渲染圖形介面,簡單遊戲等;中間是一些計算單元,Shared LLC是視訊記憶體,其他地方都是通向其他元件的介面。

CPU的理論速度可能還算比較快,但是我們實際使用CPU的時候,遠遠達不到一個CPU的理論速度,主要原因就是主記憶體訪問的延遲問題。

  一個式子的計算,需要從主記憶體,進入到CPU的視訊記憶體,再從視訊記憶體進入到核,最後進入到暫存器,完成運算。而主存訪問延時是到暫存器訪問延時的200倍。

綜上,提升CPU利用率的本質就是應該提升空間和時間的記憶體本地性,兩種方法:

  時間:重用資料使他保持在快取中(cache提升速度)

  空間:按序讀寫資料使得資料可以被預讀取。(CPU讀取的時候,可以提前讀取資料)

樣例:

  如果一個矩陣是按列儲存,訪問一行會比訪問一列要快。(這裡說的是地址本身是按行還是按列,而不是資料本身的意義是按行還是按列

    CPU是按行讀取,一次讀取64個位元組(一行,被稱為快取線),CPU會聰明地提前讀取下一個(下一行,快取線)

    故一般按行訪問會快一些。

提升CPU的利用率的另一個方式:加更多的核。上圖是一個四核CPU,現在有些CPU的核能做到32,甚至64.

Intel提出了一個超執行緒,也就是更好的並行起來利用所有的核。

  網上找到一些對於超執行緒的理解:

常規的CPU想要執行多執行緒的時候,CPU要線上程之間不斷地排程,在開啟了超執行緒之後,CPU可以更充分地利用好自身的資源(CPU某些硬體有多個備份,比如程式計數器和暫存器檔案)。例如當開啟了超執行緒之後,可以在一個執行緒執行整數指令集的時候,而恰好在這個時候,另一個執行緒執行浮點指令集,而這兩個指令集整數指令單元和浮點指令單元來執行。再比如一個執行緒必須要等到某些資料被載入到快取記憶體中,那CPU就可以繼續去執行另一個執行緒。 作者:AI草莓莓汁呀連結:https://www.zhihu.com/question/384468852/answer/1901583871

你正常情況下五秒吃一口飯,然後休息兩秒,吃下一口飯,這是單執行緒。

你有兩個嘴,一個嘴五秒吃一口飯,休息兩秒,吃下一口飯;另一個嘴兩秒喝一口湯,休息一秒,喝下一口湯,這是雙核雙執行緒。

你有一個嘴,五秒吃一口飯,隔壁的老王拿起你的湯碗往你嘴裡灌,於是在你原本用來休息吞嚥飯的兩秒你又喝下了一口湯,兩秒後你又開始下一個吃一口飯的五秒。這是超執行緒的單核雙執行緒。

作者:路並尋連結:https://www.zhihu.com/question/384468852/answer/1122097961
但是,超執行緒不一定能提升效能,比如對於計算密集型的運算,但是物理意義上的暫存器就那麼幾個,兩個超執行緒會搶奪暫存器,因為他們在共享暫存器。而搶奪計算資源甚至可能會降低效能。 GPU:

外框是一個大核,不同品質的顯示卡基本就是大核不同;

大核裡面有小核(綠點),每一個小核都是一個計算單元,每一個小核都能開一個計算單元,所以可以看到我們每次可以開上千個執行緒。

上圖的斜槓區分了兩種品質,一般和高階。

可以看到,本質區別其實就是核的數目。

除此之外,GPU的記憶體頻寬很高,這一點非常重要,因為很大的模型再加上很多的中間資料需要經常寫來寫去,這可能會引起讀取速度限制核的運算,所以GPU的頻寬做的非常大。

另外就是CPU的控制流很強,因為CPU是通用計算單元,需要處理很多if else的東西,必須預判接下來要算的是什麼,是控制流還是其他什麼東西,只留下了一小部分做計算單元;與此同時,GPU把邏輯運算刪掉了,基本整個晶片都在用於資料的計算。

提高GPU的利用率:

  1、並行,比如使用上千個執行緒(類似,1000維度的向量,就會產生1000個計算執行緒)

  2、記憶體本地性。GPU為了節省面積,會把快取做的比較小,架構更簡單,但同時做大了記憶體。

  3、tensor的運算要少用控制語句。

除此之外,就是CPU與GPU之間的頻寬也是一個很大的問題。

有一種比喻很有意思,CPU就是幾個博士生,擅長處理複雜問題;GPU就是一大堆成千上萬的小學生,只會做簡單的加減乘除。

CPU和記憶體有資料互動,同時CPU也會通過PCIE與GPU進行互動,而相對CPU與記憶體的頻寬,CPU到GPU的頻寬不是很高的,同時傳輸資料的時候GPU必須做好同步,這也是很大的一個開銷。

所以我們不要在CPU和GPU之間傳輸資料,因為有頻寬限制和同步開銷。

CPU/GPU高效能程式設計:

  CPU:用C++或者其他高效能語言,因為這種語言的編譯器很成熟。

  GPU:

    NVIDIA上用CUDA,編譯器和驅動成熟。

    其他用OpenCL,質量取決於硬體廠商。

總結:

  

Q&A

1、模型大小和計算複雜度沒有直接關係,比如AlexNet可能300MB,ResNet18可能18MB,但是ResNet執行起來要比AlexNet慢。

2、LLC,last level of cache,就是最後一層快取的意思。

3、儘量能夠用Tensor做的,不要寫for loop,不要讓GPU去算邏輯性的計算。

4、python程序有一個全域性鎖,因為這個鎖會帶來很多影響,所以python常常需要多程序。