Horovod分佈式深度學習訓練框架

文|Seraph

01 | Horovod介紹

Horovod是一個分佈式訓練框架(針對TensorFlow/Keras/PyTorch/MXNet)。Horovod目標是使分佈式深度學習更快更簡單地使用。
由於Tensorflow集羣太不友好,業內也一直在嘗試新的集羣方案。 2017年Facebook發佈了《Accurate, large minibatch SGD: Training ImageNet in 1 hour 》驗證了大數據並行的高效性,同年百度發表了《Bringing HPC techniques to deep learning 》,驗證了全新的梯度同步和權值更新算法的可行性。受這兩篇論文的啓發,Uber開發了Horovod集羣方案。
Horovod幾個亮點:不依託於某個框架,使用MPI構建一套分佈式系統;Tensor Fusion可以在梯度傳遞過程中,將小的Tensor合併成大的Tensor,減少每一次的額外開銷。

02 | Horovod安裝

一、安裝Python和Tensorflow、Pytorch
  1. 這裏需要的是Python3,如僅有Python2,請使用以下命令安裝。
apt-get update
apt-get install python3-pip

由於我們基本只會使用python3,我們可以通過版本切換設置將python,pip默認爲python3,pip3.

  • 使用版本切換命令update-alternatives --install /usr/local/bin/python python /usr/bin/python3 150更新Python自動轉Python3的優先級爲150,數字越大,越優先。
  • update-alternatives --config python查看Python版本優先級。
  • 同樣的方法更新pip版本切換優先級update-alternatives --install /usr/bin/pip pip /usr/local/bin/pip3 150
  1. 安裝TensorFlow
pip install --upgrade pip
pip install tensorflow==1.14.0
pip install tensorflow-gpu==1.14.0
pip install torch==1.2.0 torchvision==0.4.0 -f https://download.pytorch.org/whl/torch_stable.html

Pytorch版本關係詳見PREVIOUS VERSIONS OF PYTORCH
如遇見pip下載慢的情況,可以使用國內鏡像源。
比如pip install -i https://pypi.tuna.tsinghua.edu.cn/simple --upgrade pip
常用國內鏡像源:

清華:https://pypi.tuna.tsinghua.edu.cn/simple

阿里雲:http://mirrors.aliyun.com/pypi/simple/

中國科技大學 https://pypi.mirrors.ustc.edu.cn/simple/

華中理工大學:http://pypi.hustunique.com/

山東理工大學:http://pypi.sdutlinux.org/ 

豆瓣:http://pypi.douban.com/simple/

note:新版ubuntu要求使用https源,要注意。
二、安裝CUDA
  1. 卸載CUDA10.1
  • 使用apt-get remove cuda*卸載10.1
  • 使用apt-get autoremove自動卸載未卸載乾淨的的包
  • 使用rm -rf cuda cuda-10.1刪除/usr/local目錄下的cuda及cuda-10.1文件夾
  1. 打開鏈接cuda-10.0-download-archive下載相應系統版本的CUDA,我們這裏使用runfile安裝。
    CUDA 10.0
    ubuntu系統可以使用wget下載,下載鏈接獲取方式:右鍵Download按鈕複製鏈接地址即可。記得補丁包也要下載。

  2. 下載完後,使用sh cuda_10.0.130_410.48_linux.run執行安裝包,不想看EULA,可以鍵盤輸入Ctrl+C停止,直接進入安裝選項。

Do you accept the previously read EULA?
accept/decline/quit: accept

Install NVIDIA Accelerated Graphics Driver for Linux-x86_64 410.48?
(y)es/(n)o/(q)uit: n

Install the CUDA 10.0 Toolkit?
(y)es/(n)o/(q)uit: y

Enter Toolkit Location
 [ default is /usr/local/cuda-10.0 ]: 
 
Do you want to install a symbolic link at /usr/local/cuda?
(y)es/(n)o/(q)uit: y

Install the CUDA 10.0 Samples?
(y)es/(n)o/(q)uit: y

Enter CUDA Samples Location
 [ default is /root ]: 

如你已經安裝NVIDIA Accelerated Graphics Driver,一定要向上面一樣選擇no,否則半天時間就過了。。。切記。。。

  1. 配置CUDA環境變量,打開~/.bashrc文件添加如下內容:
