[分布式訓練] 單機多卡的正確打開方式:Horovod

[分布式訓練] 單機多卡的正確打開方式:Horovod

轉自:https://fyubang.com/2019/07/26/distributed-training4/

講完了單機多卡的分布式訓練的理論、TensorFlow和PyTorch分別的實現后,今天瓦礫講一個強大的第三方插件:Horovod。

Horovod是Uber開源的跨平臺的分布式訓練工具,名字來自于俄國傳統民間舞蹈,舞者手牽手圍成一個圈跳舞,與Horovod設備之間的通信模式很像,有以下幾個特點:

  1. 兼容TensorFlow、Keras和PyTorch機器學習框架。
  2. 使用Ring-AllReduce算法,對比Parameter Server算法,有著無需等待,負載均衡的優點。
  3. 實現簡單,五分鐘包教包會。(劃重點)

Uber官方在git上給了很詳細的例子: https://github.com/horovod/horovod/tree/master/examples,所以這里只簡單講一下大概的使用方法:

TensorFlow

以TF的Custom Training Loop API為例:

import tensorflow as tf
import horovod.tensorflow as hvd# 1. 初始化horovod
hvd.init()
# 2. 給當前進程分配對應的gpu,local_rank()返回的是當前是第幾個進程
config = tf.ConfigProto()
config.gpu_options.visible_device_list = str(hvd.local_rank())
# 3. Scale學習率,封裝優化器
opt = tf.train.AdagradOptimizer(0.01 * hvd.size())
opt = hvd.DistributedOptimizer(opt)
# 4. 定義初始化的時候廣播參數的hook,這個是為了在一開始的時候同步各個gpu之間的參數
hooks = [hvd.BroadcastGlobalVariablesHook(0)]
# 搭建model,定義loss
loss = ...
train_op = opt.minimize(loss)
# 5. 只保存一份ckpt就行
checkpoint_dir = '/tmp/train_logs' if hvd.rank() == 0 else None
# 7. 用MonitoredTrainingSession實現初始化,讀寫ckpt
with tf.train.MonitoredTrainingSession(checkpoint_dir=checkpoint_dir,config=config,hooks=hooks) as mon_sess:while not mon_sess.should_stop():# Perform synchronous training.mon_sess.run(train_op)

具體的代碼看tensorflow_mnist.py:https://github.com/horovod/horovod/blob/master/examples/tensorflow_mnist.py

單機雙卡訓練輸入以下命令:

CUDA_VISIBLE_DEVICES=6,7 horovodrun -np 2 -H localhost:2 python tensorflow_mnist.py

這里 -np指的是進程的數量。

執行之后可以看到如下的結果,因為多線程,每個step都打印了兩遍。

[1,0]<stderr>:INFO:tensorflow:loss = 0.13126025, step = 300 (0.191 sec)
[1,1]<stderr>:INFO:tensorflow:loss = 0.01396352, step = 310 (0.177 sec)
[1,0]<stderr>:INFO:tensorflow:loss = 0.063738815, step = 310 (0.182 sec)
[1,1]<stderr>:INFO:tensorflow:loss = 0.044452004, step = 320 (0.215 sec)
[1,0]<stderr>:INFO:tensorflow:loss = 0.028987963, step = 320 (0.212 sec)
[1,0]<stderr>:INFO:tensorflow:loss = 0.09094897, step = 330 (0.206 sec)
[1,1]<stderr>:INFO:tensorflow:loss = 0.11366991, step = 330 (0.210 sec)
[1,0]<stderr>:INFO:tensorflow:loss = 0.08559138, step = 340 (0.200 sec)
[1,1]<stderr>:INFO:tensorflow:loss = 0.037002128, step = 340 (0.201 sec)
[1,0]<stderr>:INFO:tensorflow:loss = 0.15422738, step = 350 (0.181 sec)
[1,1]<stderr>:INFO:tensorflow:loss = 0.06424393, step = 350 (0.179 sec)

PyTorch

Torch下也是類似的套路,但是由于PyTorch本身單機多卡訓練已經夠簡單了,API也穩定,所以筆者一般做的時候就是直接用Torch自己的DPDDP了。

