2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

FUJITSUAdvent Calendar 2021

Day 18

Horovod in Dockerで(Proxy環境上に)分散学習環境を構築してみた

Last updated at Posted at 2021-12-20

Fujitsu Advent Calendar 2021 18日目の記事です。

:warning: 以下の記事は限定共有で公開していた記事です。旧バージョンのHorovodで構築した時の方法のため、現行バージョンではそぐわない可能性が有ります。(構築を実施した環境が廃止されてしまっているため、再検証が難しくなってしまいました。)最新版のHorovodの環境での構築は今後随時記事を投稿予定です。

以前業務でUberが開発した分散学習用OSSHorovodを用いた分散学習環境を構築したところ、Dockerベースでの構築が一筋縄でいかなかったため、構築方法をまとめて公開します。

:bangbang: 掲載の構築方法は2019年9月時点で最新バージョンのHorovod v0.18.1では未検証です。
:warning: 構築した環境がCUDA9.0までの対応だったためHorovod v0.16.4で試した方法です。
:rage: 社内Proxy環境上で公式README記載の方法で構築しても分散学習が動作しませんでした。
:pray: Horovod最新版での構築出来た or 出来なかった等の情報をコメントで頂けると幸いです。
:clap: RedHat系OSやWindowsでの構築情報なども大歓迎です。
:grin: 本記事のDockerコマンドは全てv1.13から導入された新しいコマンド体系を採用しています。

各マシンのスペック情報

今回の環境構築に用いた各GPUマシンのスペックは以下の通りです。今回はこの2台を同一ネットワーク上で接続し、利用します。

項目 メインマシン スレーブマシン
OS Ubuntu 16.04.5 LTS Ubuntu 16.04.5 LTS
CPU Xeon(R) W-2102
2.90GHz
Xeon(R) W-2102
2.90GHz
Memory 64GB 64GB
Disk (SSD) 256GB + (HD) 1TB (HD) 500GB
GPU NVIDIA
Quadro P4000
NVIDIA
GeForce GTX 1060
CUDA 9.0 9.0

前準備:メインマシン、スレーブマシンのセットアップ

メインマシン、スレーブマシン共にOSのインストールやNVIDAのビデオドライバーCUDAのセットアップを行います。NVIDAのドライバーは以下のサイトからダウンロード出来ます。今回は別の環境の影響でCUDA9.0をインストールしました。今後、CUDA9.0以降のバージョンでも構築を試みたいと思います。CUDAやNVIDA Tool Kitのインストール方法は他のページに譲るとします。

以下のサイトには便利なシェルの実装が紹介されています。

以降の行程はrootアカウントまたはdockerを実行できる環境で実施して下さい。

通信用ポートの利用状況の確認とrootログインの設定

この行程はメインマシン、スレーブマシン双方で実施します。後程分散学習環境を構築する時の準備です。

ポート利用状況の確認

本家のREADMEで12345ポートを用いて双方向通信をしていたので、12345ポートを本記事でも用います。念のため、ポート利用状況を以下のコマンドで確認し、使用済みの場合は別のポート番号を使用してください。

lsof -i:12345

ポートが利用されていない場合、何も表示されません。

/etc/ssh/sshd_configの編集

以下の様に編集します。

  • RootLoginを許可します。
PermitRootLogin yes

sshの再起動

以下のコマンドを実行します。

/etc/init.d/ssh restart
実行結果
# /etc/init.d/ssh restart
[ ok ] Restarting ssh (via systemctl): ssh.service.

Horovod用Dockerファイルのダウンロードとビルド

まずはメインマシンで構築作業を行います。メインマシンで構築したコンテナはtarファイル化し、後程スレーブマシンに転送します。

ダウンロード用ディレクトリを作成

mkdir horovod-docker

ソースファイルのダウンロード及びDockerファイルの取り出し

cd horovod-docker
wget https://github.com/horovod/horovod/archive/v0.16.4.tar.gz
tar xvf v0.16.4.tar.gz
cp horovod-0.16.4/Dockerfile ./
取り出したDockerfileの中身

FROM nvidia/cuda:9.0-devel-ubuntu16.04

