按需分配、任務隔離、靈活控制,飛槳顯存分配策略重磅升級

雖然GPU對深度學習計算有廣泛明顯的加速做用,但其顯存也是有限的(如V100的最大顯存值也僅有32G),而深度學習模型的訓練和推理每每須要大量的顯存,用來支持更大的模型和更大的batch size。如何更高效地利用GPU顯存,在一張卡或一臺機器上同時承載更多的訓練和預測任務,讓有限的顯存支持多個開發者同時進行實驗,執行各自的任務呢?python

 

 

飛槳v1.7在GPU顯存使用策略方面作了以下3點升級:git

 

  1. 默認使用顯存自增加AutoGrowth策略,根據模型實際佔用的顯存大小,按需自動分配顯存,而且不影響訓練速度。在模型實際佔用顯存很少的狀況下,同一張GPU卡能夠同時運行多個深度學習訓練/預測任務。github

     

  2. 支持限制任務的最大顯存策略,每一個任務只能在限定的顯存量下運行,實現同一張GPU卡多個任務間的顯存隔離數組

     

  3. 默認使用Lazy顯存分配方式。只有GPU卡工做時才自動分配顯存,實現不一樣GPU卡上的任務的相互隔離,能夠在一臺機器上實現更靈活的任務排布。緩存

 

這三種顯存策略在飛槳是如何實現的?下面咱們走進飛將框架一探究竟。框架

 

01 AutoGrowth實現顯存按需分配,且不影響訓練速度

 

1.7版本以前,飛槳默認是顯存預分配策略(缺省比例是可用顯存的92%),該策略在實現上是比較高效的,可是預分配比例的設置是一個比較頭疼的事情。若是採用92%的缺省配置,能夠保證大部分狀況下任務成功分配,但麻煩的是啓動任務以後,即便模型實際佔用顯存較小,也沒法再啓動其餘的任務了。所以飛槳v1.7升級爲顯存自增加按需分配的AutoGrowth做爲默認的顯存分配策略dom

 

考慮對模型訓練速度的影響,若是直接使用cudaMalloc和cudaFree接口進行顯存分配和釋放,調用的過程很是耗時,會嚴重影響模型的訓練和預測速度。飛槳v1.7對此進行了改進,AutoGrowth顯存分配策略經過緩存顯存的方式提高顯存分配和釋放速度,如圖1所示。學習

 

圖1 AutoGrowth顯存分配策略示意圖fetch

 

框架內部緩存Memory Cache中緩存了若干顯存塊block,當用戶申請request_size大小的顯存時,AutoGrowth策略內部的具體流程以下:ui

 

  • 若Memory Cache爲空,或者全部block均小於request_size,經過調用cudaMalloc從GPU中申請顯存(對應圖1中的large_request_size)。

  • 若Memory Cache不爲空,且存在大於等或者request_size大小的block,查找到知足條件的最小block,從中分割出request_size大小的顯存返回給用戶。

  • 顯存釋放時,釋放的顯存將存儲到Memory Cache中,再也不返回給GPU。

 

能夠看到,整個策略設計是很是高效的。經過AutoGrowth策略,實現按需分配顯存的同時,也保證了模型訓練速度不受影響。

 

實驗觀察

 

下面以ResNet50 batch_size=32單卡訓練爲例,觀察一下,執行AutoGrowth策略後,顯存的佔用狀況。

 

首先您須要在本地安裝飛槳1.7,而後在飛槳GitHub中下載模型庫代碼,運行以下命令,進入」models/PaddleCV/image_classification」目錄。

 

git clone -b release/1.7 https://github.com/PaddlePaddle/models.gitcd models/PaddleCV/image_classification

 

執行以下命令啓動ResNet50單卡訓練任務。

 

export CUDA_VISIBLE_DEVICES=0python train.py  --model=ResNet50  --data_dir=./data/ILSVRC2012/  --batch_size=32

 

 

  • data_dir:設置ImageNet數據集的路徑。

  • batch_size:設置batch_size爲32。

 

訓練任務啓動後,運行nvidia-smi命令,觀察GPU顯存的佔用狀況。

 

運行1個ResNet50訓練任務,顯存佔用約4G。(飛槳1.7以前,運行1個ResNet50訓練任務,顯存空間就徹底被佔滿。)

 

 

運行2個訓練任務,顯存佔用約8G。

 

 

運行3個訓練任務,顯存佔用約12G。

 

 

運行4個訓練任務,顯存佔用約16G,此時顯存徹底被佔滿。

 

 

實驗證實:使用AutoGrowth策略後,一張16G V100的GPU能夠並行4個ResNet50訓練任務。那麼,AutoGrowth策略的使用會不會影響模型的訓練速度呢?

 

在模型訓練初期,因爲Memory Cache爲空或block數量不多,框架會先從GPU中申請顯存。顯存釋放時會存儲在Memory Cache中,所以Memory Cache中的block會不斷增長。後續顯存請求會愈來愈多的從Memory Cache中先獲取到,所以使用AutoGrowth策略後,訓練速度保持不變。

 

 

 

