摘要:到目前為止我們依然遺留了一個對在單機上使用深度學習框架來說最重要的問題如何利用,也包括利用多個進行訓練。中使用對輸入數據進行切分,使用合并多個卡上的計算結果??偨Y如何利用多個卡進行訓練對復雜模型或是大規模數據集上的訓練任務往往是必然的選擇。
到目前為止我們依然遺留了一個對在單機上使用深度學習框架來說最重要 的問題:如何利用 GPU, 也包括利用多個 GPU 進行訓練。深度學習模型的訓練往往非常耗時,在較大數據集上訓練或是訓練復雜模型往往會借助于 GPU 強大的并行計算能力。 如何能夠讓模型運行在單個/多個 GPU 上,充分利用多個 GPU 卡的計算能力,且無需關注框架在多設備、多卡通信實現上的細節是這一篇要解決的問題。?
這一篇我們以 RNN 語言模型為例。RNN 語言模型在 第三篇已經介紹過,這一篇我們維持原有的模型結構不變,在以下兩處對第三節原有的例子進行改建:?
1. 為 PaddleFluid 和 TensorFlow 模型添加上多 GPU 卡運行的支持。?
2. 使用 TensorFlow 的 dataset API 為 TensorFlow 的 RNN 語言模型重寫數據讀取 部分,以提高 I/O 效率。?
請注意,這一篇我們主要關于 如何利用多 GPU 卡進行訓練,請盡量在有多 塊 GPU 卡的機器上運行本節示例。
如何使用代碼
本篇文章配套有完整可運行的代碼, 請隨時從 github [1] 上獲取代碼。代碼包括以下幾個文件:
在執行訓練任務前,請首先進入 data 文件夾,在終端執行下面的命令進行訓練數據下載以及預處理。
sh download.sh
在終端運行以下命令便可以使用默認結構和默認參數運行 PaddleFluid 訓練序列標注模型。
python train_fluid_model.py
在終端運行以下命令便可以使用默認結構和默認參數運行 TensorFlow 訓練序列標注模型。
python train_tf_model.py
數據并行與模型并行
這一篇我們僅考慮單機多設備情況,暫不考慮網絡中的不同計算機。當我們單機上有多種計算設備(包括 CPU,多塊不同的 GPU 卡),我們希望能夠充分利用這些設備一起完成訓練任務,常用的并行方式分為三種: ?
模型并行( model parallelism ):不同設備(GPU/CPU 等)負責網絡模型的不同部分 例如,神經網絡模型的不同網絡層被分配到不同的設備,或者同一層內部的不同參數被分配到不同設備。?
每個設備都只有一部分 模型;不同設備之間會產生通信開銷 ;
?
神經網絡的計算本身有一定的計算依賴,如果計算本身存在依賴無法并行進行,不同設備之間可能會產生等待。
數據并行( data parallelism ):不同的設備有同一個模型的多個副本,每個設備分配到不同的數據,然后將所有機器的計算結果按照某種方式合并。?
每個計算設備都有一份完整的模型各自計算,指定某個設備作為 controller,將多個設備的計算結果進行合并;
?
在神經網絡中,通常需要合并的是多個設備計算的梯度,梯度合并后再進行 clipping,計算正則,計算更新量,更新參數等步驟;
?
較大化計算效率的關鍵是盡可能降低串行避免計算設備的等待。?
混合并行(Hybrid parallelism):既有模型并行,又有數據并行。?
模型并行往往使用在模型大到單個計算設備已經無法存儲整個模型(包括模型本身和計算過程中產生的中間結果)的場景,或是模型在計算上天然就存在多個 沒有強計算依賴的部分,那么很自然的可以將這些沒有計算依賴的部分放在不同設備上并行地進行計算。
然而,隨著計算設備的不斷增多,模型并行較難以一種通用的可擴展的方法達到接近線性加速的效果。一方面如何重疊(overlap)計算開銷與跨設備通信開銷依賴于對系統硬件豐富的知識和經驗,另一方面神經網絡計算的依賴性 會讓模型的拆分隨著設備的增加越發困難。
數據并行中每一個設備都維護了完整的模型,與模型并行相比往往會耗費更多的存儲空間。但數據并行的優點是:通用性很好,適用于所有可能的神經網絡模型結構。同樣地,隨著設備數目的增加通信代價也會越來越高,一般情況下在 2~8 卡時依然可以做到接近線性加速比。
需要注意的是,隨著越來越多設備的加入,數據并行會導致 batch size 增大,一個 epoch 內參數更新次數減少,往往都需要對學習率,學習率 decay 進行再調參,否則可能會引起學習效果的下降。?
鑒于在使用中的通用性和有效性,這一篇中我們主要介紹更加通用的數據并行方法。非?;\統的,數據并行遵從一下的流程,其中一個 | 代表一個計算設備:
| ? ? ? ? ? 1. 將模型參數拷貝到不同的設備
| ? ? ? ? ? 2. 對輸入數據均勻切分到不同的計算設備
|||| ? ? ? ?3. 多個設備并行進行前向計算
|||| ? ? ? ?4. 多個設備形象進行反向計算
| ? ? ? ? ? 5. 多個設備計算的梯度在主卡合并
| ? ? ? ? ? 6. 計算參數更新量,更新參數
| ? ? ? ? ? to 1
PaddleFluid使用多GPU卡進行訓練
在 PaddleFluid 中使用多個 GPU 卡以數據并行的方式訓練需要引入 parallel_do 原語。顧名思義, parallel_do 會負責數據的切分,在多個設備上并行地執行一段相同的計算,最后合并計算結果。
與 ParallelDo 函數功能相近的函數還有 ParallelExecutor,大家也可以自行嘗試一下。ParallelExecutor 的具體使用方式可以參考 API 文檔:
http://www.paddlepaddle.org/docs/develop/api/fluid/en/executor.html
圖 1 是 parallel_do 的原理示意圖:?
圖1. PaddleFluid中的Parallel do
下面我們來看看如何使用 parallel_do 讓我們在第三篇中實現的 RNN LM 可在多個 GPU 上訓練 ,下面是核心代碼片段,完整代碼請參考 rnnlm_fluid.py。
places = fluid.layers.get_places()
pd = fluid.layers.ParallelDo(places)
with pd.do():
? ? word_ = pd.read_input(word)
? ? lbl_ = pd.read_input(lbl)
? ? prediction, cost = self.__network(word_, lbl_)
? ? pd.write_output(cost)
? ? pd.write_output(prediction)
cost, prediction = pd()
avg_cost = fluid.layers.mean(x=cost)
調用 places = fluid.layers.get_places() 獲取所有可用的計算設備 ??梢酝ㄟ^設置 CUDA_VISIBLE_DEVICES 來控制可見 GPU 的數據。?
?pd = fluid.layers.ParallelDo(places) 指定將在 那些設備上并行地執行。?
?parallel_do 會構建一段 context,在其中定義要并行執行的計算,調用 pd.read_input 切分輸入數據,在 parallel_do 的 context 之外調用 pd() 獲取合并后的最終計算結果。
with pd.do():
? x_ = pd.read_input(x) ?# 切分輸入數據 x
? y_ = pd.read_input(y) ?# 切分輸入數據 y
? # 定義網絡
? cost = network(x_, y_)
? pd.write_output(cost)
cost = pd() ?# 獲取合并后的計算結果
TensorFlow中使用多GPU卡進行訓練
在 TensorFlow 中,通過調用 with tf.device() 創建一段 device context,在這段 context 中定義所需的計算,那么這 些計算將運行在指定的設備上。?
TensorFlow 中實現多卡數據并行有多種方法,常用的包括單機 ParameterServer 模式;Tower 模式 [2],甚至也 可以使用的 nccl [3] all reduce 系列 op 來實現梯度的聚合。這里我們以 Tower 模式為基礎,介紹一種簡單易用的多 GPU 上的數據并行方式。下面是核心代碼片段,完整代碼請參考 rnnlm_tensorflow.py。
def make_parallel(fn, num_gpus, **kwargs):
? ? ? ? in_splits = {}
? ? ? ? for k, v in kwargs.items():
? ? ? ? ? ? in_splits[k] = tf.split(v, num_gpus)
? ? ? ? out_split = []
? ? ? ? for i in range(num_gpus):
? ? ? ? ? ? with tf.device(tf.DeviceSpec(device_type="GPU", device_index=i)):
? ? ? ? ? ? ? ? with tf.variable_scope(
? ? ? ? ? ? ? ? ? ? ? ? tf.get_variable_scope(), reuse=tf.AUTO_REUSE):
? ? ? ? ? ? ? ? ? ? out_i = fn(**{k: v[i] for k, v in in_splits.items()})
? ? ? ? ? ? ? ? ? ? out_split.append(out_i)
? ? ? ? return tf.reduce_sum(tf.add_n(out_split)) / tf.to_float(
? ? ? ? ? ? self.batch_size)
?make_parallel 的第一個參數是一個函數,也就是我們自己定義的如何創建神經網絡模型函數。第二個參數指定 GPU 卡數,數據將被平均地分配給這些 GPU。除此之外的參數將以 keyword argument 的形式傳入,是神經網絡的輸入層 Tensor 。?
在定義神經網絡模型時,需要創建 varaiable_scope ,同時指定 reuse=tf.AUTO_REUSE ,保證多個 GPU 卡上的可學習參數會是共享的。?
?make_parallel 中使用 tf.split op 對輸入數據 Tensor 進行切分,使用 tf.add_n 合并多個 GPU 卡上的計算結果。
一些情況下同樣可以使用 tf.concat 來合并多個卡的結算結果,這里因為使用了 dataset api 為 dynamic rnn feed 數據,在定義計算圖時 batch_size 和 max_sequence_length 均不確定,無法使用 tf.concat 。?
下面是對 make_parallel 的調用,從中可看到如何使用 make_parallel 方法。
self.cost = self.make_parallel(
? ? ? ? ? ? self.build_model,
? ? ? ? ? ? len(get_available_gpus()),
? ? ? ? ? ? curwd=curwd,
? ? ? ? ? ? nxtwd=nxtwd,
? ? ? ? ? ? seq_len=seq_len)
除了調用 make_parallel 之外,還有一處修改需要注意:在定義優化方法時,需要將 colocate_gradients_with_ops 設置為 True,保證前向 Op 和反向 Op 被放置在相同的設備上進行計算。
optimizer.minimize(self.cost, colocate_gradients_with_ops=True)
總結
如何利用多個 GPU 卡進行訓練對復雜模型或是大規模數據集上的訓練任務往往是必然的選擇。鑒于在使用中的有效性和通用性,這一節我們主要介紹了在 PaddleFluid 和 TensorFlow 上通過數據并行使用多個 GPU 卡最簡單的方法。
這一篇所有可運行的例子都可以在 04_rnnlm_data_parallelism [4] 找到,更多實現細節請參考具體的代碼。值得注意的是,不論是 PaddleFluid 還是 TensorFlow 都還有其他多種利用多計算設備提高訓練并行度的方法。請大家隨時關注官方的文檔。
參考文獻
[1]. 本文配套代碼
https://github.com/JohnRabbbit/TF2Fluid/tree/master/04_rnnlm_data_parallelism
[2]. Tower模式?
https://github.com/tensorflow/models/blob/master/tutorials/image/cifar10/cifar10_multi_gpu_train.py
[3]. nccl
https://www.tensorflow.org/api_docs/python/tf/contrib/nccl
[4]. 04_rnnlm_data_parallelism
https://github.com/JohnRabbbit/TF2Fluid/tree/master/04_rnnlm_data_parallelism
聲明:文章收集于網絡,如有侵權,請聯系小編及時處理,謝謝!
歡迎加入本站公開興趣群商業智能與數據分析群
興趣范圍包括各種讓數據產生價值的辦法,實際應用案例分享與討論,分析工具,ETL工具,數據倉庫,數據挖掘工具,報表系統等全方位知識
QQ群:81035754
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/4785.html
閱讀 2567·2023-04-25 17:33
閱讀 648·2021-11-23 09:51
閱讀 2950·2021-07-30 15:32
閱讀 1394·2019-08-29 18:40
閱讀 1939·2019-08-28 18:19
閱讀 1464·2019-08-26 13:48
閱讀 2236·2019-08-23 16:48
閱讀 2274·2019-08-23 15:56