データ並列(データヘイレツ)
分散学習の最も基本的な手法。モデル全体を各GPUに複製し、学習データのミニバッチを各GPUに分配して並列に前方伝播・後方伝播を実行する。各GPUで計算した勾配をAllReduceで集約・平均してパラメータを同期更新する。
データ並列とは
データ並列(Data Parallelism, DP)は、分散学習の中で最も基本的かつ広く使われる手法である。モデルの完全なコピーを各GPU(ワーカー)に配置し、学習データセットをワーカー間で分割して並列に学習を行う。各ワーカーが計算した勾配をAllReduceで集約・平均し、全ワーカーのモデルパラメータを同期的に更新する。
データ並列の基本動作
- モデル複製: 全GPUに同一のモデルパラメータを配置
- データ分割: ミニバッチをGPU数で均等に分割(例: バッチサイズ256を8GPUで32ずつ)
- Forward Pass: 各GPUが独立に前方伝播を実行
- Backward Pass: 各GPUが独立に後方伝播を実行し、ローカル勾配を算出
- AllReduce: 全GPUの勾配を集約して平均を取る
- パラメータ更新: 全GPUが同一の勾配平均でパラメータを更新(同期が保たれる)
PyTorch DDP(DistributedDataParallel)
PyTorchの標準データ並列実装であるDDPは以下の最適化を行う。
| 機能 | 説明 | デフォルト値 |
|---|---|---|
| 勾配バケット化 | 小さな勾配テンソルをバケットにまとめてAllReduce | 25MB |
| 計算-通信オーバーラップ | backward計算と並行して勾配をAllReduce | 有効 |
| 未使用パラメータ検出 | forward未使用のパラメータの勾配をスキップ | False |
| 勾配累積 | N回のforward/backwardを勾配累積してからAllReduce | 1 |
| バックエンド | 通信バックエンド選択 | nccl (GPU) |
# PyTorch DDPの基本的な使い方(概念例)
# model = DistributedDataParallel(model, device_ids=[local_rank])
# optimizer.zero_grad()
# loss = model(input).sum()
# loss.backward() # AllReduceは自動実行
# optimizer.step()
ZeRO(Zero Redundancy Optimizer)
MicrosoftのDeepSpeedが提唱したZeROは、データ並列の冗長性を排除してメモリ効率を大幅に改善する。
| ステージ | 分割対象 | メモリ削減 | 通信量 |
|---|---|---|---|
| ZeRO-1 | オプティマイザ状態 | 4倍 | DDP同等 |
| ZeRO-2 | + 勾配 | 8倍 | DDP同等 |
| ZeRO-3 | + パラメータ | Nリニア | 1.5倍増 |
| ZeRO-Infinity | + CPUオフロード | ほぼ無制限 | 大幅増 |
ZeRO-3では7Bモデル(FP16で14GB)の学習が、8GPUならGPUあたり約1.75GB+αのパラメータメモリで済む。オプティマイザ状態(Adamで約56GB)も8分割で7GB/GPUとなる。
PyTorch FSDP(Fully Sharded Data Parallel)
MetaのFSDPはZeROの概念をPyTorchネイティブに実装したものである。
- シャーディング戦略:
FULL_SHARD(ZeRO-3相当)、SHARD_GRAD_OP(ZeRO-2相当)、NO_SHARD(DDP相当) - Mixed Precision: BF16/FP16での学習をネイティブサポート
- アクティベーションチェックポイント:
checkpoint_wrapperで再計算を自動適用 - Transformer自動ラップ:
transformer_auto_wrap_policyでTransformerブロック単位に自動シャーディング - PyTorch 2.0+統合:
torch.compileとの互換性が改善
データ並列のスケーリング
| GPU数 | グローバルバッチサイズ | 学習率 | スケーリング効率(理想1.0) |
|---|---|---|---|
| 1 | 32 | 1e-4 | 1.0(基準) |
| 8 | 256 | 8e-4 | 0.95-0.98 |
| 64 | 2,048 | 6.4e-3 | 0.90-0.95 |
| 256 | 8,192 | 2.56e-2 | 0.85-0.92 |
| 1,024 | 32,768 | ウォームアップ必須 | 0.75-0.85 |
大規模バッチでは学習率のスケーリングが重要。線形スケーリングルール(GPU数に比例して学習率を上げる)やLARS/LAMBオプティマイザを使用する。
データ並列の課題と対策
- 通信ボトルネック: GPU数が増えるとAllReduceの通信量が学習時間に影響。対策: 勾配圧縮、FP8通信、計算-通信オーバーラップ
- 大バッチ汎化問題: バッチサイズが大きすぎると汎化性能が低下。対策: ウォームアップ、学習率スケジューリング、LAMB
- メモリ冗長: 標準DDPでは全GPUにモデル全体を複製するためメモリが無駄。対策: ZeRO/FSDP
- 同期バリア: 最も遅いGPUに全体が律速される(ストラグラー問題)。対策: 非同期SGD、バックアップワーカー
2025-2026年の最新動向
- DiLoCo: Google DeepMindが提唱した「低通信分散学習」。数百ステップごとに外側ループで同期し、内側ループは各ワーカーが独立に学習。通信量を100倍以上削減
- FP8データ並列: H100のFP8演算とFP8通信を活用し、学習速度と通信効率を同時に改善
- Asynchronous DDP: 同期バリアを排除した非同期勾配更新。収束の安定性は課題だが、異種GPU混在環境で有効
- FSDP2(PyTorch 2.4+): FSDPの第2世代。DTensor統合、per-parameter sharding、より細かい制御が可能
よくある質問(FAQ)
Q1: データ並列とDDP(DistributedDataParallel)の違いは?
A: データ並列は概念・手法の名称。DDPはPyTorchにおけるデータ並列の実装。旧式のDataParallel(DP)はGILボトルネックで非推奨。DDPはプロセスベースでGPU間のAllReduceを効率的に行う。
Q2: ZeRO-3とFSDPはどちらを使うべきですか? A: PyTorchエコシステムに統一したいならFSDPが推奨。DeepSpeed固有機能(ZeRO-Infinity、1-bit Adam、勾配圧縮)が必要ならZeRO-3。性能はほぼ同等だが、FSDPはPyTorch公式でありtorch.compileとの統合が優れている。
Q3: データ並列だけで大規模モデルを学習できますか? A: ZeRO-3/FSDPを使えば数十億パラメータまでは可能。70Bモデルを64台のH100(ZeRO-3)で学習した実績がある。ただし405B以上ではテンソル並列・パイプライン並列との組み合わせ(3D並列)が必須。
まとめ
- データ並列は分散学習の基本で、モデル複製+データ分割+勾配AllReduceで動作
- PyTorch DDPが標準実装、ZeRO/FSDPがメモリ効率を大幅改善
- ZeRO-3/FSDPでGPUあたりのメモリ使用量をN分の1に削減可能
- 大バッチ学習では学習率スケーリングとウォームアップが重要
- DiLoCoなどの低通信手法が2025-2026年の注目トレンド