export CUDA_HOME=/usr/local/cuda
export PATH=$PATH:${CUDA_HOME}/bin
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:${CUDA_HOME}/lib64

然後保存,執行source ~/.bashrc

  1. 裝完成後使用nvcc --version查詢CUDA版本信息如下:
    nvcc
三、安裝cuDNN
  1. cudnn-archive下載相應的cuDNN版本,注意我們使用的是CUDA10.0,所以也要下載對應可用的版本。我這裏分別下載的是:
    cuDNN Runtime Library for Ubuntu16.04 (Deb)
    cuDNN Developer Library for Ubuntu16.04 (Deb)
  2. 執行dpkg -i libcudnn7_7.6.5.32-1+cuda10.0_amd64.deb
    dpkg -i libcudnn7-dev_7.6.5.32-1+cuda10.0_amd64.deb即可。
  3. 查詢已安裝的cuDNN版本:cat /usr/include/cudnn.h | grep CUDNN_MAJOR -A 2
    詳細步驟參考cuDNN install
四、安裝NCCL2
  1. 打開NVIDIA Collective Communications Library (NCCL) Download Page下載相應的版本文件,需要登陸,可以用社交賬號(微信)掃碼登陸。
  2. 我這裏下載的
    nccl-repo-ubuntu1604-2.5.6-ga-cuda10.0_1-1_amd64.deb
    nvidia-machine-learning-repo-ubuntu1604_1.0.0-1_amd64.deb
  3. 分別輸入如下命令
dpkg -i nccl-repo-ubuntu1604-2.5.6-ga-cuda10.0_1-1_amd64.deb
dpkg -i nvidia-machine-learning-repo-ubuntu1604_1.0.0-1_amd64.deb
apt update
apt install libnccl2=2.5.6-1+cuda10.0 libnccl-dev=2.5.6-1+cuda10.0

如提示

The public CUDA GPG key does not appear to be installed.
To install the key, run this command:
sudo apt-key add /var/nccl-repo-2.5.6-ga-cuda10.0/7fa2af80.pub

輸入apt-key add /var/nccl-repo-2.5.6-ga-cuda10.0/7fa2af80.pub即可。
詳細步驟參考Installing NCCL

