【轉載】ERNIE2.0背後的神助攻:飛槳高性能分佈式訓練引擎

互聯網新技術新應用動態2019-08-19 09:40:16

機器之心發佈

來源:百度飛槳

最近,百度 ERNIE 再升級,發佈持續學習語義理解框架 ERNIE 2.0,該模型在共計 16 箇中英文任務上超越了 BERT 和 XLNet,取得了 SOTA 效果。在ERNIE 2.0 預訓練模型耀眼光環背後的神助攻,正是源於飛槳(PaddlePaddle)長期產業實踐積累的高效率GPU分佈式訓練能力。

(圖片來自網絡)


ERNIE 連續獲得業界 SOTA 效果,離不開飛槳高性能分佈式訓練引擎提供的強大支撐。舉例來説,在計算複雜度較高的深層 Multi Head Self-Attention 結構和成本較低的海量無監督的中文預訓練語料,數據量和算力需求都是超乎想象的,不僅要求我們擁有大量高性能計算芯片,還要有非常強大的分佈式訓練能力。


1. 分佈式訓練的本質目的:提高迭代效率與降低訓練成本


深度學習模型的效果迭代對訓練速度非常敏感,能夠帶來高性能並行訓練的深度學習框架是實際開發和應用的剛需。


相同的硬件設備數,高效率的分佈式訓練,可以大大縮短產品迭代週期。而在受限的時間要求下,高效率的平台型工具也可以顯著減少硬件需求。時間的節省和成本的降低,毫無疑問值得企業重點關注。


2. 源於產業實踐的飛槳高性能分佈式訓練引擎


飛槳,源於產業實踐的深度學習平台,既是來源於產業實踐,又是服務於產業實踐。
一方面,從實際業務需求出發,面向百度海量的業務數據進行深入優化,並做通用化設計嵌入框架。經過百度大量業務場景的反覆打磨,形成一套滿足工業級業務需求的深度學習框架。


另一方面,在已有業務實踐的基礎上,飛槳又會進一步服務於新的業務以及人工智能前沿領域的探索中,不斷優化整體研發速度。ERNIE 的不斷創新與多機多卡訓練的迭代效率密切相關,相關的基礎能力正是源於飛槳對於自然語言處理或視覺任務高效支持的積累。


當前,Paddle Fluid 1.5 版本面向開發者開放更多更強大分佈式訓練能力:包括通用場景下的高擴展性並行組件,以及面向特殊場景的定製化並行訓練組件,並通過 High Level API Fleet 面向社區用户提供分佈式訓練方法。


2.1 面向通用場景的並行組件


2019 年 7 月,飛槳發佈了 Paddle Fluid 1.5 版本,面向通用 GPU 多機多卡場景的訓練,為用户帶來了更多新的特性,訓練效率相比 1.4 版本有了大幅度提升。截至目前,飛槳團隊在通信拓撲、通信內容、通信併發等方面實現了多項業界主流的加速技術,並形成靈活可配置的 Operator。開發者可以通過多種不同 Operator 的組合形成組合優勢,全面提升並行訓練的加速能力。


(1)多種通信拓撲的支持:(Ring-Topo、H-Topo)
支持多種通信拓撲結構,ring based allreduce,hierachical allreduce 等,在不同的節點範圍,用户可以定製不同的通信拓撲,靈活提升性能。
(2)通信內容智能聚合:(G-Fuse、Auto-Fuse)
通過對模型參數梯度尺寸的分析,啟發式地將梯度進行合理的聚合,可以使訓練過程中遇到的較小的梯度進行匯聚,用相同的延時完成多個碎片梯度的通信。
(3)靈活可配置的通信併發:(Multi-Comm(Mc))
支持多流通信技術,能夠將通信相關的 Operator 進行併發,進一步減小通信的整體時間。在計算與通信併發方面,通過在編譯期對用户定義的計算圖拓撲進行分析,可以找到通信 Operator 調度的合適時機,使通信與計算能夠最大限度地重疊,從而提升 GPU 的整體利用率。
(4)組件化的 Collective Opeartor 設計
通過將通信組件 Operator 化,並在不同的並行算法下將用户定義的 Program 進行轉譯,插入合適的通信組件,使得用户、開發者和框架設計都得到了極大的自由度。


下圖中比較了不同的優化方案組合給 ERNIE 帶來的訓練性能的提升,相比與 Paddle Fluid 1.4 版本沒有增加優化策略的基線,可以看到多種擴展性優化策略的組合帶來的性能提升是十分顯著的。


此外,基於最優優化策略的組合,我們以自然語言處理和計算機視覺兩個領域公開可獲取的經典預訓練模型作為 Benchmark 進行對比。在擴展性方面,從結果可以看出,隨着節點數目的增加,Paddle Fluid 1.5 在吞吐方面優勢更加明顯。在 8x8 v100 硬件條件下,Paddle Fluid 1.5 在不同任務下相比其他主流實現可以獲得 20%-100% 的速度提升。



