HorovodRunner: Horovodによる分散ディープラーニング

重要

Horovod と HorovodRunner は非推奨となり、Databricks Runtime 16.0 ML 以降ではプリインストールされません。 分散ディープラーニングの場合、Databricks では、PyTorch を使用した分散トレーニングにはTorchDistributorを使用するか、TensorFlow を使用した分散トレーニングにはtf.distribute.Strategy API を使用することをお勧めします。

HorovodRunner を使用して機械学習モデルの分散トレーニングを実行し、Databricks で Spark ジョブとして Horovod トレーニング ジョブを起動する方法について説明します。

HorovodRunnerとは?

HorovodRunner は、 Horovod フレームワークを使用して Databricks で分散ディープラーニング ワークロードを実行するための一般的な API です。 Horovod を Spark の バリア モードと統合することで、Databricks は Spark で長時間実行されるディープラーニング トレーニング ジョブの安定性を高めることができます。 HorovodRunner は、Horovod フックを使用したディープラーニングトレーニングコードを含む Python メソッドを採用しています。 HorovodRunner は、ドライバーでメソッドをピックし、Spark ワーカーに配布します。 Horovod MPI ジョブは、バリア実行モードを使用して Spark ジョブとして埋め込まれます。 最初のエグゼキューターは、 BarrierTaskContext を使用してすべてのタスク エグゼキューターの IP アドレスを収集し、 mpirunを使用して Horovod ジョブをトリガーします。 各 Python MPI プロセスは、ピクルスされたユーザプログラムをロードし、逆シリアル化して実行します。

HorovodRunner

HorovodRunnerを使った分散トレーニング

HorovodRunner を使用すると、Horovod トレーニング ジョブを Spark ジョブとして起動できます。 HorovodRunner API は、表に示されているメソッドをサポートしています。 詳細については、 HorovodRunner API のドキュメントを参照してください。

メソッドとシグネチャー

説明

init(self, np)

HorovodRunnerのインスタンスを作成します。

run(self, main, **kwargs)

main(**kwargs)を呼び出す Horovod トレーニング ジョブを実行します。main 関数とキーワード引数は、cloudpickle を使用してシリアル化され、クラスターワーカーに配布されます。

HorovodRunner を使用して分散トレーニングプログラムを開発する一般的なアプローチは次のとおりです。

  1. ノード数で初期化された HorovodRunner インスタンスを作成します。

  2. Horovod の使用方法で説明されている方法に従って Horovod トレーニングメソッドを定義し、メソッド内にインポートステートメントを追加してください。

  3. トレーニングメソッドを HorovodRunner インスタンスに渡します。

例:

hr = HorovodRunner(np=2)

def train():
  import tensorflow as tf
  hvd.init()

hr.run(train)

n サブプロセスのみを使用してドライバーで HorovodRunner を実行するには、 hr = HorovodRunner(np=-n)を使用します。たとえば、ドライバー ノードに 4 つの GPU がある場合は、最大 4 n を選択できます。パラメーター npの詳細については、 HorovodRunner API のドキュメントを参照してください。 サブプロセスごとに 1 つの GPU をピン留めする方法の詳細については、 Horovod 使用ガイドを参照してください。

一般的なエラーは、TensorFlow オブジェクトが見つからないか、ピッキングできないことです。 これは、ライブラリのインポートステートメントが他のエグゼキューターに配布されていない場合に発生します。 この問題を回避するには、すべての import ステートメント ( import tensorflow as tf など) を Horovod トレーニング メソッドの先頭と、Horovod トレーニング メソッドで呼び出される他のユーザー定義関数の両方に含めます。

Horovod Timelineを使ってHorovodトレーニングを記録する

Horovodには、 Horovodタイムラインと呼ばれるアクティビティのタイムラインを記録する機能があります。

重要

Horovod タイムラインはパフォーマンスに大きな影響を与えます。 Inception3 のスループットは、Horovod タイムラインが有効になっている場合、~40% 減少する可能性があります。 HorovodRunner ジョブを高速化するには、Horovod タイムラインを使用しないでください。

トレーニングの進行中は、 Horovod タイムラインを表示することはできません。

Horovod タイムラインを記録するには、 HOROVOD_TIMELINE 環境変数をタイムライン ファイルを保存する場所に設定します。 Databricks では、タイムライン ファイルを簡単に取得できるように、共有ストレージ上の場所を使用することをお勧めします。 たとえば、次のように DBFS ローカル ファイル APIs を使用できます。

timeline_dir = "/dbfs/ml/horovod-timeline/%s" % uuid.uuid4()
os.makedirs(timeline_dir)
os.environ['HOROVOD_TIMELINE'] = timeline_dir + "/horovod_timeline.json"
hr = HorovodRunner(np=4)
hr.run(run_training_horovod, params=params)

次に、トレーニング関数の先頭と末尾にタイムライン固有のコードを追加します。 次のノートブックの例には、トレーニングの進行状況を表示するための回避策として使用できるコード例が含まれています。