import torch
import horovod.torch as hvd# 1. 初始化horovod
hvd.init()
# 2. 給當前進程分配對應的gpu,local_rank()返回的是當前是第幾個進程
torch.cuda.set_device(hvd.local_rank())
# Define dataset...
train_dataset = ...
# 3. 用DistributedSampler給各個worker分數據
train_sampler = torch.utils.data.distributed.DistributedSampler(train_dataset, num_replicas=hvd.size(), rank=hvd.rank())
train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=..., sampler=train_sampler)
# Build model...
model = ...
model.cuda()
# 4. 封裝優化器
optimizer = optim.SGD(model.parameters())
optimizer = hvd.DistributedOptimizer(optimizer, named_parameters=model.named_parameters())
# 5. 初始化的時候廣播參數,這個是為了在一開始的時候同步各個gpu之間的參數
hvd.broadcast_parameters(model.state_dict(), root_rank=0)
# 訓練
for epoch in range(100):for batch_idx, (data, target) in enumerate(train_loader):optimizer.zero_grad()output = model(data)loss = F.nll_loss(output, target)loss.backward()optimizer.step()if batch_idx % args.log_interval == 0:print('Train Epoch: {} [{}/{}]\tLoss: {}'.format(epoch, batch_idx * len(data), len(train_sampler), loss.item()))

速度

瓦礫還沒有來得及做一個全面的Horovod、tf.distribute和 Torch的單機多卡訓練速度的橫向對比,不過大家可以參考這兩篇:

  1. Horovod: fast and easy distributed deep learning in TensorFlow
  2. Goodbye Horovod, Hello CollectiveAllReduce

總體而言,用了All-Reduce算法的API,速度應該都差不多,如果你是土豪,擁有NVLINK(卡間通信極快)的話,那忘了我說的這幾篇“廢話”吧朋友。Orz。

總結

終于結束了單機多卡系列的最后一章,由于博客本身的限制,給的例子整體還是比較簡單,以入門為主,大家具體使用的時候肯定還是會遇到一些坑,這里瓦礫把踩過的一些坑和解決辦法列舉在這,以避免大家以后重復踩坑:

  • tf.contrib.distributed.MirroredStrategy 需要optimizer支持merge_call(bert實現的optimizer是直接修改apply_gradient的,所以會報錯),這個時候就需要正確地修改optimizer里的_apply_dense、_apply_sparse(參考Issue 23986 和 JayYip)。或者用horovod,就可以避免這個問題。
  • Effective batch size,不同的多卡工具對輸入的batch size的操作不一樣,要確定最后進模型的effective batch size才有意義。一般來說,多進程的batch size指的是每張卡的batch size。
  • Learning rate scale,學習率要根據effective batch size調整。
  • All-Reduce由于是多進程的,數據流各自獨立,為了防止同一個step多gpu的batch重疊,最好的的辦法是在每個進程里根據local_rank設置shard的數據,保證各個gpu采樣的數據不重疊。
  • 為了使用horovod,新建docker container時,要加—privileged,否則會瘋狂報warning,雖然沒影響,但是看著難受。
  • Pytorch的DP多卡要注意最后一個batch的batch size不能小于gpu的數量,否則會報錯,最保險的做法是drop_last,扔掉最后的batch。
  • 并不是所有情況下All-Reduce都比PS好,比如當卡間通信用的是NVLink的時候,在gpu數量不多的情況下,數據傳輸的時間不是瓶頸,All-Reduce的提升就幾乎沒有了。
  • DP和DDP有一個區別在于BatchNorm。
  • DDP封裝model后不能再改動model。
  • 待補充。。。

Reference

  1. Horovod的官方給的一些例子。
  2. Uber:如何用Horovod實現bert的單機多卡訓練
  3. Goodbye Horovod, Hello CollectiveAllReduce
  4. Horovod: fast and easy distributed deep learning in TensorFlow

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/532701.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/532701.shtml
英文地址,請注明出處:http://en.pswp.cn/news/532701.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【c語言數據結構筆記】1.2 數據結構