五、OpenMPI安裝
  1. 因爲我們要演示的是TensorFlow訓練,安裝前,確認g++版本,必須是g++-4.8.5g++-4.9。否則執行如下命令apt-get install g++-4.8。(這部及其重要,否則,安裝Horovod會報錯,如果我們使用的是Pytorch,則安裝g++-4.9
  2. 新建一個文件目錄openmpi,將OpenMPI 4.0.0版本下載至該目錄。
    wget https://download.open-mpi.org/release/open-mpi/v4.0/openmpi-4.0.0.tar.gz
  3. 解壓文件:tar -zxvf openmpi-4.0.0.tar.gz
  4. 進入解壓後的文件目錄,配置:./configure (必須保證以及安裝了g++gcc) ,默認配置安裝路徑爲/usr/local/lib,也可以使用--prefix=路徑參數指定安裝路徑
  5. 編譯:make
  6. 安裝:make all install
  7. ~/.bashrc文件末尾加上:export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
    永久化環境變量:source ~/.bashrc
  8. 測試,進入example目錄,然後make,最後輸入mpirun --allow-run-as-root -oversubscribe -np 2 hello_c
    這裏需要解釋一下兩個參數:--allow-run-as-root-oversubscribe,一般不需要這兩個參數便能執行。
  • --allow-run-as-root:一般不建議root執行該命令,所以如果要在root下執行,需要加上這個參數;
  • -oversubscirbe:執行命令前,mpi會當前的CPU資源是否適合運行,如不管這個判斷,需要-oversubscirbe
六、安裝Horovod
  1. 執行pip install horovod即能完成horovod安裝。
    執行如果沒有安裝任何東西,顯示包都已安裝,請執行pip install --upgrade horovod即可。
    由於我們需要使用NCCL2中的算法庫,所以我們安裝horovod的時候需要添加如下參數:
    HOROVOD_GPU_ALLREDUCE=NCCL pip install --no-cache-dir horovod

    HOROVOD_GPU_ALLREDUCE=NCCL pip install --no-cache-dir --upgrade horovod
  2. 如果要額外安裝Pytorch版本,則運行下面命令:
    HOROVOD_WITH_TENSORFLOW=1 HOROVOD_WITH_PYTORCH=1 HOROVOD_GPU_ALLREDUCE=NCCL pip install --no-cache-dir horovod
  3. 測試example
  • 使用git工具將horovod庫clone下來。
  • 進入examples目錄,輸入命令horovodrun -np 1 -H localhost:1 python tensorflow_mnist.py便能運行tensorflow_mnist.py示例。
    這裏的localhost表示本機,輸入主機名也可以,當不同的機器,以號隔開,輸入不同的主機名與GPU數量即可。

03 | Horovod使用

一、單機單卡訓練腳本改爲多機多卡步驟
  1. 初始化
    hvd.init()
  2. 每個進程分別與指定的GPU綁定
config = tf.ConfigProto()
config.gpu_options.visible_device_list = str(hvd.local_rank())
  1. 根據GPU數量放大學習率
    opt = tf.train.AdagradOptimizer(learningrate * hvd.size())
    因爲BatchSize會根據GPU數量放大,所以學習率也應該放大。

  2. 封裝optimizer
    opt = hvd.DistributedOptimizer(opt)

  3. 廣播初始變量值給所有進程
    hooks = [hvd.BroadcastGlobalVariablesHook(0)]

  4. 設置只在worker 0上保持checkpoint
    hooks = [hvd.BroadcastGlobalVariablesHook(0)]

04 | 問題解決

  1. 更換Tensorflow版本後,horovodrun有問題,說沒有安裝MPI或Gloo。
    解決:按步驟全部重新安裝一遍。
    理解:不知道Horovod到tensorflow有什麼依賴關係。可能也和版本有關係,我嘗試了多遍。目前使用tensorflow 1.14.0版本/MPI 4.0.0版本安裝環境沒有問題。

  2. 當使用兩臺機器進行GPU訓練時,報如下錯誤:
    WARNING: Open MPI accepted a TCP connection from what appears to be a another Open MPI process but cannot find a corresponding process entry for that peer.
    解決:使用ifconfig查找通信使用的網卡,我這裏是eno1
    eno1
    然後給mpirun命令添加-mca btl_tcp_if_include eno1參數即能正常運行。
    我的執行命令如下:
    mpirun --allow-run-as-root -np 2 -H ubuntu90:1,sugon92:1 -bind-to none -map-by slot -mca plm_rsh_args "-p 31028" -x NCCL_DEBUG=INFO -x LD_LIBRARY_PATH -x PATH -mca pml ob1 -mca btl ^openib -mca btl_tcp_if_include eno1 python tensorflow_mnist.py
    因爲我的環境是docker,監聽端口不是22,所以還額外加了-mca plm_rsh_args "-p 31028"參數以表示ssh連接使用31028端口。
    當然你也可以嘗試下GitHub上Run Horovod with Open MPI文章Hangs due to non-routed network interfaces章節中提供方法。(雖然我沒試通。。。)

  3. 運行訓練腳本時提示Failed to find dynamic library: libnccl.so ( libnccl.so: cannot open shared object file: No such file or directory )等錯誤信息。
    解決:NCCL2未正確安裝。
    我在安裝NCCL2中執行apt update提示

E: The method driver /usr/lib/apt/methods/https could not be found.
N: Is the package apt-transport-https installed?

執行apt install apt-transport-https安裝apt-transport-https即能正確安裝。
安裝過程中,一定要注意提示信息,確保每步執行正確。由於安裝軟件時,都有依賴包,有些執行步驟不會自動安裝依賴包。

  1. 多機GPU訓練腳本提示:NCCL INFO NET/IB : Using interface ib0 for sideband communication
    解決:這裏表示的意思是使用ib0接口進行通信,這裏的ib0指得是infiniband網卡,用於高性能計算的一種通信網卡。默認設置爲NCCL默認設置infiniband進行通信,但如果雙機的infibiband不能通信,則會導致多機並行計算失敗。我們可以將NCCL使用的網卡設置爲我們正常使用的以太網卡即能成功運行,給mpirun命令添加如下參數:
    -x NCCL_SOCKET_IFNAME=eno1

  2. 多機GPU訓練腳本提示:NCCL INFO NET/Plugin : No plugin found (libnccl-net.so), using internal implementation
    解決:我理解是能接入外部的網絡通信實現包,如果沒有使用內部實現。例如外部包AWS OFI NCCL。所以這個提示是不影響正常運行的。

  3. 運行某些腳本時,提示:failed to allocate 3.21G (3452305408 bytes) from device: CUDA_ERROR_OUT_OF_MEMORY: out of memory
    解決:提示明顯時是顯存申請失敗,使用nvidia-smi命令查看N卡的信息,關注固有顯存以及使用情況。
    嘗試使用config = tf.ConfigProto()控制GPU的顯存使用。

    config.gpu_options.allow_growth = True   #設置成動態申請
    config.gpu_options.per_process_gpu_memory_fraction = 0.3   #設置成最大使用多少比例的顯存

嘗試無效果的話,使用添加代碼os.environ["CUDA_VISIBLE_DEVICES"] = "1"來選擇哪個GPU,也許有的GPU顯存被佔用,亦不能釋放。可以指定一個完全空閒的GPU進行訓練。
或者可以在執行命令前加CUDA_VISIBLE_DEVICES=1來指定GPU。但這種對多機情況不適用,其他機器不能同步該參數。當然也可以將這個寫進~/.bashrc中,便可以了。
當整個卡都無法滿足顯存需求時,可以修改batch_size以適當減少顯存需求。

  1. 多機GPU訓練腳本提示:misc/ibvwrap.cc:212 NCCL WARN Call to ibv_open_device failed
    解決:IB卡的infiniband設備未找到。當我們利用MPI在IB卡做通信時,可以使用兩種協議進行通信,一種是TCP,一種是infiniband協議(RDMA)。這裏錯誤是指的是未找到infiniband協議設備,使用ibv_devices指令查看當前機器的IB卡設備。
    因爲我是在容器內使用的,所以在創建容器時,需要加上--cap-add=IPC_LOCK --device=/dev/infiniband參數,具體見問題19

  2. 代碼錯誤提示:RuntimeError: Global step should be created to use StepCounterHook.
    解決:使用global_step = tf.train.get_or_create_global_step()生成global_step。

  3. 代碼錯誤提示:RuntimeError: Run called even after should_stop requested.
    解決:

  4. 使用docker容器,訓練代碼時,提示Read -1, expected 7329, errno = 1
    解決:官方文檔說明這是因爲權限問題,但可以忽略,不影響訓練執行。

  5. 使用docker容器執行多機GPU訓練,提示:A process or daemon was unable to complete a TCP connection to another process: Local host: fe31b0df9223 Remote host: 0f5f1d90a597 This is usually caused by a firewall on the remote host. Please check that any firewall (e.g., iptables) has been disabled and try again.
    解決:有可能時網卡問題,新建Docker容器時,默認時以Bridge的模式。指定爲Host模式即可。
    在docker run運行命令後面加上--network host參數。

  6. 多卡訓練時,出現如下錯誤:
    tensorflow.python.framework.errors_impl.FailedPreconditionError: Mismatched ALLREDUCE CPU/GPU device selection: One rank specified device CPU, but another rank specified device GPU. [[node DistributedAdamOptimizer_Allreduce/HorovodAllreduce_gradients_dense_1_BiasAdd_grad_tuple_control_dependency_1_0 (defined at <string>:80) ]]
    解決:卸載horovod,使用HOROVOD_GPU_ALLREDUCE=NCCL pip install --no-cache-dir horovod安裝。

  7. 多卡訓練時,出現如下錯誤:
    NCCL INFO Call to connect returned Connection refused, retrying
    解決:新建一個docker環境,重新搭整個環境。(我試過重新安裝cuda/cuDNN/NCCL等,但是沒有效果)。

  8. 多機訓練時,出現如下錯誤:

hvd1:60423:60555 [1] NCCL INFO NET/IB : No device found.
hvd1:60422:60554 [0] NCCL INFO NET/Socket : Using [0]ib0:192.168.1.200<0>
hvd1:60423:60555 [1] NCCL INFO NET/Socket : Using [0]ib0:192.168.1.200<0>
hvd:27943:28074 [1] NCCL INFO Setting affinity for GPU 1 to ff00ff00
hvd1:60422:60554 [0] NCCL INFO Setting affinity for GPU 0 to ff00ff
hvd1:60423:60555 [1] NCCL INFO Setting affinity for GPU 1 to ff00ff00

hvd1:60422:60554 [0] include/socket.h:397 NCCL WARN Connect to 192.168.1.50<49823> failed : No route to host
hvd1:60422:60554 [0] NCCL INFO bootstrap.cc:95 -> 2
hvd1:60422:60554 [0] NCCL INFO bootstrap.cc:308 -> 2
hvd1:60422:60554 [0] NCCL INFO init.cc:443 -> 2
hvd1:60422:60554 [0] NCCL INFO init.cc:732 -> 2
hvd1:60422:60554 [0] NCCL INFO init.cc:771 -> 2
hvd1:60422:60554 [0] NCCL INFO init.cc:782 -> 2

解決:添加mpirun運行指令-x NCCL_SOCKET_IFNAME=eno1參數,由於我們IB卡沒有通,這裏告訴NCCL指定eno1進行通信。如果你的IB卡的RDMA通信正常,NCCL會默認使用infiniband協議進行通信。

  1. 安裝CUDA時, 出錯:gpgkeys: protocol https’ not supported
    解決:apt install gnupg-curl

  2. 如安裝CUDA後,使用nvcc命令顯示:nvcc: command not found
    解決:配置CUDA環境變量。

export LD_LIBRARY_PATH=/usr/local/cuda/lib:$LD_LIBRARY_PATH
export PATH=$PATH:/usr/local/cuda/bin
  1. 多機訓練時,出錯:Unable to load libnccl-net.so : libnccl-net.so: cannot open shared object file: No such file or directory
    解決:提示其實不影響訓練進行,NCCL可提供給第三方開發庫,但不是必須。如沒有這個庫,會自動選擇內部實現進行通信。詳細情況見Issues 162

  2. docker容器下,Pytorch多卡訓練報錯:ERROR: Unexpected bus error encountered in worker. This might be caused by insufficient shared memory (shm).
    解決:新建容器時,添加--ipc=host參數。

  3. docker容器下,欲使用IB卡的RMDA,出錯:

A process failed to create a queue pair. This usually means either
the device has run out of queue pairs (too many connections) or
there are insufficient resources available to allocate a queue pair
(out of memory). The latter can happen if either 1) insufficient
memory is available, or 2) no more physical memory can be registered
with the device.

