🎉

【LLM】分散トレーニングに関して

2023/12/19に公開

分散に関して深掘り

world_size

・worldは、「分散トレーニングのすべてのプロセスを含むグループ」と見なせる。
・基本的にworld 内のプロセスは相互に通信することが可能。

1プロセスごとに1GPUが使用されるならば、分散トレーニングに使用するGPUの数がworld sizeとなる

world_size = node数 * プロセス数

rank(ランク)とlocal_rank(ローカルランク)

ランクはプロセスに与えられる一意の ID。
ローカルランクは、単一ノードで実行されているプロセスの一意のローカル ID

(例)二つのサーバー(ノード)があり、それぞれ4GPU搭載されていた。
(1プロセスごとに1GPUが使用されると仮定)

ローカルランクは、各ノードごとに
[0, 1, 2, 3] [0, 1, 2, 3]

transformersのライブラリ該当するクラスでもよく登場してくる。

TrainingArgumentsクラスの引数にもあったりする。
local_rank (`int`, *optional*, defaults to -1):
            Rank of the process during distributed training.

device_mapに関して

device_map={"":0}

上記の意味合いは、device 0にモデル全体をフィットさせる。

device_map = "auto"

は、モデルの並列処理を実行したい時に使用する。

ちなみに現在利用しているgpuのidをフィットさせる場合はtorch.cuda.current_device()ではなく、下記の方で取得した方が良いそうです。

from accelerate import Accelerator

dummy_accelerator = Accelerator()
current_device = dummy_accelerator.process_index

https://github.com/huggingface/transformers/issues/21736

分散トレーニングに関連したライブラリ

TorchDistributor

複数ノード(または単一ノード)で,プロセス(gpu)ごとに分散処理できるライブラリ

⭐️databricksのノートブックでも利用できる。
https://docs.databricks.com/en/machine-learning/train-model/distributed-training/spark-pytorch-distributor.html

from pyspark.ml.torch.distributor import TorchDistributor

distributor = TorchDistributor(num_processes=2, local_mode=True, use_gpu=True)
distributor.run(<function_or_script>,<args>)

・単一ノードでトレーニングする場合は、local_mode=True。つまりマルチノードの場合Failse
・Spark タスクごとに 1 つの GPU を割り当てる

(例)
3 つの GPU を備えた単一ノードでファイルを実行場合

from pyspark.ml.torch.distributor import TorchDistributor

distributor = TorchDistributor(num_processes=3, local_mode=True, use_gpu=True)
distributor.run(<function_or_script>,<args>)

⚠️databricksで使用する場合、sparkのオプションでspark.task.resource.gpu.amountの設定を求められることがある。

spark.task.resource.gpu.amount 1

並列処理の手法

モデル並列処理

■ メリット

巨大なモデルは単一の GPU に収まらない。

■ 概要

すべてのモデルを「N」個の部分に分割する。NはGPUの数
各モデルは個別の GPU に配置される。

順伝播: GPU#0⇨GPU#1⇨ ... ⇨GPU#N
逆伝播: GPU#N⇨GPU#N-1⇨ ... ⇨GPU#0

このモデル並列処理を効率よくした方法としてPipelined Executionがある。
https://pytorch.org/docs/stable/pipeline.html

データ並列処理

こっちがトレーニングをスケールアップするための最も一般的な方法論。

■ 概要

データセットをN個に分割する。
NはGPUの数

・DataParallel (dp)
・Distributed Data Parallel (ddp)
等の種類がある。

■ DataParallel (DP)

同じセットアップが複製され、処理は並行して実行される。
各トレーニング ステップの終了時にすべてのセットアップが同期される。

■ ddp(Distributed Data Parallel)

・モデルはすべてのプロセス(各プロセス/ワーカー)で複製される。
・すべてのモデルの複製は 異なる入力データ サンプルのセットが供給される

DP の場合1回のパラメータ更新に対し GPU:0 を起点とした GPU 間通信(データ送信)回数が DDP より多い
引用:https://qiita.com/fam_taro/items/df6061b589c3ccf86089

◇ torchのDistributedDataParallel

https://pytorch.org/docs/stable/generated/torch.nn.parallel.DistributedDataParallel.html

import文
from torch.nn.parallel import DistributedDataParallel as DDP
notebookの場合は下記の環境変数をセットする。
%env MASTER_ADDR=localhost
%env MASTER_PORT=29500

MASTER_PORTとMASTER_ADDRを指定する必要があります。(おそらく、DDPは、マルチノードの並列化にも対応しているからだと思われます

参考:https://qiita.com/meshidenn/items/1f50246cca075fa0fce2

N 個の GPU を備えたホストで DistributedDataParallel を実行する場合には環境変数
をセットしておきます。下記の例では、4つのGPUがある場合です。

notebookの場合で見えるGPUを制限する
%env CUDA_VISIBLE_DEVICES=0,1,2,3

◇AccelerateとDDP

AccelerateはDDP+model parallelismに対応していないらしい。

Accelerate does not support DDP with model parallelism
https://github.com/huggingface/accelerate/issues/1368

fsdp(Fully Shared Data Paralle)

記載予定

参考

https://www.databricks.com/blog/2023/04/20/pytorch-databricks-introducing-spark-pytorch-distributor.html
https://analyticsindiamag.com/data-parallelism-vs-model-parallelism-how-do-they-differ-in-distributed-training/
https://stackoverflow.com/questions/58271635/in-distributed-computing-what-are-world-size-and-rank
https://qiita.com/fam_taro/items/df6061b589c3ccf86089
https://docs.databricks.com/ja/_extras/notebooks/source/deep-learning/torch-distributor-file.html

Discussion