1.2數據結構 數據元素并獨立 結構實體關系 形式定義&#xff08;D&#xff0c;S&#xff09; 其中D是數據元素的有限集&#xff0c;S是D上關系的有限集 eg&#xff1a;12位數&#xff1a;132423451233 分成三組四位數 次序關系<a1,a2><a2,a3> 遵守次序關系 eg&…

使用Apex進行混合精度訓練

使用Apex進行混合精度訓練 轉自&#xff1a;https://fyubang.com/2019/08/26/fp16/ 你想獲得雙倍訓練速度的快感嗎&#xff1f; 你想讓你的顯存空間瞬間翻倍嗎&#xff1f; 如果我告訴你只需要三行代碼即可實現&#xff0c;你信不&#xff1f; 在這篇博客里&#xff0c;瓦礫…

【數據結構1.3筆記】研究內容

1.3研究內容 數據結構&#xff08;D&#xff0c;S&#xff09; {邏輯結構&#xff1a; {物理結構&#xff08;存儲結構&#xff09; {數據的運算 1.邏輯結構 1 集合&#xff1a;集合&#xff0c;沒有邏輯關系 2 線性結構 “一對一” 3樹形結構 層次關系 4圖形結構 練習&…

Linux下的LD_PRELOAD環境變量與庫打樁

Linux下的LD_PRELOAD環境變量與庫打樁 LD_PRELOAD是Linux系統的一個環境變量&#xff0c;它可以影響程序的運行時的鏈接&#xff08;Runtime linker&#xff09;&#xff0c;它允許你定義在程序運行前優先加載的動態鏈接庫&#xff0c;一方面&#xff0c;我們可以以此功能來使…

2019年藍橋杯第一題

第一題 標題&#xff1a;組隊&#xff08;本題總分&#xff1a;5 分&#xff09; 作為籃球隊教練&#xff0c;你需要從以下名單中選出 1 號位至 5 號位各一名球員&#xff0c; 組成球隊的首發陣容。 每位球員擔任 1 號位至 5 號位時的評分如下表所示。請你計算首發陣容 1 號位…

深度學習編譯:MLIR初步

深度學習編譯MLIR初步 深度模型的推理引擎 目前深度模型的推理引擎按照實現方式大體分為兩類&#xff1a;解釋型推理引擎和編譯型推理引擎。 解釋型推理引擎 一般包含模型解析器&#xff0c;模型解釋器&#xff0c;模型優化器。 模型解析器負責讀取和解析模型文件&#xff…

深入淺出LLVM

深入淺出LLVM 轉自&#xff1a;https://www.jianshu.com/p/1367dad95445 什么是LLVM&#xff1f; LLVM項目是模塊化、可重用的編譯器以及工具鏈技術的集合。 美國計算機協會 (ACM) 將其2012 年軟件系統獎項頒給了LLVM&#xff0c;之前曾經獲得此獎項的軟件和技術包括:Java、A…

藍橋杯真題訓練 2019.2題

2019第二題 標題&#xff1a;年號字串&#xff08;本題總分&#xff1a;5 分&#xff09; 小明用字母 A 對應數字 1&#xff0c;B 對應 2&#xff0c;以此類推&#xff0c;用 Z 對應 26。對于 27 以上的數字&#xff0c;小明用兩位或更長位的字符串來對應&#xff0c;例如 AA…

一分鐘系列:什么是虛擬內存?

一分鐘系列&#xff1a;什么是虛擬內存&#xff1f; 轉自&#xff1a;https://mp.weixin.qq.com/s/opMgZrXV-lfgOWrNUMKweg 注&#xff1a;一分鐘系列的篇幅都不長&#xff0c;適合吃飯蹲坑、地鐵公交上食用&#xff5e; 內存對于用戶來說就是一個字節數組&#xff0c;我們可…

藍橋杯真題訓練 2019.3題

標題&#xff1a;數列求值 &#xff08;本題總分&#xff1a;10 分&#xff09;### 給定數列 1, 1, 1, 3, 5, 9, 17, …&#xff0c;從第 4 項開始&#xff0c;每項都是前 3 項的和。求 第 20190324 項的最后 4 位數字。 【答案提交】 這是一道結果填空的題&#xff0c;你只需…