02 支持限制任務的最大顯存策略,實現單卡多任務間的資源隔離

 

實際應用中,常會遇到多個開發者使用同一個GPU卡進行模型訓練的場景,此時須要將GPU卡的顯存分爲若干份,分給開發者獨立使用。飛槳1.7支持自定義每一個任務使用的最大顯存策略,用戶只須要配置幾個參數,便可實現同一張GPU卡多個任務間的資源隔離。

 

例如,若想限定某個任務的最大顯存佔用量不超過2048MB,代碼以下:

 

export  FLAGS_gpu_memory_limit_mb=2048

 

環境變量FLAGS_gpu_memory_limit_mb表示限定每一個任務的最大顯存佔用量,爲uint64類型的整數,單位爲MB。

 

  • 默認值爲0,表示飛槳任務可使用全部可用的顯存資源,不設上限。

  • FLAGS_gpu_memory_limit_mb > 0,表示飛槳任務僅可以使用不超過FLAGS_gpu_memory_limit_mb MB的顯存。

 

若FLAGS_gpu_memory_limit_mb > 0,飛槳框架內部會對GPU顯存分配cudaMalloc和釋放cudaFree這兩個接口進行監控,保證任務佔用的顯存量不超過用戶設定的閾值。

 

舉例來講,用戶經過下述代碼申請了2G大小的Numpy數組,並拷貝到飛槳的GPU Tensor中。

 


import paddle.fluid as fluidimport numpy as np# 申請2G大小的Numpy數組two_gb_numpy_array = np.ndarray([2, 1024, 1024, 1024], dtype='uint8')place = fluid.CUDAPlace(0)t = fluid.Tensor()t.set(two_gb_numpy_array, place) # 將2G大小的Numpy數組拷貝到GPU上

 

  • 若未設置FLAGS_gpu_memory_limit_mb,上述飛槳任務可正常運行,任務佔用2048MB顯存。

  • 若設置了FLAGS_gpu_memory_limit_mb=1024,則會報出顯存不足錯誤,如圖2所示。代表任務使用的最大顯存量被限定爲1024MB。

 

圖2顯存不足報錯提示

 

03 默認LAZY顯存分配方式,實現不一樣卡上訓練任務的隔離

 

下面經過執行一段簡單的飛槳訓練代碼,瞭解下使用LAZY策略後,顯存分配方式的變化。假設用戶有2張GPU卡,分別爲GPU 0和GPU 1。GPU 1被訓練任務佔用了16092MB顯存,幾乎將顯存徹底佔滿。

 

 

在LAZY模式下,用戶仍能夠在GPU 0上執行訓練任務,以下代碼所示。

 




import paddle.fluid as fluidimport numpy as npx = fluid.data(name='x', shape=[None, 784], dtype='float32')fc = fluid.layers.fc(x, size=10)loss = fluid.layers.reduce_mean(fc)sgd = fluid.optimizer.SGD(learning_rate=1e-3)sgd.minimize(loss)place = fluid.CUDAPlace(0)   # 使用GPU 0卡進行訓練exe = fluid.Executor(place)exe.run(fluid.default_startup_program())BATCH_SIZE = 32BATCH_NUM = 1000000for batch_id in range(BATCH_NUM):x_np = np.random.random([BATCH_SIZE, 784]).astype('float32')loss_np, = exe.run(fluid.default_main_program(),    feed={x.name: x_np}, fetch_list=[loss])    print('Batch id {}, loss {}'.format(batch_id, loss_np))

 

運行nvidia-smi命令,觀察GPU 0和GPU 1上的顯存佔用狀況。

 

 

GPU 0佔用了750MB的顯存,但GPU 1卡上的顯存佔用量仍爲16092MB,與任務啓動前的顯存佔用量一致,說明在GPU 0上執行訓練任務在GPU 1上不佔用任何顯存,實現了不一樣卡上訓練任務的隔離。

 

以上就是飛槳1.7給開發者們帶來的3個全新的顯存分配策略,但願能幫助你們更高效的完成模型訓練和預測。固然GPU顯存價格不菲,對於剛剛接觸深度學習的用戶,讓我告訴你如何得到飛槳的免費GPU算力,快速上手屬於你的深度學習任務,詳情請戳以下連接(或點擊「閱讀原文」):

https://ai.baidu.com/support/news?action=detail&id=981

 

若是您加入官方QQ羣,您將趕上大批志同道合的深度學習同窗。官方QQ羣:703252161。

 

若是您想詳細瞭解更多飛槳的相關內容,請參閱如下文檔。

 

官網地址:https://www.paddlepaddle.org.cn

本地安裝飛槳1.7:

https://www.paddlepaddle.org.cn/install/quick

 

飛槳核心框架項目地址:

 

GitHub: https://github.com/PaddlePaddle/Paddle

Gitee: https://gitee.com/paddlepaddle/Paddle

>> 訪問 PaddlePaddle 官網,瞭解更多相關內容 ​​​​​​​

相關文章
相關標籤/搜索