雖然GPU對深度學習計算有廣泛明顯的加速做用,但其顯存也是有限的(如V100的最大顯存值也僅有32G),而深度學習模型的訓練和推理每每須要大量的顯存,用來支持更大的模型和更大的batch size。如何更高效地利用GPU顯存,在一張卡或一臺機器上同時承載更多的訓練和預測任務,讓有限的顯存支持多個開發者同時進行實驗,執行各自的任務呢?python
飛槳v1.7在GPU顯存使用策略方面作了以下3點升級:git
默認使用顯存自增加AutoGrowth策略,根據模型實際佔用的顯存大小,按需自動分配顯存,而且不影響訓練速度。在模型實際佔用顯存很少的狀況下,同一張GPU卡能夠同時運行多個深度學習訓練/預測任務。github
支持限制任務的最大顯存策略,每一個任務只能在限定的顯存量下運行,實現同一張GPU卡多個任務間的顯存隔離。數組
默認使用Lazy顯存分配方式。只有GPU卡工做時才自動分配顯存,實現不一樣GPU卡上的任務的相互隔離,能夠在一臺機器上實現更靈活的任務排布。緩存
這三種顯存策略在飛槳是如何實現的?下面咱們走進飛將框架一探究竟。框架
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=0
python 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策略後,訓練速度保持不變。
實際應用中,常會遇到多個開發者使用同一個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顯存不足報錯提示
下面經過執行一段簡單的飛槳訓練代碼,瞭解下使用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 官網,瞭解更多相關內容。