目次を表示する

LLM完全解説:スクラッチから理解する大規模言語モデル

スケーリング則と訓練インフラ ── Chinchilla・分散訓練

スケーリング則と訓練インフラ ── Chinchilla・分散訓練

LLM との関係:「モデルを大きくすれば性能が上がる」──この経験則を理論化したのがスケーリング則。そしてそれを実現するのが数千 GPU の分散訓練インフラ。


スケーリング則と訓練インフラ — Chinchilla・分散訓練・ZeRO

この章で何ができるようになるか:「なぜ LLM はこれほど巨大になったのか」を経済的・技術的に説明でき、分散訓練の基本的な並列化戦略を理解できる。


スケーリング則(Scaling Laws)

Kaplan et al.(2020, OpenAI)の発見

モデルの性能(損失 L)は以下の3つの変数のべき乗則に従う:

L(N) ∝ N^(-0.076)   — N: パラメータ数
L(D) ∝ D^(-0.095)   — D: 訓練データ量(トークン数)
L(C) ∝ C^(-0.050)   — C: 計算量(FLOPs)

つまり:
  パラメータ数を10倍にすると → 損失が約 0.076 × log(10) ≈ 0.17 減少
  データ量を10倍にすると   → 損失が約 0.095 × log(10) ≈ 0.22 減少
  
→ 予測可能に性能が改善し続ける(飽和しない)
→ 「お金を投じれば性能が上がる」ことが保証される

Chinchilla(2022, DeepMind)の修正

Kaplan 則は「パラメータ数を増やすことが最優先」と示唆したが、Chinchilla 論文はこれを修正した。

Chinchilla の主張:
  最適な訓練は「パラメータ数 N とデータ量 D を同じ比率で増やす」こと。
  
  最適比率: D ≈ 20 × N
  → 70B パラメータのモデルには 1.4T トークンが必要
  
  GPT-3(175B パラメータ、300B トークン)は
  「パラメータが多すぎ、データが少なすぎ」だった。
  
  Chinchilla(70B パラメータ、1.4T トークン)は
  GPT-3 より小さいのに同等以上の性能を達成。
  → 推論コストも大幅削減(パラメータが少ない = 推論が速い)

実際のモデルのスケール

モデルパラメータ数訓練トークン数訓練 FLOPs(推定)
GPT-3175B300B3.1 × 10²³
Chinchilla70B1.4T5.8 × 10²³
LLaMA 2 70B70B2T
LLaMA 3 405B405B15T3.8 × 10²⁵
GPT-4(推定)~1.8T (MoE)~13T

訓練コストの見積もり

def estimate_training_flops(num_params: float, num_tokens: float) -> float:
    """訓練の FLOPs を概算(Kaplan の近似式)"""
    return 6 * num_params * num_tokens
    # 6N×D: 順伝播 2N×D + 逆伝播 4N×D

def estimate_training_cost(flops: float, gpu_flops_per_sec: float,
                            gpu_utilization: float, gpu_cost_per_hour: float,
                            num_gpus: int) -> dict:
    """訓練コストの概算"""
    effective_flops = gpu_flops_per_sec * gpu_utilization * num_gpus
    training_seconds = flops / effective_flops
    training_hours = training_seconds / 3600
    cost = training_hours * gpu_cost_per_hour * num_gpus
    return {
        "training_hours": training_hours,
        "training_days": training_hours / 24,
        "cost_usd": cost
    }

# LLaMA 3 70B の概算
flops = estimate_training_flops(70e9, 15e12)  # 6.3 × 10²⁴ FLOPs

result = estimate_training_cost(
    flops=flops,
    gpu_flops_per_sec=312e12,  # H100: 312 TFLOPS (FP16)
    gpu_utilization=0.4,       # 実効利用率 ~40%
    gpu_cost_per_hour=3.0,     # H100 クラウド単価
    num_gpus=2048,
)
# → 約 25 日、約 360 万ドル

分散訓練:数千 GPU の協調

1台の GPU では LLM の訓練は不可能。H100 のメモリは 80GB だが、70B パラメータのモデルは FP16 で 140GB(パラメータだけで)。

Data Parallelism(データ並列)