For more information on memory registration see the Open MPI FAQs at:
http://www.open-mpi.org/faq/?category=openfabrics#ib-locked-pages

Local host:             laser045
Local device:           qib0
Queue pair type:        Reliable connected (RC)

解決:首先做分佈式GPU訓練,推薦使用nvidia-docker,這個命令起始就是基於英偉達的顯卡配置信息上給原裝的docker添加了一些配置參數。
解決本問題在於新建容器時命令如下:nvidia-docker run -it --network=host -v /mnt/share/ssh:/root/.ssh --cap-add=IPC_LOCK --device=/dev/infiniband horovod:latest
關鍵參數爲:--cap-add=IPC_LOCK --device=/dev/infiniband,表示關聯主機上的IB卡設備。

  1. RuntimeError: Global step should be created to use StepCounterHook.
    解決:使用global_step = tf.train.get_or_create_global_step()生成Global_step。

  2. RuntimeError: Run called even after should_stop requested.
    解決:

05 | 解決方案

  1. 多機GPU運行
    答:將SSH連接設置成無需密碼就能訪問的模式即可。
    同時注意可以在/ect/hosts文件中添加主機名和IP地址的映射關係。
    參考 SSH login without password

  2. 22端口ssh連接運行
    答:不能直接使用horovodrun命令,需要使用mpirun添加相關端口參數。
    參考 Run Horovod with Open MPI文章中的Custom SSH ports章節。
    只能找到統一端口的配置方式,未找到不同機不同監聽端口配置方式。

06 | 其他

  1. CUDA/MPI等環境變量參考
    PATH
    /usr/local/mpi/bin:/usr/local/nvidia/bin:/usr/local/cuda/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/tensorrt/bin
    LD_LIBRARY_PATH /usr/local/cuda/extras/CUPTI/lib64:/usr/local/cuda/compat/lib:/usr/local/nvidia/lib:/usr/local/nvidia/lib64:/usr/local/lib/tensorflow
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章