Pytorch中多GPU訓練指北

https://www.jianshu.com/p/bb28669018b3

前言

在數據越來越多的時代,隨着模型規模參數的增多,以及數據量的不斷提升,使用多GPU去訓練是不可避免的事情。Pytorch在0.4.0及以後的版本中已經提供了多GPU訓練的方式,本文簡單講解下使用Pytorch多GPU訓練的方式以及一些注意的地方。

這裏我們談論的是單主機多GPUs訓練,與分佈式訓練不同,我們採用的主要Pytorch功能函數爲DataParallel而不是DistributedParallel,後者爲多主機多GPUs的訓練方式,但是在實際任務中,兩種使用方式也存在一部分交集。

使用方式

使用多卡訓練的方式有很多,當然前提是我們的設備中存在兩個及以上的GPU:使用命令nvidia-smi查看當前Ubuntu平臺的GPU數量(Windows平臺類似),其中每個GPU被編上了序號:[0,1]:

在我們設備中確實存在多卡的條件下,最簡單的方法是直接使用torch.nn.DataParallel將你的模型wrap一下即可:

net=torch.nn.DataParallel(model)

這時,默認所有存在的顯卡都會被使用。

如果我們機子中有很多顯卡(例如我們有八張顯卡),但我們只想使用0、1、2號顯卡,那麼我們可以:

net=torch.nn.DataParallel(model,device_ids=[0,1,2])

或者這樣:

 

很簡單的操作,這樣我們就可以比較方便地使用多卡進行訓練了。

另一種方法

在前言中提到過,另一種方法DistributedParallel,雖然主要的目標爲分佈式訓練,但也是可以實現單主機多GPU方式訓練的,只不過比上一種方法稍微麻煩一點,但是訓練速度和效果比上一種更好。

爲什麼呢?

請看官方相關介紹:

nccl backend is currently the fastest and highly recommended backend to be used with Multi-Process Single-GPU distributed training and this applies to both single-node and multi-node distributed training

好了,來說說具體的使用方法(下面展示一個node也就是一個主機的情況)爲:

 

上述的命令和我們平常的命令稍有區別,這裏我們用到了torch.distributed.launch這個module,我們選擇運行的方式變換爲python -m,上面相當於使用torch.distributed.launch.py去運行我們的YOUR_TRAINING_SCRIPT.py,其中torch.distributed.launch會向我們的運行程序傳遞一些變量。

爲此,我們的YOUR_TRAINING_SCRIPT.py也就是我們的訓練代碼中這樣寫(省略多餘代碼,只保留核心代碼):

 

我們要注意,上述代碼在運行的過程中產生了很多個,具體多少個取決你GPU的數量,這也是爲什麼上面需要torch.cuda.set_device(args.local_rank)設定默認的GPU,因爲torch.distributed.launch爲我們觸發了n個YOUR_TRAINING_SCRIPT.py進程,n就是我們將要使用的GPU數量。

有一點想問的,我們每次必須要使用命令行的方式去運行嗎?當然也可以一鍵解決,如果我們使用Pycharm,只需要配置成下面這樣就可以了:

 


單顯卡與DataParallel多顯卡訓練對比

最近兩天訓練一個魔改的mobilenetv2+yolov3,同樣的優化方法同樣的學習率衰減率,所有的參數都相同的情況下,發現單顯卡訓練的方式竟然比多顯卡訓練的方式收斂更快。

配置爲兩張1080Ti,使用Pytorch的版本爲1.0.0。下圖紅線爲使用一張1080Ti訓練的情況,藍線爲使用兩張1080Ti訓練的情況,batchsize每張顯卡設置爲10,也就是說,使用兩張顯卡訓練時的batchsize爲單張顯卡的兩倍,同一個step時,雙卡走的步數爲單卡步數的兩倍。這裏使用的多卡訓練方式爲DataParallel。

但是下圖可以看到,在雙卡相同step的情況下,雖然紅色曲線的損失相較藍色下降的稍微慢一些,但是到了一定時候,兩者的損失值會相交(此時未達到最低損失點),也就是說使用雙卡和單卡訓練時候loss損失收斂的速度是一樣的。

更奇怪的是,下圖中,在驗證集中,單顯卡雖然沒有雙顯卡的準確度曲線增長迅速,但是到了某一點,單顯卡的曲線會超過雙顯卡訓練的精度,也就是說,單卡訓練在前期沒有雙卡訓練效果顯著,但是到了訓練中期效果就會優於雙卡。

(上述兩個圖爲訓練早期和中期的展示,並沒有完全訓練完畢)關於爲什麼會這樣的情況,有可能是因爲訓練中期所有的激活值更新幅度不是很明顯(一般來說,權重值和激活值更新幅度在訓練前期比較大),在不同GPU轉化之間會損失一部分精度?。當然這僅僅是猜測,博主還沒有仔細研究這個問題,待有結論時會在這裏進行更新。

注意點

多GPU固然可以提升我們訓練的速度,但弊端還有有一些的,有幾個我們需要注意的點:

多個GPU的數量儘量爲偶數,奇數的GPU有可能會出現中斷的情況

選取與GPU數量相適配的數據集,多顯卡對於比較小的數據集來說反而不如單個顯卡訓練的效果好

多GPU訓練的時候注意機器的內存是否足夠(一般爲使用顯卡顯存x2),如果不夠,建議關閉pin_memory(鎖頁內存)選項。

採用DistributedDataParallel多GPUs訓練的方式比DataParallel更快一些,如果你的Pytorch編譯時有nccl的支持,那麼最好使用DistributedDataParallel方式。

關於什麼是鎖頁內存:

pin_memory就是鎖頁內存,創建DataLoader時,設置pin_memory=True,則意味着生成的Tensor數據最開始是屬於內存中的鎖頁內存,這樣將內存的Tensor轉義到GPU的顯存就會更快一些。

主機中的內存,有兩種存在方式,一是鎖頁,二是不鎖頁,鎖頁內存存放的內容在任何情況下都不會與主機的虛擬內存進行交換(注:虛擬內存就是硬盤),而不鎖頁內存在主機內存不足時,數據會存放在虛擬內存中。顯卡中的顯存全部是鎖頁內存,當計算機的內存充足的時候,可以設置pin_memory=True。當系統卡住,或者交換內存使用過多的時候,設置pin_memory=False。因爲pin_memory與電腦硬件性能有關,pytorch開發者不能確保每一個煉丹玩家都有高端設備,因此pin_memory默認爲False。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章