# TensorFlow version is tightly coupled to CUDA and cuDNN so it should be selected carefully
ENV TENSORFLOW_VERSION=1.12.0
ENV PYTORCH_VERSION=1.1.0
ENV TORCHVISION_VERSION=0.2.2.post3
ENV CUDNN_VERSION=7.4.1.5-1+cuda9.0
ENV NCCL_VERSION=2.3.7-1+cuda9.0
ENV MXNET_VERSION=1.4.1

# Python 2.7 or 3.5 is supported by Ubuntu Xenial out of the box
ARG python=2.7
ENV PYTHON_VERSION=${python}

RUN apt-get update && apt-get install -y --allow-downgrades --allow-change-held-packages --no-install-recommends \
        build-essential \
        cmake \
        git \
        curl \
        vim \
        wget \
        ca-certificates \
        libcudnn7=${CUDNN_VERSION} \
        libnccl2=${NCCL_VERSION} \
        libnccl-dev=${NCCL_VERSION} \
        libjpeg-dev \
        libpng-dev \
        python${PYTHON_VERSION} \
        python${PYTHON_VERSION}-dev

RUN ln -s /usr/bin/python${PYTHON_VERSION} /usr/bin/python

RUN curl -O https://bootstrap.pypa.io/get-pip.py && \
    python get-pip.py && \
    rm get-pip.py

# Install TensorFlow, Keras, PyTorch and MXNet
RUN pip install 'numpy<1.15.0' tensorflow-gpu==${TENSORFLOW_VERSION} keras h5py torch==${PYTORCH_VERSION} torchvision==${TORCHVISION_VERSION} mxnet-cu90==${MXNET_VERSION}

# Install Open MPI
RUN mkdir /tmp/openmpi && \
    cd /tmp/openmpi && \
    wget https://www.open-mpi.org/software/ompi/v4.0/downloads/openmpi-4.0.0.tar.gz && \
    tar zxf openmpi-4.0.0.tar.gz && \
    cd openmpi-4.0.0 && \
    ./configure --enable-orterun-prefix-by-default && \
    make -j $(nproc) all && \
    make install && \
    ldconfig && \
    rm -rf /tmp/openmpi

# Install Horovod, temporarily using CUDA stubs
RUN ldconfig /usr/local/cuda-9.0/targets/x86_64-linux/lib/stubs && \
    HOROVOD_GPU_ALLREDUCE=NCCL HOROVOD_WITH_TENSORFLOW=1 HOROVOD_WITH_PYTORCH=1 HOROVOD_WITH_MXNET=1 pip install --no-cache-dir horovod && \
    ldconfig

# Install OpenSSH for MPI to communicate between containers
RUN apt-get install -y --no-install-recommends openssh-client openssh-server && \
    mkdir -p /var/run/sshd

# Allow OpenSSH to talk to containers without asking for confirmation
RUN cat /etc/ssh/ssh_config | grep -v StrictHostKeyChecking > /etc/ssh/ssh_config.new && \
    echo "    StrictHostKeyChecking no" >> /etc/ssh/ssh_config.new && \
    mv /etc/ssh/ssh_config.new /etc/ssh/ssh_config

# Download examples
RUN apt-get install -y --no-install-recommends subversion && \
    svn checkout https://github.com/horovod/horovod/trunk/examples && \
    rm -rf /examples/.svn

WORKDIR "/examples"

※ 最新版のHorovodのDockerfileをダウンロードするには以下のコマンドを実行します。

wget -O horovod-docker/Dockerfile https://raw.githubusercontent.com/uber/horovod/master/Dockerfile

Dockerfileの編集

以下のようにDockerfileを書き換えます。このまま実行すると最新版のHorovodがインストールされてしまい、イメージファイルビルド時に実行エラーが発生します。

# Install Horovod, temporarily using CUDA stubs
RUN ldconfig /usr/local/cuda-9.0/targets/x86_64-linux/lib/stubs && \
    HOROVOD_GPU_ALLREDUCE=NCCL HOROVOD_WITH_TENSORFLOW=1 HOROVOD_WITH_PYTORCH=1 
- HOROVOD_WITH_MXNET=1 pip install --no-cache-dir horovod && \
+ HOROVOD_WITH_MXNET=1 pip install --no-cache-dir horovod==0.16.4 && \
    ldconfig

examplesもv0.16.4対応の物をダウンロードするためにDockerファイルを書き換えます。また、Proxy環境上でSubversionのProxy設定を別途やる必要が無くなります。