11-Kafka

1 Kafka Kafka是一個分布式流式數據平臺&#xff0c;它具有三個關鍵特性 Message System: Pub-Sub消息系統Availability & Reliability&#xff1a;以容錯及持久化的方式存儲數據記錄流Scalable & Real time 1.1 Kafka架構體系 Kafka系統中存在5個關鍵組件 Producer…

虛擬內存精粹

虛擬內存精粹 標題&#xff1a;虛擬內存精粹 作者&#xff1a;潘建鋒 原文&#xff1a;HTTPS://strikefreedom.top/memory-management–virtual-memory 導言 虛擬內存是當今計算機系統中最重要的抽象概念之一&#xff0c;它的提出是為了更加有效地管理內存并且降低內存出錯的概…

藍橋杯真題訓練 2019.4題

標題&#xff1a; 數的分解&#xff08;本題總分&#xff1a;10 分&#xff09; 【問題描述】 把 2019 分解成 3 個各不相同的正整數之和&#xff0c;并且要求每個正整數都不包 含數字 2 和 4&#xff0c;一共有多少種不同的分解方法&#xff1f; 注意交換 3 個整數的順序被視…

深度學習自動編譯和優化技術調研

深度學習自動編譯和優化技術調研 轉自&#xff1a;https://moqi.com.cn/blog/deeplearning/ 作者&#xff1a;墨奇科技全棧開發 在墨奇科技&#xff0c;我們需要將一些包含深度神經網絡&#xff08;DNN&#xff09;的 AI 算法移植到邊緣端的設備&#xff0c; 這些設備往往使用 …

三元組數據處理系統

include<stdio.h> include<stdlib.h> define OK 1 define ERROR 0 define OVERFLOW -2 typedef int Status; typedef float ElemType; typedef ElemType *Triplet; // 聲明Triplet為ElemType指針類型 //三元組的初始化 Status initTriplet(Triplet &T, E…

Copy-On-Write COW機制

Copy-On-Write COW機制 轉自&#xff1a;https://zhuanlan.zhihu.com/p/48147304 作者&#xff1a;Java3y 前言 只有光頭才能變強 在讀《Redis設計與實現》關于哈希表擴容的時候&#xff0c;發現這么一段話&#xff1a; 執行BGSAVE命令或者BGREWRITEAOF命令的過程中&#xff0c…

實驗報告:抽象數據類型的表現和實現

實驗報告&#xff1a;抽象數據類型的表現和實現 實驗內容 基本要求&#xff1a; 設計實現抽象數據類型“三元組”&#xff0c;要求動態分配內存。每個三元組由任意三個實數的序列構成&#xff0c;基本操作包括&#xff1a;創建一個三元組&#xff0c;取三元組的任意一個分量&…

關于x86、x86_64/x64、amd64和arm64/aarch64

關于x86、x86_64/x64、amd64和arm64/aarch64 轉自&#xff1a;https://www.jianshu.com/p/2753c45af9bf 為什么叫x86和x86_64和AMD64? 為什么大家叫x86為32位系統&#xff1f; 為什么軟件版本會注明 for amd64版本&#xff0c;不是intel64呢&#xff1f; x86是指intel的開…

實驗報告: 線性表的基本操作及應用

實驗報告&#xff1a; 線性表的基本操作及應用 實驗內容 基本要求&#xff1a; &#xff08;1&#xff09;實現單鏈表的創建&#xff1b;&#xff08;2&#xff09;實現單鏈表的插入&#xff1b;&#xff08;3&#xff09;實現單鏈表的刪除 &#xff08;4&#xff09;實現單鏈…

TVM:源碼編譯安裝

TVM&#xff1a;Linux源碼編譯安裝 筆者環境&#xff1a; OS&#xff1a;Ubuntu 18.04 CMake&#xff1a;3.10.2 gcc&#xff1a;7.5.0 cuda&#xff1a;11.1 編譯安裝過程總覽 本文將簡介 tvm 的編譯安裝過程&#xff0c;包含兩個步驟&#xff1a; 通過C代碼構建共享庫設置相…