同じモデルのコピーを各 GPU に配置。
異なるミニバッチを処理し、勾配を平均する。

GPU 0: batch[0:32]   → 勾配G0
GPU 1: batch[32:64]  → 勾配G1
GPU 2: batch[64:96]  → 勾配G2
GPU 3: batch[96:128] → 勾配G3

全GPUの勾配を平均: G = (G0 + G1 + G2 + G3) / 4
→ 各GPUが G で重みを更新

問題: モデル全体が各 GPU のメモリに載る必要がある
→ 大きなモデルには使えない

Model Parallelism(モデル並列)

Tensor Parallelism(テンソル並列):
  1つの行列演算を複数 GPU に分割
  W = [W1 | W2](行列を列方向に分割)
  GPU 0: y1 = W1 @ x
  GPU 1: y2 = W2 @ x
  y = concat(y1, y2)

Pipeline Parallelism(パイプライン並列):
  モデルの層を GPU に分割
  GPU 0: Layer 0-23  → 中間出力を GPU 1 へ
  GPU 1: Layer 24-47 → 中間出力を GPU 2 へ
  GPU 2: Layer 48-71 → 中間出力を GPU 3 へ
  GPU 3: Layer 72-95 → 最終出力

  問題: 1つのバッチの処理中、待機する GPU がある(バブル)
  対策: Micro-batching(バッチをさらに分割して流す)

ZeRO(Zero Redundancy Optimizer)

DeepSpeed が実装した、Data Parallelism の改良。

通常の Data Parallelism:
  各 GPU がモデル全体のコピー(パラメータ + 勾配 + オプティマイザ状態)を持つ
  → 冗長なメモリ消費

ZeRO Stage 1: オプティマイザ状態を GPU 間で分割
ZeRO Stage 2: + 勾配も分割
ZeRO Stage 3: + パラメータも分割
  → 各 GPU は全体の 1/N だけ保持
  → 必要なときに他の GPU から取得(通信コストと引き換え)

訓練の安定性

大規模モデルの訓練は不安定で、突然損失が発振(spike)することがある。

安定化のテクニック:
  
  1. Learning Rate Warmup
     最初は学習率を小さくして徐々に上げる
     → 初期の大きな勾配による発散を防ぐ
  
  2. Cosine Learning Rate Schedule
     ピーク後に学習率をコサイン曲線で減衰
  
  3. Gradient Clipping
     勾配の L2 ノルムが閾値を超えたらクリッピング
     → 勾配爆発を防ぐ
  
  4. Mixed Precision Training(FP16/BF16)
     FP32 → BF16 で計算(メモリ半減、速度2倍)
     重要な計算(勾配の累積・損失計算)は FP32 で行う
# PyTorch での典型的な訓練設定
from torch.optim.lr_scheduler import CosineAnnealingLR

optimizer = torch.optim.AdamW(model.parameters(), lr=3e-4, weight_decay=0.1)
scheduler = CosineAnnealingLR(optimizer, T_max=total_steps, eta_min=3e-5)

for step, batch in enumerate(dataloader):
    # Warmup(最初の2000ステップ)
    if step < 2000:
        lr = 3e-4 * step / 2000
        for pg in optimizer.param_groups:
            pg['lr'] = lr

    with torch.cuda.amp.autocast(dtype=torch.bfloat16):  # Mixed Precision
        logits = model(batch.input_ids)
        loss = criterion(logits, batch.labels)

    loss.backward()
    torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)  # Gradient Clipping
    optimizer.step()
    scheduler.step()
    optimizer.zero_grad()

まとめ

テーマ要点
Scaling Lawsパラメータ・データ・計算量を増やすと性能が予測可能に改善
Chinchilla最適比率 D ≈ 20N。データを十分に食わせることが重要
Data Parallelism同じモデルを複数 GPU に複製し、バッチを分割
Model Parallelismモデル自体を複数 GPU に分割(テンソル/パイプライン)
ZeROメモリの冗長性を排除(Stage 1/2/3)
訓練安定化Warmup + Cosine LR + Gradient Clipping + BF16

次章では、事前学習済みモデルを「人間にとって有用な応答をするモデル」に変える──RLHF とアラインメントの話に進む。