# Download examples
- RUN apt-get install -y --no-install-recommends subversion && \
-    svn checkout https://github.com/horovod/horovod/trunk/examples && \
-    rm -rf /examples/.svn
-
- WORKDIR "/examples"
+ RUN cd / && \
+    git clone https://github.com/uber/horovod.git -b v0.16.4 && \
+    rm -rf /horovod/.git
+    
+ WORKDIR "/horovod/examples"

その他実行環境に応じてDokcerファイルに必要事項を追記してください。因みに引数として渡したProxy情報等はビルド後消えてしまいます。

Dockerファイルのビルド

Dockerファイルをビルドし、イメージファイルを作ります。記載のコマンドは社内Proxyを考慮したコマンドを記載しています。イメージタグ名(本記事ではhorovod-docker-2019-September)は任意の名前を付けてください。デフォルトでは最新版を表すlatestタグを記載している資料が多いです。今回は別バージョンとの共存の必要性から別名を付けています。

docker image build --force-rm --build-arg http_proxy=${http_proxy} --build-arg https_proxy=${https_proxy} -t horovod:horovod-docker-2019-September ./

イメージファイルの確認

# docker image ls | grep horovod-docker 
horovod                                        horovod-docker-2019-September   c8ed3f918584        9 minutes ago       7.79GB

Dockerコンテナの起動

以下のコマンドを実行します。古いネットの記事ではnvidia-dockerで実行と記載されている場合が有りますが、現在nvidia-dockerの実行は--runtime=nvidiaを渡す仕様に変わっています。

docker container run -it --rm -p 12345:12345 -d --runtime=nvidia --name horovod-docker horovod:horovod-docker-2019-September

Dockerファイル内にProxy情報を直接書き込むのはセキュリティー上好ましくありません。故に、Dockerファイルには直接書き込まず、両マシン上で、/etc/environmentに書き込んでおき、docker container run --volume(-vオプション)オプションで渡す方法も有ります。

docker container run -it --rm -p 12345:12345 -d --runtime=nvidia --volume=/etc/environment:/etc/environment --name horovod-docker horovod:horovod-docker-2019-September

起動確認

# docker container ls | grep horovod-docker 
4724b9e94a6b        horovod:horovod-docker-2019-September   "/bin/bash"              16 seconds ago      Up 15 seconds
                    horovod-docker

メインマシンだけでサンプルソースを実行

分散環境の構築前に、メインマシンだけでサンプルソースが動くか試します。

コンテナにログイン

docker container exec -it horovod-docker /bin/bash

サンプルソースの実行

