飛槳自動混合精度技術,讓你的訓練速度飛起來。php
隨着生活節奏的加快,「等待」已經愈來愈成爲人們但願遠離的事情。可是在深度學習領域,模型的參數、數據集的規模等等動輒就是以億爲單位,甚至更大,所以當模型訓練成功之時,放一首張靚穎的「終於等到你」做爲背景音樂實在是太應景了。git
那若是如今向你推薦一款神器,能夠實現訓練速度翻倍,訪存效率翻倍,你心動嗎?心動不如行動(這可不是電視直銷,彆着急換頻道),來和我一塊兒看看這款神器——基於飛槳核心框架的自動混合精度(Automatic Mixed Precision) 技術,簡稱飛槳 AMP 技術。github
飛槳 AMP 技術僅僅經過一行代碼便可幫助用戶簡便快速的將單精度訓練的模型修改成自動混合精度訓練。同時經過黑白名單和動態 Loss Scaling 來保證訓練的穩定性,避免出現 INF 或者 NAN 問題。飛槳 AMP 能夠充分發揮新一代 NVIDIA GPU 中 Tensor Core 的計算性能優點,ResNet50、Transformer 等模型的訓練速度與單精度訓練相比能夠提高到 1.5~2.9 倍。網絡
那麼它是怎麼實現的呢?咱們先從什麼是自動混合精度技術講起。session
01
架構
什麼是自動混合精度技術框架
顧名思義,自動混合精度是一種自動將半精度和單精度混合使用,從而加速模型訓練的技術。其中單精度(Float Precision32,FP32)好理解,是計算機經常使用的一種數據類型。那麼半精度是什麼呢?如圖 1 所示,半精度(Float Precision16,FP16)是一種相對較新的浮點類型,在計算機中使用 2 字節(16 位)存儲,在 IEEE 754-2008 中,它被稱做 binary16。與計算中經常使用的單精度和雙精度類型相比,Float16 更適於在精度要求不高的場景中使用。函數
圖 1 半精度和單精度數據示意圖佈局
不言而喻,在深度學習領域,若是使用 Float16 代替 Float32 來存儲數據,那麼開發者就能夠訓練更大更復雜的模型,使用更大的 batch size。所以對於那些巴不得挖掘出 GPU 裏每個晶體管所有潛力的科學家們怎麼能放過它呢?同時因爲 NVIDIA 推出了具有 Tensor Core 技術的 Volta 及 Turing 架構 GPU,使半精度計算趨向成熟。在相同的 GPU 硬件上,Tensor Core 的半精度計算吞吐量是單精度的 8 倍。性能
但顯而易見,使用 Float16 確定會同時帶來計算精度上的損失。但對深度學習訓練而言,並非全部計算都要求很高的精度,一些局部的精度損失對最終訓練效果影響很微弱,僅須要某些特殊步驟保留 Float32 的計算精度便可。所以混合精度計算的需求應運而生。咱們能夠將訓練過程當中一些對精度損失不敏感且能使用 Tensor Core 進行加速的運算使用半精度處理,最大限度的提高訪存和計算效率。
可是對每一個具體模型,人工去設計和嘗試精度混合的方法,是很是繁瑣的,咱們迫切須要一種更簡潔的方式,高效地實現混合精度的訓練。AMP,顧名思義,就是讓混合精度訓練自動化,所以使用簡單是它的重要特點。具體咋用,我們往下看!
02
AMP 的使用方法
下面以 MNIST 爲例介紹如何使用飛槳 AMP 技術。MNIST 網絡定義的代碼以下所示。其中 conv2d、batch_norm(bn)和 pool2d 的數據佈局須要提早設置爲'NHWC',這樣有利於加速混合精度訓練,而且 conv2d 的輸出通道數須要設置爲 4 的倍數,以便使用 Tensor Core 技術加速。
import paddle.fluid as fluid def MNIST(data, class_dim): conv1 = fluid.layers.conv2d(data, 16, 5, 1, act=None, data_format='NHWC') bn1 = fluid.layers.batch_norm(conv1, act='relu', data_layout='NHWC') pool1 = fluid.layers.pool2d(bn1, 2, 'max', 2, data_format='NHWC') conv2 = fluid.layers.conv2d(pool1, 64, 5, 1, act=None, data_format='NHWC') bn2 = fluid.layers.batch_norm(conv2, act='relu', data_layout='NHWC') pool2 = fluid.layers.pool2d(bn2, 2, 'max', 2, data_format='NHWC') fc1 = fluid.layers.fc(pool2, size=50, act='relu') fc2 = fluid.layers.fc(fc1, size=class_dim, act='softmax') return fc2
爲了訓練 MNIST 網絡,還須要定義損失函數來更新權重參數,此處使用的優化損失函數是 SGDOptimizer。爲了簡化說明,這裏省略了迭代訓練的相關代碼,僅體現損失函數及優化器定義相關的內容。
import paddle.fluid as fluid import numpy as np data = fluid.layers.data( name='image', shape=[None, 28, 28, 1], dtype='float32') label = fluid.layers.data(name='label', shape=[None, 1], dtype='int64') out = MNIST(data, class_dim=10) loss = fluid.layers.cross_entropy(input=out, label=label) avg_loss = fluid.layers.mean(loss) sgd = fluid.optimizer.SGDOptimizer(learning_rate=1e-3) sgd.minimize(avg_loss)
那麼如何將上面的示例改形成使用 AMP 訓練的方式呢?用戶僅須要使用飛槳提供的 AMP 函數 fluid.contrib.mixed_precision.decorate 將原來的優化器 SGDOptimizer 進行封裝,而後使用封裝後的優化器(mp_sgd)更新參數梯度,代碼以下所示:
sgd = fluid.optimizer.SGDOptimizer(learning_rate=1e-3) mp_sgd = fluid.contrib.mixed_precision.decorator.decorate(sgd) mp_sgd.minimize(avg_loss)
如上即爲最簡單的飛槳 AMP 功能使用方法。
可是你們可能有些疑問,模型是如何感知哪些算子(Op)須要被轉換呢?是否是還須要手工指定呢?算子那麼多,我怎麼知道哪一個算子能夠被轉換呢?彆着急,飛槳已經幫你定製好了,這也是這門技術被稱爲「自動」的緣由之一,且請往下看!
03
黑白名單功能
爲了讓開發者能夠方便快捷的使用混合精度計算,飛槳的工程師們使用了大量模型在不一樣應用場景中反覆驗證,而後根據半精度數據類型計算的穩定性和加速效果,梳理出一系列適合轉換爲半精度計算的算子,並將這些算子定義到了一份白名單文件中。同時對於一些通過驗證發現不適合轉換的算子,也就是使用半精度計算會致使數值不精確的算子將被記錄到黑名單文件中。此外一些對半精度計算沒有多少影響的算子歸類於灰名單。在使用 AMP 訓練過程當中,系統會自動讀取黑白名單,從而感知到哪些算子須要被轉換爲半精度計算。
對於某些特殊場景,若是開發者但願使用自定義的黑白名單,則可使用 AutoMixedPrecisionLists 類設置,代碼示例以下所示。
sgd = SGDOptimizer(learning_rate=1e-3) # 指定自定義的黑白名單,其中 list1 和 list2 爲包含有算子名稱的列表 amp_list = AutoMixedPrecisionLists(custom_white_list=list1,custom_black_list=list2) mp_sgd = fluid.contrib.mixed_precision.decorator.decorate(sgd, amp_list) mp_sgd.minimize(avg_loss)
那麼自動混合精度技術被稱爲「自動」的緣由之二呢?那就是下面的自動調整 Loss Scaling 功能。
04
自動調整 Loss Scaling
AMP 技術在提高訪存和計算效率的同時,伴隨的反作用也是很明顯的。那就是因爲半精度數據類型的精度範圍與轉換前的單精度相比過窄,致使容易產生 INF 和 NAN 問題。爲了不此類問題,AMP 技術實現了自動調整 Loss Scaling 功能,即在 AMP 訓練過程當中,爲了不精度下溢,每訓練必定數量批次的數據,就將 Loss 放大指定倍數。若是 Loss 在放大過程當中發生上溢,則能夠再縮小必定倍數,確保整個訓練過程當中,梯度能夠正常收斂。
fluid.contrib.mixed_precision.decorate 函數攜帶了自動調整 Loss Scaling 功能相關的參數,這些參數都帶有默認值,以下面代碼所示。這些默認值都是通過飛槳工程師屢次驗證後定義的。一般狀況下,用戶能夠直接使用,無需從新設置。
sgd = SGDOptimizer(learning_rate=1e-3) mp_sgd = fluid.contrib.mixed_precision.decorator.decorate(sgd, init_loss_scaling=2**15, incr_every_n_steps=2000, use_dynamic_loss_scaling=True) mp_sgd.minimize(avg_loss)
05
多卡 GPU 訓練的優化
在新發布的飛槳核心框架 1.7 版本上,AMP 技術深度優化了多卡 GPU 訓練。如圖 2 所示,在優化以前的參數梯度更新過程當中,梯度計算時雖然使用的是半精度數據類型,可是不一樣 GPU 卡之間的梯度傳輸數據類型仍爲單精度。
圖 2 1.7 版本以前的參數梯度更新過程示意圖
爲了下降 GPU 多卡之間的梯度傳輸帶寬,咱們將梯度傳輸這個過程提到 Cast 操做以前,而每一個 GPU 卡在獲得對應的半精度梯度後再執行 Cast 操做,將其轉變爲單精度類型,如圖 3 所示。這一優化在訓練網絡複雜度較大的模型時,對減小帶寬佔用方面很是有效,如多卡訓練 BERT-Large 模型。
圖 3 1.7 版本的參數梯度更新過程示意圖
06
訓練性能對比(AMP VS FP32)
飛槳 AMP 技術在 ResNet50、Transformer 等模型上訓練速度相對於 FP32 訓練來講有很是大的優點,下面以 ResNet50 模型爲例,從下圖中能夠看出,ResNet50 的 AMP 訓練相對與 FP32 訓練,單卡加速比可達 2.9 倍,八卡加速比可達 2.8 倍。
相關資料
Mixed Precision Training:https://arxiv.org/abs/1710.03740
使用自動混合精度加速 PaddlePaddle 訓練:https://on-demand-gtc.gputechconf.com/gtcnew/sessionview.php?sessionName=cn9312-使用自動混合精度加速+paddlepaddle+訓練
若是您加入官方 QQ 羣,您將趕上大批志同道合的深度學習同窗。官方 QQ 羣:703252161。
若是您想詳細瞭解更多飛槳的相關內容,請參閱如下文檔。
官網地址:https://www.paddlepaddle.org.cn
飛槳核心框架項目地址:
https://github.com/PaddlePaddle/Paddle
本文分享 CSDN - 飛槳PaddlePaddle。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。