【LLM】分散トレーニングに関して
分散に関して深掘り
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のライブラリ該当するクラスでもよく登場してくる。
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
分散トレーニングに関連したライブラリ
TorchDistributor
複数ノード(または単一ノード)で,プロセス(gpu)ごとに分散処理できるライブラリ
⭐️databricksのノートブックでも利用できる。
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がある。
データ並列処理
こっちがトレーニングをスケールアップするための最も一般的な方法論。
■ 概要
データセットを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
from torch.nn.parallel import DistributedDataParallel as DDP
%env MASTER_ADDR=localhost
%env MASTER_PORT=29500
MASTER_PORTとMASTER_ADDRを指定する必要があります。(おそらく、DDPは、マルチノードの並列化にも対応しているからだと思われます
参考:https://qiita.com/meshidenn/items/1f50246cca075fa0fce2
N 個の GPU を備えたホストで DistributedDataParallel を実行する場合には環境変数
をセットしておきます。下記の例では、4つの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)
記載予定
参考
Discussion