分散 GPU トレーニング
#
基本的なコンセプトこのガイドの読者は data parallelism、distributed data parallelism、model parallelism などの分散 GPU トレーニングに対する基本的なコンセプトを理解していると想定しています。
info
どの parallelism を使うべきか判断できない場合: 90% 以上の場合で Distributed Data Parallelism が使われます。
#
MPI (Message Passing Interface)Azure ML は各ノードで与えられたプロセッサー数の MPI ジョブを提供します。利用者は、process_count_per_node
が 1 に設定されている場合 (デフォルト) は per-node-launcher、デバイス/ GPU の数に等しい場合は per-process-launcher を使って分散トレーニングを実行することができます。Azure ML は裏側で完全な MPI 実行コマンド (mpirun
) を構築して処理します。
note
Azure ML は今のところユーザーからの完全なmpirun
のような head-node-launcher コマンドや DeepSpeed ランチャーを受け取ることができません。この機能は将来のリリースで追加される可能性があります。
caution
Azure ML の MPI ジョブを使うために、ベースとなる Docker イメージには MPI ライブラリがインストールされている必要があります。Open MPI はすべての AzureML GPU ベースイメージに含まれています。もしもカスタム Docker イメージを使う場合にはユーザーが責任を持って MPI ライブラリをインストールする必要があります。Open MPI が推奨ですが、Intel MPI などの他の MPI 実装を使うこともできます。Azure ML はこの他にも人気のあるフレームワークのキュレーションされた環境も提供します。
MPIを使って分散トレーニングを実行するには下記のステップに従います:
- Azure ML 環境、好みのディープラーニングフレームワーク、MPI を使います。AzureML は人気のあるフレームワーク環境を提供します。キュレーションされた環境
MpiConfiguration
を定義して望ましいprocess_count_per_node
とnode_count
を設定します。per-process-launch の場合はprocess_count_per_node
はノードあたりのGPU数と同じにする必要があります。もしもユーザースクリプトがノードあたりの実行プロセス数に責任を持つ場合、per-node-launch は 1 (デフォルト値)に設定します。MpiConfiguration
オブジェクトをScriptRunConfig
のパラメータであるdistributed_job_config
に渡します。
#
Horovodもしもユーザーが選択したディープラーニングフレームワークと共に Horovod を分散トレーニングに使う場合、MPI ジョブ構成を使うことで Azure ML 上で分散トレーニングを実行することができます。
下記が行われていることを確認してください:
- トレーニングコードが正しく Horovod で実装されていること。
- コードを実行する Azure ML 環境に Horovod と MPI を含んでいること。PyTorch と TensorFlow のキュレーションされた GPU 環境には Horovod とその設定情報が付属しています。
- 任意の分散を指定した
MpiConfiguration
が作成されていること。
#
例#
DeepSpeedAzure ML 上で DeepSpeed を使って分散トレーニングを行うには、DeepSpeed のカスタムランチャーを使わないでください。代わりに、MPI を使ってトレーニングジョブを実行してください。
下記が行われていることを確認してください:
- ジョブを実行する Azure ML 環境が DeepSpeed とその依存関係、Open MPI、mpi4py を含んでいること。
- 任意の分散を指定した
MpiConfiguration
が作成されていること。
#
例#
Open MPI の環境変数MPI ジョブを Open MPI イメージで実行する時、実行されたそれぞれのプロセスに対して下記の環境変数が作成されます。
- OMPI_COMM_WORLD_RANK - プロセスのランク
- OMPI_COMM_WORLD_SIZE - ワールドのサイズ (プロセスが含まれるMPI_COMM_WORLD内に存在するプロセス数)
- AZ_BATCH_MASTER_NODE - マスターアドレスとポート、MASTER_ADDR:MASTER_PORT
- OMPI_COMM_WORLD_LOCAL_RANK - ノード上でのプロセスのローカルランク
- OMPI_COMM_WORLD_LOCAL_SIZE - ノード上のプロセス数
caution
名前にもかかわらず、OMPI_COMM_WORLD_NODE_RANK は NODE_RANK と対応していません。per-node-launcher を使うには、単にprocess_count_per_node=1
を設定して、OMPI_COMM_WORLD_RANK を NODE_RANKとして使います。
#
PyTorchAzure ML は PyTorch の分散トレーニング機能 (torch.distributed
) を使った分散ジョブ実行もサポートしています。
torch.nn.parallel.DistributedDataParallel 対 torch.nn.DataParallel / torch.multiprocessing の比較
シングルノード、マルチノード分散トレーニングどちらの場合も、並列処理については PyTorch の公式ガイドでは DistributedDataParallel (DDP) を DataParallel よりも優先して使っています。さらに、PyTorch は multiprocessing パッケージよりも DistributedDataParallel を推奨しています。よって、Azure ML のドキュメントとサンプルも DistributedDataParallel に注目します。
#
プロセスグループ初期化分散トレーニングのバックボーンは、互いの存在を知っていてコミュニケーションを取り合うプロセスのグループによって成り立っています。PyTorch の場合、そのプロセスのグループは すべての分散プロセス の中で torch.distributed.init_process_group を呼ぶことで作成されます。
最も一般的に使われるコミュニケーションバックエンドは mpi、nccl、gloo です。GPU ベースのトレーニングでは、パフォーマンスの観点から nccl が強く推奨されており、可能な場合はこれを使用すべきです。
init_method
は、コミュニケーションバックエンドを使ってプロセスグループを確認するだけではなく、各プロセスが互いを見つける方法を指定したり、初期化を行います。デフォルトでは、init_method
が指定されていない場合、PyTorchは環境変数の初期化メソッド (env://
) を使います。Azure ML 上で分散 PyTorch を実行するためのトレーニングコードでも、この初期化メソッドを使うことが推奨されています。環境変数の初期化のために PyTorch は下記の環境変数を探します:
- MASTER_ADDR - ランク 0 のプロセスをホストするマシンの IP アドレス。
- MASTER_PORT - ランク 0 のプロセスをホストするマシンのフリーポート。
- WORLD_SIZE - プロセスの合計数。この数は分散トレーニングで使用されるデバイス (GPU) の数と同じにすべきです。
- RANK - 現在のプロセスのグローバルランク。考えられる値は 0 からワールドサイズ -1 までです。
プロセスグループの初期化に関するより詳細な情報は次のリンク先を参照してください。 PyTorch documentation
これより先に記載する多くのアプリケーションが同じく下記の環境変数を必要とします:
- LOCAL_RANK - ノード上のプロセスのローカル (相対) ランク。考えられる値は 0 からノード上のプロセス数 -1 までです。データ準備のような様々なオペレーションがノードごとに 1 回ずつ実行されるため、この情報は有用です。 --- 通常 local_rank = 0 を使用します。
- NODE_RANK - マルチノードトレーニングで使われるノードのランクです。考えられる値は 0 からノード数の合計 -1 までです。
#
実行オプションAzure ML の PyTorch ジョブは分散トレーニングを実行する 2 種類のオプションをサポートしています。
- Per-process-launcher: システムはユーザーのために、プロセスグループをセットアップする関連情報 (e.g. 環境変数) と共に、すべての分散プロセスを実行します。
- Per-node-launcher: ユーザーは Azure ML に対して、各ノードでの実行を受け取るユーティリティランチャーを与えます。このユーティリティランチャーは与えられたノード上での各プロセスの実行を管理します。各ローカルノードでは、ユーティリティランチャーによって RANK と LOCAL_RANK が設定されます。torch.distributed.launch ユーティリティと PyTorch Lightning の両方がこちらに該当します。
これらの実行オプションの間に根本的な差はありません。ほとんどユーザーの好み、もしくは Lightning や Hugging Face などのよく見る PyTorch フレームワーク・ライブラリのしきたりによるものです。
以下のシナリオは、それぞれの実行オプションにおける Azure ML PyTorch ジョブの構成方法のより詳細な情報に踏み込みます。
#
DistributedDataParallel (per-process-launch)Azure ML はtorch.distributed.launch
のようなランチャーユーティリティを使うことなくプロセスを実行することをサポートしています。
分散 PyTorch ジョブを実行するためには、下記のことをするだけです:
- トレーニングスクリプトと引数を指定します。
PyTorchConfiguration
を作成し、node_count
とprocess_count
を指定します。process_count
は実行したいジョブにおける合計プロセス数と一致します。この値は一般的にノードあたりの GPU 数 x ノード数
と同じです。process_count
が指定されない場合、Azure ML はデフォルトで各ノードにつき 1 プロセスずつ実行します。
Azure ML はプロセスレベルで RANK と LOCAL_RANK の環境変数を設定した上で、各ノードで MASTER_ADDR、MASTER_PORT、WORLD_SIZE、NODE_RANK の環境変数を設定します。
caution
各ノード上でマルチプロセスのトレーニングを実行するためにこのオプションを使用するためには、Azure ML Python SDK >= 1.22.0
を使用する必要があります。これは、process_count がバージョン 1.22.0 で導入されたためです。
tip
もしもトレーニングスクリプトがローカルランクランクやランクをスクリプト引数として受け取る場合、引数の中でこのように環境変数を参照することができます: arguments=['--epochs', 50, '--local_rank', $LOCAL_RANK]
#
例torch.distributed.launch
(per-node-launch) の使用#
PyTorch は各ノード上でマルチプロセスを実行するためのするためのユーティリティとして torch.distributed.launch を提供します。このtorch.distributed.launch
モジュールは各ノード上で複数のトレーニングプロセスを生成します。
以下のステップはどのように Azure ML 上で per-node-launcher により PyTorch ジョブを構成するかというデモンストレーションです。これは以下のコマンドを実行することと同等のことです。
torch.distributed.launch
コマンドをScriptRunConfig
コンストラクタのcommand
パラメータに与えます。Azure ML はユーザーが指定したクラスター上の各ノード上でこのコマンドを実行します。--nproc_per_node
は各ノードで利用可能な GPU 数と同じかそれ以下に設定します。MASTER_ADDR、MASTER_POR、NODE_RANK のすべては Azure ML によって設定されるため、ユーザーはコマンド中でこれらの環境変数を参照するだけで済みます。Azure ML は MASTER_PORT を6105
に設定しますが、ユーザーは必要に応じて異なる値を torch.distributed.launch コマンドの--master_port
引数に渡すこともできます。(その時、実行ユーティリティは環境変数を再設定します。)PyTorchConfiguration
を作成し、node_count
を指定します。
: シングルノードマルチ GPU トレーニング
もしもシングルノードマルチ GPU の PyTorch トレーニングを実行するためにこの実行ユーティリティを使用する場合は、ScriptRunConfig のdistributed_job_config
を指定する必要はありません。
#
例#
PyTorch LightningPyTorch Lightning は軽量のオープンソースライブラリで、PyTorch のハイレベルなインターフェースを提供します。Lightning を使うことで、素の PyTorch により必要とされる低レベルの分散トレーニング構成の大部分を抽象化して、シングル GPU、シングルノードマルチ GPU、マルチノードマルチ GPU 設定のトレーニングスクリプトを実行することができます。この裏側ではtorch.distributed.launch
のようにマルチプロセスが実行されます。
シングルノードトレーニング (シングルノードマルチ GPU トレーニングを含む) では、distributed_job_config
を指定することなく Azure ML 上でコードを実行することができます。Lightning でマルチノードトレーニングを行う場合は、ユーザーが指定したトレーニングクラスター上の各ノードで下記の環境変数が設定されている必要があります。
- MASTER_ADDR
- MASTER_PORT
- NODE_RANK
マルチノード Lightning トレーニングを Azure ML 上で実行する場合は per-node-launch guide を参考にしてください:
PyTorchConfiguration
を定義して望ましいnode_count
を指定します。Lightning は内部的に各ノードのワーカープロセス実行を管理するため、process_count
を指定してはいけません。- PyTorch ジョブのために、Azure ML は Lightning が必要とする MASTER_ADDR、MASTER_PORT、and NODE_RANK 環境変数の制御を行います。
- Lightning は
--gpus
や--num_nodes
などのトレーナーフラグからコンピューティングのワールドサイズを制御し、内部的にランクやローカルランクを管理します。
#
Hugging Face TransformersHugging Face は、torch.distributed.launch
を使って分散トレーニングを実行する Transformers を使う際の多くの サンプル を提供しています。Hugging Face Transformers Trainer API を使ってこれらのサンプルや任意のカスタムトレーニングスクリプトを実行するためには、torch.distributed.launch の使用 のセクションを参考にしてください。
8 つの GPU を搭載したノード上でrun_glue.py
というスクリプトによりテキスト分類 MNLI タスクを解く BERT の巨大モデルのファインチューニングジョブを構成するコードの例:
torch.distributed.launch
を使わずに、per-process-launch オプションを使用して分散トレーニングを実行することもできます。このメソッドを使う際に気をつけることは、Transformers TrainingArguments は引数中のローカルランク (--local_rank
) を除外することです。torch.distributed.launch
は--use_env=False
が設定されているときこれを管理しますが、Azure ML は LOCAL_RANK 環境変数のみを設定するため、per-process-launch を使うときは明示的に--local_rank=$LOCAL_RANK
引数をトレーニングスクリプトに渡す必要があります。
#
TensorFlowもしもトレーニングコードで TensorFlow 2.x の tf.distribute.Strategy
API のような native distributed TensorFlow を使っている場合は Azure ML のTensorflowConfiguration
を介して分散ジョブを実行することができます。
そのためには、ScriptRunConfig
コンストラクタのdistributed_job_config
パラメータにTensorflowConfiguration
オブジェクトを指定する必要があります。もしもtf.distribute.experimental.MultiWorkerMirroredStrategy
を使っている場合は、トレーニングジョブで使用するノード数をTensorflowConfiguration
のworker_count
で指定します。
分散トレーニングのスクリプトが parameter server strategy を使用する場合 (i.e. レガシーな TensorFlow 1.x を使う場合) は、合わせてジョブの中で使用する parameter server の数を指定する必要があります。 (e.g. tf_config = TensorflowConfiguration(worker_count=2, parameter_server_count=1)
)
#
TF_CONFIGTensofFlow を使って複数のマシン上でのトレーニングを実行するには TF_CONFIG 環境変数が必要になります。TensorFlow ジョブを実行するために、Azure ML はトレーニングスクリプトを実行する前に各ワーカーに対して適切な TF_CONFIG 変数を設定します。
もし必要な場合は、トレーニングスクリプトからos.environ['TF_CONFIG']
によって TF_CONFIG にアクセスすることができます。
チーフワーカーノードで TF_CONFIG を設定する例:
#
例#
InfiniBand による GPU トレーニングのアクセラレーションAzureには、SR-IOV と InfiniBand をサポートする RDMA 対応の VM シリーズがあります (NC、ND、H-シリーズ)。これらの VM は、Ethernet ベースの接続性よりもはるかに高性能の、低遅延で高帯域幅の InfiniBand ネットワークを介してコミュニケーションを行います。SR-IOV for InfiniBand は、MPI ライブラリ (MPI は NVIDIA の NCCL ソフトウェアを含む分散トレーニングフレームワークやツールによって利用されます) に対してニアベアメタルパフォーマンスを提供します。これらの SKU は 高計算負荷ワークロードや、GPU によりアクセラレートされる機械学習ワークロードのニーズを満たすことを目的としています。より詳細な情報は Accelerating Distributed Training in Azure Machine Learning with SR-IOV を参照してください。
もしもAmlCompute
クラスターをStandard_ND40rs_v2
などの RDMA 対応で InfiniBand が有効化された VM サイズで作成している場合は、OS イメージには InfiniBand を有効にするために必要な Mellanox OFED ドライバー のインストールと構築が事前に行われています。