Fujitsu Advent Calendar 2021 18日目の記事です。
以下の記事は限定共有で公開していた記事です。旧バージョンのHorovodで構築した時の方法のため、現行バージョンではそぐわない可能性が有ります。(構築を実施した環境が廃止されてしまっているため、再検証が難しくなってしまいました。)最新版のHorovodの環境での構築は今後随時記事を投稿予定です。
以前業務でUberが開発した分散学習用OSSHorovodを用いた分散学習環境を構築したところ、Dockerベースでの構築が一筋縄でいかなかったため、構築方法をまとめて公開します。
掲載の構築方法は2019年9月時点で最新バージョンのHorovod v0.18.1では未検証です。
構築した環境がCUDA9.0までの対応だったためHorovod v0.16.4で試した方法です。
社内Proxy環境上で公式README記載の方法で構築しても分散学習が動作しませんでした。
Horovod最新版での構築出来た or 出来なかった等の情報をコメントで頂けると幸いです。
RedHat系OSやWindowsでの構築情報なども大歓迎です。
本記事の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