mpirun --allow-run-as-root -np 1 -H localhost:1 python keras_mnist_advanced.py
実行結果
/horovod/examples# time mpirun --allow-run-as-root -np 1 -H localhost:1 python keras_mnist_advanced.py
Using TensorFlow backend. 
2019-09-03 07:20:46.807102: I tensorflow/core/platform/cpu_feature_guard.cc:141] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 AVX512F FMA
2019-09-03 07:20:47.020836: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1432] Found device 0 with properties:  
name: Quadro P4000 major: 6 minor: 1 memoryClockRate(GHz): 1.48
pciBusID: 0000:65:00.0
totalMemory: 7.93GiB freeMemory: 7.83GiB
2019-09-03 07:20:47.020868: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1511] Adding visible gpu devices: 0
2019-09-03 07:20:47.409998: I tensorflow/core/common_runtime/gpu/gpu_device.cc:982] Device interconnect StreamExecutor with strength 1 edge matrix: 
2019-09-03 07:20:47.410040: I tensorflow/core/common_runtime/gpu/gpu_device.cc:988]      0
2019-09-03 07:20:47.410049: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1001] 0:   N
2019-09-03 07:20:47.410260: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1115] Created TensorFlow device (/job:localhost/replica:0/task:0/device:GPU:0 with 7553 MB memory) -> physical GPU (device: 0, name: Quadro P4000, pci bus id: 0000:65:00.0, compute capability: 6.1)
x_train shape: (60000, 28, 28, 1) 
60000 train samples
10000 test samples
Epoch 1/24 
468/468 [==============================] - 18s 37ms/step - loss: 0.4606 - acc: 0.8546 - val_loss: 0.0462 - val_acc: 0.9849 
Unexpected end of /proc/mounts line `overlay / overlay rw,relatime,lowerdir=/var/lib/docker/overlay2/l/UL43O2ONW7PVU55RLVWO56PBSQ:/var/lib/docker/overlay2/l/D5I5BQJ5RWNQ6FOEOK4BIIMZCC:/var/lib/docker/overlay2/l/LRIO2ZYIYXXJ4LZBTBY5BKDG36:/var/lib/docker/overlay2/l/XFBQUFCZ7Y2WHPIKP47NKS6CNM:/var/lib/docker/overlay2/l/PZ5BRRWRC3GUEK5YHRIFJIH5ZO:/var/lib/docker/overlay2/l/VL232KYNXUQN3UIWEVTKXO462I:/var/lib/docker/overlay2/l/R5FK4HKNKG7NMBGFAQCEWEBLS3:/var/lib/docker/overlay2/l/XRL2S7KJWAVAD7HKLTR4WULHOJ:/var/lib/docker/overlay2/l/6TONSZZSENN7D'
Unexpected end of /proc/mounts line `J6ZDKP4O6MCCQ:/var/lib/docker/overlay2/l/LTSGLK6CENJ2256EOESRU7LEBU:/var/lib/docker/overlay2/l/6CRSESMM5NBGI7GFGH3PD33OZA:/var/lib/docker/overlay2/l/3WV2PP5HRFZQJ5QGSMDTIAFCEM:/var/lib/docker/overlay2/l/ULGPD6V4SZOHFTVZBI7K5ADWCY:/var/lib/docker/overlay2/l/LNMJHOYTMLCW4DBSCSGFJMUYPB:/var/lib/docker/overlay2/l/KUVWQZCTBIQPJCDH2UYZWPJOEL:/var/lib/docker/overlay2/l/LBPVPLDYLSA73BULYASYSAY6CN:/var/lib/docker/overlay2/l/SN7RTYBEOAVPDPK7X2RJZFYFS5:/var/lib/docker/overlay2/l/UCVZKXBTZXMANZHSKPD5JVUTW5:/var/lib/do'
Epoch 2/24 
468/468 [==============================] - 16s 34ms/step - loss: 0.1734 - acc: 0.9486 - val_loss: 0.0403 - val_acc: 0.9870 
Epoch 3/24 
468/468 [==============================] - 16s 34ms/step - loss: 0.1340 - acc: 0.9608 - val_loss: 0.0282 - val_acc: 0.9902 
Epoch 4/24 
468/468 [==============================] - 16s 35ms/step - loss: 0.1159 - acc: 0.9653 - val_loss: 0.0281 - val_acc: 0.9905 
Epoch 5/24 
468/468 [==============================] - 16s 34ms/step - loss: 0.1048 - acc: 0.9691 - val_loss: 0.0325 - val_acc: 0.9894 
 