Horovod タイムラインのサンプルノートブック

ノートブックを新しいタブで開く

タイムライン ファイルをダウンロードするには、 Databricks CLIを使用し、Chrome ブラウザーのchrome://tracing機能を使用して表示します。 例えば:

Horovod タイムライン

開発ワークフロー

これらは、単一ノードのディープラーニングコードを分散トレーニングに移行する際の一般的な手順です。 このセクションの「 例: HorovodRunner を使用した分散ディープラーニングへの移行 」では、これらのステップについて説明します。

  1. 単一ノード コードを準備します。 単一ノードのコードを TensorFlow、Keras、または PyTorch で準備してテストします。

  2. HorovodRunnerへの移行: 「Horovod の使用法」の指示に従って、 Horovod を使用してコードを移行し、ドライバーでテストします。

    1. hvd.init() を追加して Horovodを初期化します。

    2. このプロセスで使用するサーバー GPU を config.gpu_options.visible_device_listを使用してピン留めします。 プロセスごとに 1 つの GPU の一般的なセットアップでは、これをローカル ランクに設定できます。 その場合、サーバー上の最初のプロセスには最初の GPU が割り当てられ、2 番目のプロセスには 2 番目の GPU が割り当てられます。

    3. データセットのシャードを含めます。 このデータセット演算子は、各ワーカーが一意のサブセットを読み取ることができるため、分散トレーニングを実行するときに非常に役立ちます。

    4. ワーカー数で学習率をスケーリングします。 同期分散トレーニングの有効なバッチ サイズは、ワーカーの数によってスケーリングされます。 学習率を上げると、バッチサイズの増加が補われます。

    5. オプティマイザを hvd.DistributedOptimizerでラップします。 分散オプティマイザは、勾配の計算を元のオプティマイザに委任し、allreduce または allgatherを使用して勾配を平均化してから、平均化された勾配を適用します。

    6. hvd.BroadcastGlobalVariablesHook(0) を追加して、初期変数の状態をランク0から他のすべてのプロセスにブロードキャストします。これは、トレーニングがランダムな重みで開始された場合、またはチェックポイントから復元された場合に、すべてのワーカーの一貫した初期化を保証するために必要です。 または、 MonitoredTrainingSessionを使用していない場合は、グローバル変数が初期化された後に hvd.broadcast_global_variables 操作を実行できます。

    7. ワーカー 0 にのみチェックポイントを保存するようにコードを変更して、他のワーカーがチェックポイントを破損しないようにします。

  3. HorovodRunnerへの移行: HorovodRunner は、Python 関数を呼び出すことによって Horovod トレーニングジョブを実行します。 メインのトレーニング手順を 1 つの Python 関数にラップする必要があります。 その後、HorovodRunner をローカル モードと分散モードでテストできます。

ディープラーニングライブラリを更新する

この記事には、Databricks が使用しない用語である スレーブという用語への参照が含まれています。 この用語がソフトウェアから削除されると、この記事から削除します。

TensorFlow、Keras、または PyTorch をアップグレードまたはダウングレードする場合は、Horovod を再インストールして、新しくインストールされたライブラリに対してコンパイルする必要があります。 たとえば、TensorFlow をアップグレードする場合、Databricks では、TensorFlow のインストール手順の initスクリプトを使用し、次の TensorFlow 固有の Horovod インストール コードを末尾に追加することをお勧めします。 PyTorch やその他のライブラリのアップグレードやダウングレードなど、さまざまな組み合わせを操作するには、 Horovod のインストール手順 を参照してください。

add-apt-repository -y ppa:ubuntu-toolchain-r/test
apt update
# Using the same compiler that TensorFlow was built to compile Horovod
apt install g++-7 -y
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-7 60 --slave /usr/bin/g++ g++ /usr/bin/g++-7

HOROVOD_GPU_ALLREDUCE=NCCL HOROVOD_CUDA_HOME=/usr/local/cuda pip install horovod==0.18.1 --force-reinstall --no-deps --no-cache-dir

例: HorovodRunnerを使用した分散ディープラーニングへの移行

次の例では、 MNIST データセットに基づいて、単一ノードのディープラーニング プログラムを HorovodRunner を使用して分散ディープラーニングに移行する方法を示します。

制限

  • ワークスペース ファイルを操作する場合、 np が 1 より大きく設定され、ノートブックが他の相対ファイルからインポートされる場合、HorovodRunner は機能しません。 HorovodRunnerの代わりに .spark を使用するHorovod ことを検討してください。

  • 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のようなエラーが発生した場合は、クラスター内のノード間のネットワーク通信に問題があることを示しています。 このエラーを解決するには、トレーニング コードに次のスニペットを追加して、プライマリ ネットワーク インターフェースを使用します。

import os
os.environ["OMPI_MCA_btl_tcp_if_include"]="eth0"
os.environ["NCCL_SOCKET_IFNAME"]="eth0"