硬件配置


模型配置


2.2 面向特殊場景的並行組件


Paddle Fluid 1.5 除了面向一般場景提供的通用並行能力外,還針對特殊場景研發內建(Built-in)並行能力。


在公有云場景下,GPU 資源非常昂貴,如果用户的計算量很大,可以選擇多機訓練。但公有云環境 GPU 節點之間,由於調度或者資源碎片等問題通常會造成網絡互聯不是最優狀態,網絡的帶寬相比大公司定製化的訓練集羣會有一定折扣。
針對這種高性能計算硬件、低配置網絡環境的公有云場景,飛槳團隊在 Paddle Fluid 1.4 版本就推出了以稀疏通信技術為主的並行訓練方法,通過不斷的累計本地梯度,同步最有代表性的少量梯度,在保證模型收斂的前提下可以將通信量減小為原始通信量的 1% 以內,大大降低了網絡通信負載。


如下圖所示,在帶寬壓縮到 1Gb/s 的情況下,通用的多機多卡並行訓練方法的吞吐能力已經趨近於 0,而 Paddle Fluid 1.5 基於稀疏通信的並行訓練方法依然可以保持較高的吞吐量


硬件配置

模型配置


收斂效果:基於 Imagenet 數據集,Resnet50 模型的收斂效果在稀疏通信下與常規的並行訓練方法沒有損失,證明了稀疏通信訓練方法的有效性。

2.3 簡單易用的 High Level API——Fleet


從 Paddle Fluid 1.5.1 開始,針對分佈式訓練的易用性問題,飛槳團隊推出 Fleet API 作為分佈式訓練的統一方式。Fleet 的命名出自於 PaddlePaddle,象徵一個艦隊中的多隻雙槳船協同工作。Fleet 的設計在易用性和算法可擴展性方面做出了很好的折衷權衡。用户可以很容易從單機版的訓練程序,通過添加幾行代碼切換到分佈式訓練程序。此外,分佈式訓練的算法也可以通過 Fleet API 接口靈活定義。下面給出一個極簡示例,方便讀者感受一下 Fleet API 的易用性。


(1)我們定義 MLP 網絡如下:
import paddle.fluid as fluid

def mlp(input_x, input_y, hid_dim=128, label_dim=2):
    fc_1 = fluid.layers.fc(input=input_x, size=hid_dim, act='tanh')
    fc_2 = fluid.layers.fc(input=fc_1, size=hid_dim, act='tanh')
    prediction = fluid.layers.fc(input=[fc_2], size=label_dim, act='softmax')
    cost = fluid.layers.cross_entropy(input=prediction, label=input_y)
    avg_cost = fluid.layers.

(2)定義一個在內存生成數據的 Reader 如下:
import numpy as np

def gen_data():
    return {"x"
: np.random.random(size=(128,32)).astype('float32'),            "y": np.random.randint(2, size=(128,1)).astype('int64')}

(3)使用 Collective 訓練方法
Collective Training 通常在 GPU 多機多卡訓練中使用,一般在複雜模型的訓練中⽐較常見,我們基於上面的單機模型定義給出使用 Collective 方法進⾏分佈式訓練的示例如下: 
import paddle.fluid as fluid
from nets import mlp
from paddle.fluid.incubate.fleet.collective import fleet
from paddle.fluid.incubate.fleet.base import role_maker
from utils import gen_data

input_x = fluid.layers.data(name="x"
, shape=[32], dtype='float32')input_y = fluid.layers.data(name="y", shape=[1], dtype='int64')cost = mlp(input_x, input_y)optimizer = fluid.optimizer.SGD(learning_rate=0.01)role = role_maker.PaddleCloudRoleMaker(is_collective=True)fleet.init(role)optimizer = fleet.distributed_optimizer(optimizer)optimizer.minimize(cost)place = fluid.CUDAPlace(0)exe = fluid.Executor(place)exe.run(fluid.default_startup_program())step = 1001for i in range(step): cost_val = exe.run(program=fluid.default_main_program(), feed=gen_data(), fetch_list=[cost.name]) print("worker_index: %d, step%d cost = %f"% (fleet.worker_index(), i, cost_val[0]))

啟動單機八卡進行訓練:
python -m paddle.distributed.launch collective_train.py

快快自己動手嘗試下吧!


如果您想詳細瞭解更多飛槳的相關內容,請參閲以下文檔或點擊閲讀原文


官網地址:https://www.paddlepaddle.org.cn/?fr=jqzx4


更多示例與 Benchmark 請參考項目地址:
  • https://github.com/PaddlePaddle/Paddle?fr=jqzx4

  • https://github.com/PaddlePaddle/Fleet?fr=jqzx4



https://hk.wxwenku.com/d/201196682