Epoch 5: finished gradual learning rate warmup to 1.
Epoch 6/24 
468/468 [==============================] - 15s 33ms/step - loss: 0.0927 - acc: 0.9717 - val_loss: 0.0238 - val_acc: 0.9919 
Epoch 7/24 
468/468 [==============================] - 16s 34ms/step - loss: 0.0879 - acc: 0.9732 - val_loss: 0.0249 - val_acc: 0.9921 
Epoch 8/24 
468/468 [==============================] - 15s 33ms/step - loss: 0.0839 - acc: 0.9752 - val_loss: 0.0242 - val_acc: 0.9920 
Epoch 9/24 
468/468 [==============================] - 15s 33ms/step - loss: 0.0812 - acc: 0.9764 - val_loss: 0.0231 - val_acc: 0.9922 
Epoch 10/24 
468/468 [==============================] - 16s 34ms/step - loss: 0.0799 - acc: 0.9766 - val_loss: 0.0225 - val_acc: 0.9925 
Epoch 11/24 
468/468 [==============================] - 15s 33ms/step - loss: 0.0800 - acc: 0.9768 - val_loss: 0.0254 - val_acc: 0.9920 
Epoch 12/24 
468/468 [==============================] - 15s 33ms/step - loss: 0.0782 - acc: 0.9775 - val_loss: 0.0244 - val_acc: 0.9922 
Epoch 13/24 
468/468 [==============================] - 16s 34ms/step - loss: 0.0753 - acc: 0.9783 - val_loss: 0.0221 - val_acc: 0.9922 
Epoch 14/24 
468/468 [==============================] - 16s 33ms/step - loss: 0.0748 - acc: 0.9782 - val_loss: 0.0233 - val_acc: 0.9927 
Epoch 15/24 
468/468 [==============================] - 16s 33ms/step - loss: 0.0697 - acc: 0.9787 - val_loss: 0.0236 - val_acc: 0.9926 
Epoch 16/24 
468/468 [==============================] - 16s 34ms/step - loss: 0.0719 - acc: 0.9794 - val_loss: 0.0257 - val_acc: 0.9919 
Epoch 17/24 
468/468 [==============================] - 15s 33ms/step - loss: 0.0699 - acc: 0.9796 - val_loss: 0.0211 - val_acc: 0.9930 
Epoch 18/24 
468/468 [==============================] - 15s 33ms/step - loss: 0.0658 - acc: 0.9813 - val_loss: 0.0210 - val_acc: 0.9936 
Epoch 19/24 
468/468 [==============================] - 16s 34ms/step - loss: 0.0661 - acc: 0.9808 - val_loss: 0.0210 - val_acc: 0.9935 
Epoch 20/24 
468/468 [==============================] - 16s 33ms/step - loss: 0.0661 - acc: 0.9811 - val_loss: 0.0200 - val_acc: 0.9946 
Epoch 21/24 
468/468 [==============================] - 15s 33ms/step - loss: 0.0654 - acc: 0.9816 - val_loss: 0.0224 - val_acc: 0.9932 
Epoch 22/24 
468/468 [==============================] - 16s 34ms/step - loss: 0.0630 - acc: 0.9814 - val_loss: 0.0197 - val_acc: 0.9939 
Epoch 23/24 
468/468 [==============================] - 16s 33ms/step - loss: 0.0637 - acc: 0.9822 - val_loss: 0.0215 - val_acc: 0.9938 
Epoch 24/24 
468/468 [==============================] - 15s 33ms/step - loss: 0.0605 - acc: 0.9830 - val_loss: 0.0214 - val_acc: 0.9934 
Test loss: 0.0218829112259677 
Test accuracy: 0.9934

real    6m24.112s
user    6m0.316s
sys     0m19.704s

メインマシン単独での実行では、約6分30秒程の時間を要しました。いよいよ分散学習環境を構築して分散学習を実施します。

サンプル実行後、コンテナからログアウトします。

exit

分散学習環境の構築

メインマシン単独でサンプルソースを実行しました。続いて、分散学習環境を構築しhorovodによる分散学習を実現します。

前準備:コンテナイメージの保存及びスレーブマシンへの転送

スレーブマシン側でもコンテナイメージファイルが必要になります。0からイメージファイルを作るのではなく、メインマシン側でビルドしたイメージファイルをtarファイルにし、転送します。

コンテナイメージファイルのtarファイル化

以下のコマンドを実行します。

docker image save horovod:horovod-docker-2019-September > ./horovod-docker-2019-September.tar

双方向通信の設定

ssh認証でメインマシンとスレーブマシン間で双方向通信が出来るようにしておきます。

参考
【秘密鍵/公開鍵】コピペで出来る!鍵認証の設定方法

tarファイルをスレーブマシンに転送

以下のコマンドを実行します。

scp ./horovod-docker-2019-September.tar <USER>@<SLAVEMACHINE_IP>:/root/

コンテナイメージのロード @ スレーブマシーン

スレーブマシン側で以下のコマンドを実行

docker image load < horovod-docker-2019-September.tar

イメージファイルの確認 @ スレーブマシン

# docker image ls | grep horovod-docker 
horovod                                           horovod-docker-2019-September   c8ed3f918584        About an hour ago   7.79GB

スレーブマシンでコンテナにログイン

双方向通信、ポート開放を終えたら再度コンテナにログインします。
まず、スレーブマシン側でコンテナにログインし、スレーブマシン用のコマンドを実行します。

コンテナにログイン

docker container run -it --network=host --runtime=nvidia --volume=/mnt/share/ssh:/root/.ssh horovod:horovod-docker-2019-September bash -c "/usr/sbin/sshd -p 12345; sleep infinity"

これでスレーブ側のコンテナが実行状態のままになります。Proxy情報などの環境情報をオプションで渡す場合は以下のコマンドを実行します。

