モデルパラメータが数億〜数千億に達する現代の深層学習では、1台のGPUで訓練を完結させることは現実的ではありません。Databricksは、Sparkクラスタのインフラを活用してPyTorch・TensorFlow・DeepSpeedなどの分散トレーニングをノートブックから直接実行できる統合環境を提供しています。本記事ではTorchDistributor・HorovodRunner・Ray・DeepSpeedの4つのフレームワークを軸に、分散戦略の選択からGPU構成、MLflowとの連携まで実務と試験の両面から解説します。
分散トレーニングの戦略は大きく2つに分かれます。どちらを採用するかはモデルサイズとGPUメモリの関係で決まります。
モデルの完全なコピーを各GPUに配置し、訓練データを分割して各GPUが異なるミニバッチを処理します。各GPUは独立にフォワード・バックワードパスを実行し、勾配をAllReduceで集約してパラメータを同期します。モデルが1台のGPUメモリに収まる場合はデータ並列が第一選択です。
データ並列の概念図:
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ GPU 0 │ │ GPU 1 │ │ GPU 2 │
│ Model Copy │ │ Model Copy │ │ Model Copy │
│ Batch 0-99 │ │ Batch 100-199│ │ Batch 200-299│
└──────┬──────┘ └──────┬──────┘ └──────┬──────┘
│ │ │
└────────┬───────┴────────┬───────┘
│ AllReduce │
│ (勾配集約) │
▼ ▼
パラメータ同期 → 次のイテレーションモデルが1台のGPUメモリに収まらない場合、モデル自体を分割して複数GPUに配置します。テンソル並列(Tensor Parallelism)は1つのレイヤー内の行列演算を分割し、パイプライン並列(Pipeline Parallelism)はレイヤー群を段階的に各GPUに割り当てます。LLMのファインチューニングではこの2つを組み合わせる3D並列(データ+テンソル+パイプライン)が主流です。
モデル並列の概念図:
パイプライン並列:
┌──────────┐ ┌──────────┐ ┌──────────┐
│ GPU 0 │───▶│ GPU 1 │───▶│ GPU 2 │
│ Layer 0-7│ │ Layer 8-15│ │Layer 16-23│
└──────────┘ └──────────┘ └──────────┘
テンソル並列 (1レイヤー内):
┌────────────────────────────┐
│ Weight Matrix │
│ ┌──────┬──────┬──────┐ │
│ │GPU 0 │GPU 1 │GPU 2 │ │
│ │Col0-3│Col4-7│Col8-11│ │
│ └──────┴──────┴──────┘ │
└────────────────────────────┘TorchDistributorはDatabricks Runtime 13.0+で導入された、Sparkクラスタ上でPyTorch DDPを実行するためのAPIです。 Sparkのタスクスケジューリングを利用してワーカーノードにPyTorchプロセスを配置し、 NCCLバックエンドでGPU間通信を行います。 従来のPyTorch DDPではtorchrunコマンドやランチャースクリプトが必要でしたが、 TorchDistributorはノートブックから直接分散訓練を起動できるため、セットアップの手間が大幅に削減されます。
from pyspark.ml.torch.distributor import TorchDistributor
import torch
import torch.nn as nn
import torch.distributed as dist
from torch.nn.parallel import DistributedDataParallel as DDP
from torch.utils.data import DataLoader, DistributedSampler
def train_fn():
dist.init_process_group("nccl")
rank = dist.get_rank()
device = torch.device(f"cuda:{rank % torch.cuda.device_count()}")
model = nn.Sequential(
nn.Linear(784, 512), nn.ReLU(),
nn.Linear(512, 256), nn.ReLU(),
nn.Linear(256, 10)
).to(device)
model = DDP(model, device_ids=[device])
dataset = load_training_data() # 訓練データの読み込み
sampler = DistributedSampler(dataset)
loader = DataLoader(dataset, batch_size=64, sampler=sampler)
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)
loss_fn = nn.CrossEntropyLoss()
for epoch in range(10):
sampler.set_epoch(epoch)
for batch_x, batch_y in loader:
batch_x, batch_y = batch_x.to(device), batch_y.to(device)
loss = loss_fn(model(batch_x), batch_y)
optimizer.zero_grad()
loss.backward()
optimizer.step()
dist.destroy_process_group()
return model
# Sparkクラスタ上で4GPU分散訓練を実行
distributor = TorchDistributor(
num_processes=4,
local_mode=False, # True: ドライバノードのみ、False: ワーカーノードに分散
use_gpu=True
)
trained_model = distributor.run(train_fn)local_mode=Trueはドライバノード上のマルチGPU実行(デバッグ用途)、local_mode=Falseはワーカーノードへの分散実行です。num_processesは使用するGPUの総数を指定します。 クラスタのワーカーが各2GPUで2ノードならnum_processes=4です。
HorovodはUber社が開発したフレームワーク非依存の分散トレーニングライブラリです。PyTorch・TensorFlow・Kerasに対応し、MPIベースのAllReduce通信で勾配を集約します。DatabricksではHorovodRunnerというラッパーAPIが提供されており、Sparkクラスタ上でHorovodプロセスをバリアモードで起動します。
import horovod.torch as hvd
import torch
import torch.nn as nn
from torch.utils.data import DataLoader, DistributedSampler
def train_hvd():
hvd.init()
rank = hvd.rank()
torch.cuda.set_device(hvd.local_rank())
device = torch.device("cuda")
model = nn.Sequential(
nn.Linear(784, 512), nn.ReLU(),
nn.Linear(512, 256), nn.ReLU(),
nn.Linear(256, 10)
).to(device)
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3 * hvd.size())
optimizer = hvd.DistributedOptimizer(optimizer, named_parameters=model.named_parameters())
hvd.broadcast_parameters(model.state_dict(), root_rank=0)
dataset = load_training_data()
sampler = DistributedSampler(dataset, num_replicas=hvd.size(), rank=hvd.rank())
loader = DataLoader(dataset, batch_size=64, sampler=sampler)
loss_fn = nn.CrossEntropyLoss()
for epoch in range(10):
sampler.set_epoch(epoch)
for batch_x, batch_y in loader:
batch_x, batch_y = batch_x.to(device), batch_y.to(device)
loss = loss_fn(model(batch_x), batch_y)
optimizer.zero_grad()
loss.backward()
optimizer.step()
return model
from sparkdl import HorovodRunner
hr = HorovodRunner(np=4, driver_log_verbosity="all")
trained_model = hr.run(train_hvd)HorovodRunnerのnpパラメータはプロセス数です。np=-1を指定するとクラスタの全GPUを自動検出して使用します。 TorchDistributorとの主な違いは、HorovodがDistributedOptimizerでoptimizerをラップし、broadcast_parametersで初期パラメータを明示的に同期する必要がある点です。 TorchDistributorではPyTorch標準のDDPラッパーをそのまま使うため、既存のDDPコードを最小限の変更で移行できます。
Ray 2.x以降、DatabricksクラスタはRayクラスタとしても動作できるようになりました。ray.util.spark.setup_ray_cluster()でSparkワーカー上にRayワーカーを起動し、 Ray TrainやRay TuneでPyTorch・TensorFlowの分散訓練とハイパーパラメータチューニングを統合実行できます。
Rayの強みは訓練とチューニングの統合です。Ray Tuneの探索アルゴリズム(ASHA、PBTなど)とRay Trainの分散訓練を組み合わせることで、複数のハイパーパラメータ設定を並列に分散訓練できます。単純な分散訓練だけならTorchDistributorの方がセットアップが簡単ですが、大規模なハイパーパラメータサーチを伴う場合はRayが有利です。
MicrosoftのDeepSpeedは、ZeROオプティマイザによるメモリ効率化が最大の特徴です。ZeRO Stage 1はオプティマイザ状態を分割、Stage 2は勾配も分割、Stage 3はモデルパラメータも分割し、GPUメモリ消費を劇的に削減します。Databricks上ではTorchDistributorの訓練関数内でDeepSpeedを初期化して使用します。
70Bパラメータ規模のLLMをファインチューニングする場合、ZeRO Stage 3 + Offload(CPUメモリへのパラメータ退避)を組み合わせることで、A100 80GB×8台程度のクラスタでも実行可能になります。DeepSpeedはJSON設定ファイルで各種最適化を制御するため、コード変更なしにメモリ最適化レベルやバッチサイズ調整が可能です。
| 項目 | TorchDistributor | HorovodRunner | Ray Train | DeepSpeed |
|---|---|---|---|---|
| 対応フレームワーク | PyTorchのみ | PyTorch / TensorFlow / Keras | PyTorch / TensorFlow / JAX | PyTorch(主にTransformers) |
| 通信バックエンド | NCCL(GPU)/ Gloo(CPU) | MPI / NCCL / Gloo | NCCL / Gloo(内部でPyTorch DDP使用) | NCCL(ZeRO通信最適化内蔵) |
| 主な利点 | Spark統合がネイティブ、セットアップ最小 | フレームワーク非依存、実績豊富 | 訓練+チューニングの統合 | 超大規模モデルのメモリ効率化 |
| 推奨シナリオ | PyTorch DDP新規プロジェクト | TensorFlow分散 / 既存Horovodコード | ハイパーパラメータサーチ併用 | LLMファインチューニング(10B+パラメータ) |
分散トレーニングにはノード間通信のオーバーヘッドが伴います。闇雲にマルチノードにすると、通信コストがボトルネックになり逆に遅くなるケースがあります。以下の基準で判断します。
| 判断軸 | シングルノードマルチGPU | マルチノード分散 |
|---|---|---|
| モデルサイズ | 1ノードのGPUメモリ合計に収まる | 1ノードに収まらない(例: 70B LLM) |
| データ規模 | 数百GB以下 | TB規模のデータセット |
| 訓練時間 | 許容範囲(数時間〜1日) | シングルノードでは数日以上かかる |
| 通信 | NVLink/NVSwitch(ノード内高速通信) | InfiniBand推奨(ノード間通信がボトルネック) |
| デバッグ容易性 | 高い(1ノードで完結) | 低い(ノード障害・通信タイムアウト対応が必要) |
DatabricksでGPUクラスタを構成する際、ワークロードに応じて適切なGPUインスタンスを選択します。
| GPU | メモリ | FP16性能 | 適用シナリオ | AWSインスタンス例 |
|---|---|---|---|---|
| A10G | 24 GB | 125 TFLOPS | 中規模モデル推論、軽量ファインチューニング | g5.xlarge〜g5.48xlarge |
| A100 | 40 / 80 GB | 312 TFLOPS | 大規模訓練、LLMファインチューニング | p4d.24xlarge(8×A100 40GB) |
| H100 | 80 GB | 990 TFLOPS | 超大規模LLM訓練、Transformer Engineによる混合精度 | p5.48xlarge(8×H100) |
A10Gはコストパフォーマンスに優れ、7B以下のモデルのファインチューニングや推論に適しています。A100はLLMの本格的な訓練に必要なメモリ帯域とTFLOPSを備え、分散訓練のスタンダードです。H100はFP8対応のTransformer Engineを搭載し、A100比で約3倍の訓練スループットを実現しますが、コストも相応に高くなります。
クラスタ設定では、Databricks Runtime ML(MLR)を選択し、GPUドライバ・CUDA・cuDNN・NCCL・PyTorch・TensorFlowが事前インストールされた環境を使います。マルチノード分散ではワーカー間のネットワーク帯域が重要で、AWSならEFAネットワーク、AzureならInfiniBand対応のインスタンスを選択すると通信ボトルネックを軽減できます。
分散トレーニングでは複数のプロセスが同時にMLflowにログを書き込むと、 メトリクスの重複やランの競合が発生します。 ベストプラクティスはrank 0のプロセスのみがMLflowにログを記録するパターンです。
import mlflow
import torch.distributed as dist
def train_fn():
dist.init_process_group("nccl")
rank = dist.get_rank()
# ... モデル定義・訓練ループ ...
# rank 0 のみが MLflow にログを記録
if rank == 0:
with mlflow.start_run():
mlflow.log_param("num_gpus", dist.get_world_size())
mlflow.log_param("batch_size_per_gpu", 64)
mlflow.log_param("effective_batch_size", 64 * dist.get_world_size())
mlflow.log_metric("final_loss", avg_loss)
mlflow.pytorch.log_model(model.module, "model")
dist.destroy_process_group()model.moduleはDDPラッパーを外した元のモデルです。 DDPラッパーのまま保存すると推論時にDDP初期化が必要になるため、 必ず.moduleでアンラップしてからMLflowに記録します。 effective_batch_sizeはGPU数×per-GPU batch sizeで、学習率のスケーリングの根拠としてログに残します。
分散トレーニングはML Professional試験で深く問われるトピックです。以下のポイントを整理しておくと得点源になります。
local_mode=Trueはドライバノード上のローカル実行(デバッグ用)、Falseはワーカーノードへの分散実行np=-1はクラスタの全GPUを自動使用するオプションML Professional
問題 1
MLエンジニアが13BパラメータのTransformerモデルをDatabricksクラスタ(A100 80GB × 4台)でファインチューニングしたい。モデルの全パラメータとオプティマイザ状態を合計するとGPUメモリ約200GBを必要とする。最も適切なアプローチはどれか。
正解: B
モデルの全パラメータ+オプティマイザ状態で約200GBが必要で、A100 80GBの1台には収まりません。通常のデータ並列(AやC)はモデルの完全コピーを各GPUに配置するため、1GPU 80GBでは不足します。DeepSpeed ZeRO Stage 3はオプティマイザ状態・勾配・パラメータの3つを全GPUに分割するため、200GB ÷ 4 = 50GB/GPUとなり80GBメモリ内に収まります。Dはハイパーパラメータサーチであってモデルのメモリ問題を解決しません。
TorchDistributorとHorovodRunnerはどちらを使うべきですか?
新規プロジェクトではTorchDistributorが推奨されます。TorchDistributorはDatabricks Runtime 13.0+でネイティブサポートされており、PyTorch DDPをSpark上でシームレスに実行できます。HorovodRunnerはTensorFlowやMXNetなど複数フレームワークに対応していますが、Uber社によるHorovodの開発が縮小傾向にあるため、PyTorch単体であればTorchDistributorの方がセットアップが簡単で公式サポートも手厚いです。
シングルノードマルチGPUと分散マルチノードはどう使い分けますか?
まずシングルノードマルチGPU(例: A100×4のインスタンス)で訓練を試し、GPU メモリやスループットが不足する場合にマルチノードへ拡張するのが定石です。シングルノードではノード間通信のオーバーヘッドがなくデバッグも容易です。マルチノードが必要になるのは、モデルサイズが1ノードのGPUメモリに収まらない場合、またはデータ規模が大きくバッチ並列度を上げたい場合です。
分散トレーニングはどの認定試験で出題されますか?
ML Professional試験で最も深く問われます。TorchDistributorとHorovodRunnerの使い分け、データ並列とモデル並列の違い、MLflowでの分散実行トラッキングが出題範囲です。ML Associate試験では分散トレーニングの基本概念(なぜ分散が必要か、データ並列の仕組み)が軽く問われることがあります。GenAI Engineer試験ではDeepSpeedを使ったLLMファインチューニングが関連トピックとして出題される可能性があります。
NicheeLab編集部
データエンジニアリング・クラウド資格の専門家。Databricks・Snowflake等の認定資格を保有し、実務経験に基づいた問題作成・解説を行っています。NicheeLab運営。
Databricks資格一覧|全7試験・難易度・勉強法
Databricks認定資格全7試験の一覧・難易度・出題範囲・合格ラインを徹底解説。2026年最新版の公式試験ガイドに準...
Databricks試験の難易度ランキング|全7資格を徹底比較
Databricks認定全7試験の難易度をランキング形式で徹底比較。合格率・学習時間・出題傾向から難易度を分析。...
Databricks資格の勉強方法|最短合格ルートと学習時間の目安
Databricks認定資格に最短で合格するための勉強方法を完全ガイド。公式リソース・問題集・学習スケジュールを徹底解説...
Databricks Data Engineer Associate完全解説|出題範囲・問題例・合格戦略
Databricks Certified Data Engineer Associate試験を徹底解説。5つの出題ドメイ...
Databricks Data Engineer Professional完全解説|上級試験の攻略法
Databricks Certified Data Engineer Professional試験を徹底解説。10の出題...