docker container run -it --network=host --runtime=nvidia --volume=/mnt/share/ssh:/root/.ssh --volume=/etc/environment:/etc/environment  horovod:horovod-docker-2019-September bash -c "/usr/sbin/sshd -p 12345; sleep infinity"

メインマシンでコンテナにログイン

メインマシンでもコンテナにログインします。メインマシンはもう少し設定が必要です。

docker container exec -it horovod-docker /bin/bash

hostfileの作成

ログイン後、作業ディレクトリ(/horovod/examples)直下にhostfileを作成します。以下の内容を記載し、作成します。

MAIN_IP slots=1
SLAVE_IP slots=1

MAIN_IPにはメインマシンのIPアドレス、SLAVE_IPにはスレーブマシンのIPアドレスを記載します。

NCCL関連の設定

  • configファイルの内容の確認
# cat /etc/nccl.conf
cat: /etc/nccl.conf: No such file or directory
  • 以下の内容を追記
echo "NCCL_DEBUG=INFO" >> /etc/nccl.conf
echo "NCCL_SOCKET_IFNAME=enp0s31f6" >> /etc/nccl.conf

File Openのマックスサイズの変更

echo "root soft nofile 2048" >> /etc/security/limits.conf 
echo "root hard nofile 2048" >> /etc/security/limits.conf

.bashrcに以下の内容を追加し有効化

vim ~/.bashrc

MPI_PATH=/usr/local/openmpi
PATH=/usr/local/openmpi/bin:/usr/local/nvidia/bin:/usr/local/cuda/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/root/bin:/usr/local/clang/bin
LD_LIBRARY_PATH=/usr/local/lib:/opt/clBLAS/lib64:/usr/local/nvidia/lib:/usr/local/nvidia/lib64:/usr/local/openmpi/lib
HTTPS_PROXY=<HTTPS_PROXY>:<PORT>
HTTP_PROXY=<HTTP_PROXY>:<PORT>
  • 下の2行は必要な場合のみ記載して下さい。
source ~/.bashrc

ソースの実行 @ メインマシン

 mpirun --allow-run-as-root -np 2 -hostfile ./hostfile  -mca plm_rsh_args "-p 12345"  --mca pml ob1 --mca btl tcp,self python keras_mnist_advanced.py

Infrastructure as Codeを目指して

本記事で扱った内容を反映したDockerfileの内容は以下の様になります。hostファイル作成部分の設定値についていは上述の行程を参考に修正してください。

Dockerfile

FROM nvidia/cuda:9.0-devel-ubuntu16.04

# TensorFlow version is tightly coupled to CUDA and cuDNN so it should be selected carefully
ENV TENSORFLOW_VERSION=1.12.0
ENV PYTORCH_VERSION=1.1.0
ENV TORCHVISION_VERSION=0.2.2.post3
ENV CUDNN_VERSION=7.4.1.5-1+cuda9.0
ENV NCCL_VERSION=2.3.7-1+cuda9.0
ENV MXNET_VERSION=1.4.1
# Add IP info
ENV MAIN_IP=
ENV SLAVE_IP=
# Add Proxy info if necessary
ENV HTTP_PROXY=
ENV HTTPS_PROXY=
ENV NO_PROXY=
ENV HTTP_PROXY2=
ENV HTTPS_PROXY2=

# Python 2.7 or 3.5 is supported by Ubuntu Xenial out of the box
ARG python=2.7
ENV PYTHON_VERSION=${python}

RUN apt-get update && apt-get install -y --allow-downgrades --allow-change-held-packages --no-install-recommends \
        build-essential \
        cmake \
        git \
        curl \
        vim \
        wget \
        ca-certificates \
        libcudnn7=${CUDNN_VERSION} \
        libnccl2=${NCCL_VERSION} \
        libnccl-dev=${NCCL_VERSION} \
        libjpeg-dev \
        libpng-dev \
        python${PYTHON_VERSION} \
        python${PYTHON_VERSION}-dev

RUN ln -s /usr/bin/python${PYTHON_VERSION} /usr/bin/python

RUN curl -O https://bootstrap.pypa.io/get-pip.py && \
    python get-pip.py && \
    rm get-pip.py

# Install TensorFlow, Keras, PyTorch and MXNet
RUN pip install 'numpy<1.15.0' tensorflow-gpu==${TENSORFLOW_VERSION} keras h5py torch==${PYTORCH_VERSION} torchvision==${TORCHVISION_VERSION} mxnet-cu90==${MXNET_VERSION}

# Install Open MPI
RUN mkdir /tmp/openmpi && \
    cd /tmp/openmpi && \
    wget https://www.open-mpi.org/software/ompi/v4.0/downloads/openmpi-4.0.0.tar.gz && \
    tar zxf openmpi-4.0.0.tar.gz && \
    cd openmpi-4.0.0 && \
    ./configure --enable-orterun-prefix-by-default && \
    make -j $(nproc) all && \
    make install && \
    ldconfig && \
    rm -rf /tmp/openmpi

# Install Horovod, temporarily using CUDA stubs
RUN ldconfig /usr/local/cuda-9.0/targets/x86_64-linux/lib/stubs && \
    HOROVOD_GPU_ALLREDUCE=NCCL HOROVOD_WITH_TENSORFLOW=1 HOROVOD_WITH_PYTORCH=1 HOROVOD_WITH_MXNET=1 pip install --no-cache-dir horovod && \
    ldconfig

# Install OpenSSH for MPI to communicate between containers
RUN apt-get install -y --no-install-recommends openssh-client openssh-server && \
    mkdir -p /var/run/sshd

# Allow OpenSSH to talk to containers without asking for confirmation
RUN cat /etc/ssh/ssh_config | grep -v StrictHostKeyChecking > /etc/ssh/ssh_config.new && \
    echo "    StrictHostKeyChecking no" >> /etc/ssh/ssh_config.new && \
    mv /etc/ssh/ssh_config.new /etc/ssh/ssh_config

# Download examples
RUN cd / && \
   git clone https://github.com/uber/horovod.git -b v0.16.4 && \
   rm -rf /horovod/.git

# Shell for single machine
RUN echo "#!/bin/bash" > /horovod/examples/exec_horovod_single_machine.sh && \
echo "mpirun --allow-run-as-root -np 1 -H localhost:1 python \$1" >> /horovod/examples/exec_horovod_single_machine.sh && \
chmod +x /horovod/examples/exec_horovod_single_machine.sh

# Shell for main machine
RUN echo "#!/bin/bash" > /horovod/examples/exec_horovod_main_machine.sh && \
echo "mpirun --allow-run-as-root -np 2 -hostfile ./hostfile  -mca plm_rsh_args \"-p 12345\" --mca pml ob1 --mca btl tcp,self python keras_mnist_advanced.py" >> /horovod/examples/exec_horovod_main_machine.sh && \
chmod +x /horovod/examples/exec_horovod_main_machine.sh

# hostfile for main machine
RUN echo ${MAIN_IP} " slots=1" > /horovod/examples/hostfile && \
echo ${SLAVE_IP} " slots=1" >> /horovod/examples/hostfile

# Add info into NCCL conf
RUN echo "NCCL_DEBUG=INFO" >> /etc/nccl.conf && \
echo "NCCL_SOCKET_IFNAME=enp0s31f6" >> /etc/nccl.conf

# Add info of Max File Open size
RUN echo "root soft nofile 2048" >> /etc/security/limits.conf && \
echo "root hard nofile 2048" >> /etc/security/limits.conf

# Add Open MPI info into bashrc
RUN echo "MPI_PATH=/usr/local/openmpi" >> ~/.bashrc && \
echo "PATH=/usr/local/openmpi/bin:/usr/local/nvidia/bin:/usr/local/cuda/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/root/bin:/usr/local/clang/bin" >> ~/.bashrc && \
echo "LD_LIBRARY_PATH=/usr/local/lib:/opt/clBLAS/lib64:/usr/local/nvidia/lib:/usr/local/nvidia/lib64:/usr/local/openmpi/lib" >> ~/.bashrc && \
echo "HTTPS_PROXY=${HTTPS_PROXY2}" >> ~/.bashrc && \
echo "HTTP_PROXY=${HTTP_PROXY2}" >> ~/.bashrc
 
WORKDIR "/horovod/examples"

コンテナログイン後に、

  • メインマシンのみで実行 : ./exec_horovod_single_machine.sh
  • 分散学習メインマシン : ./exec_horovod_main_machine.sh

Reference

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?