Skip to content
Published on

2026年のLLM学習スタック地図 — 各層が何を代わりにやってくれて、何を隠すか

シェア
Authors

はじめに — フレームワークを選ぶことは何を隠すかを選ぶこと

「どのフレームワークで学習すべきか」という質問に答えはひとつではありません。層が違うからです。torchrunで直接書いたループとYAML一枚で回るファインチューニングは競合関係ではなく上下関係です。

そこでこの記事はフレームワークを羅列する代わりに、三つの層に分けて系譜を描きます。各層について三つだけ見ます。この層が代わりにやってくれることこの層が隠すもの、そして隠したものをもう一度開ける必要があるとき逃げ道があるかです。

この分野は月単位で変わります。以下のバージョンはすべて2026年8月2日にPyPIの配布履歴とGitHubのリリースタグで直接確認した値であり、確認できなかった項目は本文にそう記しました。読まれる時点ではすでにいくつか変わっているはずなので、数字そのものより層構造を持ち帰る方が長く使えます。

確認基準 — バージョンと確認日

ツール確認したバージョン配布日出典
PyTorch2.13.02026-07-08PyPI
DeepSpeed0.19.32026-07-23PyPI
Megatron-Core0.18.22026-07-21GitHub
Transformer Engine2.17.02026-07-09PyPI
torchtitanv0.2.22026-02-20GitHub
NeMo Toolkit2.7.32026-04-23PyPI
NeMo-RLv0.7.02026-07-29GitHub
Transformers5.14.12026-07-16PyPI
TRL1.9.22026-07-28PyPI
PEFT0.20.02026-07-28PyPI
Accelerate1.14.02026-06-11PyPI
Axolotl0.18.02026-07-17PyPI
LLaMA-Factory0.9.52026-05-30PyPI
Unsloth2026.7.62026-07-29PyPI
verl0.8.02026-06-01PyPI
OpenRLHF0.10.42026-06-08PyPI
Liger Kernel0.8.12026-07-23PyPI
torchao0.17.02026-03-30PyPI
torchtune0.6.1(最終)2025-04-07GitHub

1層 — 分散実行エンジン

もっとも下の層は「このテンソルをどのGPUに置き、いつどの集合通信をかけるか」を担当します。三つの系譜があります。

PyTorch分散系列。 torch.distributedがDDP、FSDP2、DTensor、DeviceMesh、torch.distributed.pipeliningをすべて提供します。2026年基準で特徴的な変化は、並列化が別ライブラリではなくPyTorch本体のAPIになったという点です。FSDP2のfully_shardはモジュールを包まず、その場でパラメータをDTensorに変えるため、パラメータ名が維持されチェックポイント互換性の問題が減ります。公式チュートリアルはFSDP1を廃止状態と表記しています。

DeepSpeed系列。 ZeRO 1〜3段階、オフロード、シーケンス並列(Ulysses)、推論カーネルまでひとつのパッケージに入っています。よく受ける質問が「まだ生きているか」ですが、0.19.3が2026年7月23日に出たので活発です。所有構造は変わりました。GitHub組織がmicrosoftからdeepspeedaiに移り、LF AI & DataインキュベーションプロジェクトPyTorch Foundationホスティングプロジェクトになりました。以前のリンクと組織名が文書に残っていれば、その文書は古いものです。

Megatron系列。 NVIDIAのMegatron-LMリポジトリから再利用可能な部分だけを切り出したのがMegatron-Coreで、これがテンソル並列、パイプライン並列、シーケンス並列、コンテキスト並列、専門家並列の事実上の参照実装です。ここに低精度学習を担当するTransformer Engineが付きます。FP8学習は以前からサポートされており、NVFP4の4ビット事前学習もTransformer Engineでサポートされます。NVIDIAの論文は12Bのハイブリッド Mamba-Transformerを10Tトークンまで、FP8基準線と同等に学習できたと報告しています。ただしこの結果を自分のモデルにそのまま移せるかは別問題なので、4ビット事前学習を導入するなら短いランで損失曲線を直接比較すべきです。

この層を直接触るときのインターフェースは大抵設定ファイルです。DeepSpeedならこういう形です。

{
  "bf16": { "enabled": true },
  "zero_optimization": {
    "stage": 3,
    "overlap_comm": true,
    "contiguous_gradients": true,
    "reduce_bucket_size": 5e8,
    "stage3_prefetch_bucket_size": 5e8,
    "stage3_param_persistence_threshold": 1e6,
    "stage3_gather_16bit_weights_on_model_save": true
  },
  "gradient_accumulation_steps": "auto",
  "train_micro_batch_size_per_gpu": "auto",
  "gradient_clipping": 1.0,
  "steps_per_print": 50,
  "wall_clock_breakdown": false
}

ここで実務上もっともよく問題になる行がstage3_gather_16bit_weights_on_model_saveです。3段階ではパラメータがGPUごとに分割されているため、この値を有効にせず保存すると、サービングで読めないシャード断片が出ます。そしてoverlap_commを有効にすると通信と計算が重なって速くなりますが、活性化メモリの余裕を削る方向に働くので、OOMがぎりぎりの構成ではこの値をまず疑ってください。

この層が隠すものはほとんどありません。代わりに何も代行してくれません。データローダー、チェックポイントフォーマット、再開ロジック、ロギングを全部自分で書かなければなりません。

2層 — 学習ループフレームワーク

1層の上に「学習を最初から最後まで回すループ」を載せた層です。

torchtitanはPyTorchチームが作った参照実装で、FSDP2、テンソル並列(非同期変種を含む)、パイプライン並列、コンテキスト並列、HSDPを組み合わせられ、Float8とMXFP8学習をサポートします。リポジトリは自身を「高速な実験と大規模学習のためのPyTorchネイティブプラットフォーム」と紹介し、最新機能を使うにはPyTorchナイトリーを勧めています。つまり安定版の上で回す製品用スタックとして設計されたものではありません。コードを読んで書き写す用途にはこの上ない参照です。

Megatron-BridgeはNVIDIAがHugging FaceチェックポイントとMegatron-Core間の双方向変換を担当させるために作ったライブラリであり、その上にMegatron-Coreを使う学習ループを載せたものです。この橋が重要な理由は実務の流れにあります。モデルはHugging Faceフォーマットで受け取り、学習はMegatron-Coreの並列化で回し、サービングは再びHugging Faceフォーマットで出力しなければなりません。この変換を自分で書くと、テンソル名のマッピングとマージ・分割規則で必ず間違えます。NeMo-RLとSkyRLがMegatron-Coreコネクタとしてこれを採用したという文書の記述があります。

NVIDIA NeMoはその上の総合フレームワークです。事前学習からアライメント、デプロイまでレシピとしてまとめられており、強化学習部分はNeMo-RLとして分離されています。NVIDIAのコンテナ環境をそのまま使えるならもっとも速い経路であり、そうでなければ依存関係の重さが負担になります。

この層が代わりにやってくれるのは並列化の構成、分散チェックポイント、再開、スループットのロギングです。隠すのはオプティマイザステップの詳細と通信スケジュールで、損失スパイクをデバッグするときにもう一度開ける必要が出てきます。

3層 — 設定ファイルで回る事後学習ツール

もっとも上の層はデータセットフォーマット、プロンプトテンプレート、LoRA設定、評価フックまでまとめてコマンド一行で実行します。

TRLはHugging Faceエコシステムの事後学習の標準です。1.9.2のリリースノート基準でSFT、DPO、GRPO、RLOO、KTO、報酬モデルトレーナーが入っており、KTOトレーナーは1.8.0で実験ラベルが外れました。1.7.0でデフォルトの損失がチャンク単位のNLLに変わりMoE補助損失が追加されたように、デフォルト値自体がマイナーリリースで変わります。実験的な名前空間にトレーナーがもう数個入っているという記述をリリースページで見ましたが、個々のアルゴリズムまでは確認していないので、使うバージョンの文書で直接リストを確認してください。TRLはバージョンを必ずピンで固定すべきライブラリです

TRLを直接使うときの最小形はこうです。バージョン固定と損失マスキング確認を一緒に入れておきました。

# pip install "trl==1.9.2" "transformers==5.14.1" "peft==0.20.0" "accelerate==1.14.0"
from datasets import load_dataset
from peft import LoraConfig
from trl import SFTConfig, SFTTrainer

ds = load_dataset("json", data_files="data/sft-train.jsonl", split="train")

cfg = SFTConfig(
    output_dir="out/sft-7b",
    per_device_train_batch_size=4,
    gradient_accumulation_steps=8,
    learning_rate=1e-5,
    num_train_epochs=2,
    bf16=True,
    gradient_checkpointing=True,
    max_length=4096,
    packing=False,              # マスキングを自分で検証するまではオフにしておく
    logging_steps=10,
    save_steps=200,
    report_to="mlflow",
)

trainer = SFTTrainer(
    model="meta-llama/Llama-3.1-8B",
    args=cfg,
    train_dataset=ds,
    peft_config=LoraConfig(r=32, lora_alpha=64, lora_dropout=0.05,
                           target_modules="all-linear", task_type="CAUSAL_LM"),
)

# 学習を始める前にバッチをひとつ目で確認する
batch = next(iter(trainer.get_train_dataloader()))
ids, labels = batch["input_ids"][0], batch["labels"][0]
tok = trainer.processing_class
print("全体:", tok.decode(ids[:200]))
print("損失対象:", tok.decode([i for i, l in zip(ids, labels) if l != -100][:200]))

trainer.train()

最後の五行がこのスクリプトでもっとも重要です。-100でマスキングされた位置は損失から外れますが、テンプレートが少しでもずれると、プロンプト全体に損失がかかったり、逆に応答全体が外れたりします。損失曲線はどちらの場合でももっともらしく下がるので、学習が終わったあとの評価ではじめて発見することになります。

AxolotlはYAML一枚にモデル、データセット、並列化、LoRA設定を詰め込む方式です。複数のデータフォーマットを勝手にトークン化してくれるのがもっとも大きな価値であり、下位ではAccelerateとDeepSpeed/FSDPを選んで使います。

# axolotl==0.18.0基準。accelerate launch -m axolotl.cli.train config.yaml
base_model: meta-llama/Llama-3.1-8B
load_in_4bit: false
strict: false

datasets:
  - path: data/sft-train.jsonl
    type: chat_template
    field_messages: messages

sequence_len: 4096
sample_packing: true
gradient_checkpointing: true
bf16: auto

adapter: lora
lora_r: 32
lora_alpha: 64
lora_dropout: 0.05
lora_target_linear: true

micro_batch_size: 4
gradient_accumulation_steps: 8
num_epochs: 2
learning_rate: 1e-5
warmup_ratio: 0.03
lr_scheduler: cosine

deepspeed: deepspeed_configs/zero3_bf16.json
output_dir: ./out/axolotl-8b

LLaMA-Factoryは似たカテゴリにウェブUIと幅広いモデル対応を加えた方であり、Unslothはカーネル最適化で単一GPUファインチューニングの速度とメモリを改善する方です。Unsloth のマルチGPU対応範囲は配布形態によって変わってきており、この記事を書いている時点の正確な方針は確認できていません。マルチGPUが必要な場合は導入前にリポジトリの文書で直接確認してください。

大規模強化学習側は別系譜です。verlOpenRLHFはロールアウトエンジン(大抵vLLMかSGLang)と学習エンジン(FSDPかMegatron-Core)を分離して付ける構造を使います。GRPO系を数千GPU規模で回すつもりなら、TRLではなくこの系譜を見るべきです。

消えた系譜が教えてくれること — torchtuneとtorchforge

この分野でフレームワークを選ぶことがなぜ危険なのかを示す事例があります。

torchtuneはPyTorchネイティブなファインチューニングライブラリとして始まり、良い評価を受けました。ところが2025年7月、リポジトリのissue #2883番で活発な開発の中断が告知され、PyPI最後の配布は0.6.1、2025年4月7日で止まっています。後継としてtorchforgeが発表されました。ところが2026年8月2日時点でtorchforgeリポジトリの最上部にはこういうバナーが付いています。

Development paused: Development in Forge has paused. LLM training at PyTorch is being consolidated in torchtitan.

つまり後継の後継として吸収される最中です。この経緯から持ち帰るべき教訓は特定のライブラリを非難することではなく、上位フレームワークの期待寿命は下位層より短いという事実です。PyTorch分散APIとMegatron-Coreは何年も生き残ってきましたが、その上の便利な層は二年周期で作り直されてきました。

だから実務の規則はこうなります。プロジェクトの中核資産はフレームワークの設定ファイルではなく、データパイプライン、評価スイート、チェックポイントフォーマットに置いてください。この三つをフレームワークの外に置けば、上位層が消えても取り替えるだけで済みます。

ファインチューニング経路とアライメント段階 — 今の呼び方

何を学習するか決める軸は二つです。ひとつはどの重みを触るか、もうひとつはどんな信号で学習するかです。

経路学習対象おおまかなメモリいつ
Full fine-tuning全重みパラメータあたり16バイト + 活性化ドメイン自体が違うとき、データが十分なとき
LoRA低ランクアダプタのみ基底モデル2バイト + アダプタ状態大半の実務ファインチューニング
QLoRA4ビット基底 + アダプタ基底0.5バイト台 + アダプタ単一カードで大きなモデルを扱わねばならないとき

LoRA系列の変種(DoRA、rsLoRA、LoRA+、PiSSAなど)はPEFTが吸収してきました。どの変種がどのPEFTバージョンに入っているかはリリースごとに異なるので文書を見てください。実務でまず調整すべき手がかりは変種の選択ではなく、ランクと対象モジュール、そして学習率です。QLoRAを実際のサービスに載せる過程はQLoRAプロダクションファインチューニングに別途整理してあり、そもそもファインチューニングが正しい選択かどうかはRAGとファインチューニング、プロンプトエンジニアリングの比較を先に見る方がよいでしょう。

アライメント段階の現在の呼び方はこうです。

  1. 教師ありファインチューニング。 指示・応答ペアで形式とスタイルを整えます。ここで体感品質の大部分が決まります。
  2. 選好最適化。 選好ペアを直接使うオフライン系列(DPOとその変種)と、ポリシーからサンプルを取りグループ内でアドバンテージを計算するオンライン系列(GRPO、RLOO)に分かれます。TRLには両方のトレーナーがあります。
  3. 検証可能な報酬に基づく強化学習。 数学の正解一致やテスト通過のように規則で採点できる報酬を使う方式です。学習済みの報酬モデルを使わないため報酬ハッキングの表面が狭く、推論能力の学習で事実上の標準になりました。

呼び方は増え続けます。新しい略語が出るたびに問うべきことは三つだけです。報酬はどこから来るか、ロールアウトが必要か、参照モデルをメモリに載せる必要があるか。この三つが決まれば必要なGPU数が決まります。

上位フレームワークが邪魔になる瞬間

便利な層は大半の場合利得です。ただし次のような状況ではコストが利得を上回ります。

  • 損失関数やマスキングを変える必要があるとき。 どのトークンに損失をかけるかは事後学習品質の中心的な手がかりですが、上位フレームワークはこれをデータフォーマットの裏に隠します。損失マスクが実際どこにかかったか確認するには、バッチをひとつデコードして自分の目で見る必要があります。この確認をせずに何日も無駄にする事故がもっとも多いです。
  • 並列化の組み合わせが標準を外れるとき。 コンテキスト並列と専門家並列を一緒に有効にするような組み合わせは、上位フレームワークの設定スキーマで表現できないことが多いです。
  • デバッグが必要なとき。 損失スパイクの原因を探るには、勾配ノルム、特定レイヤーの活性化統計、オプティマイザ状態をステップ単位で見る必要があります。コールバックで開くなら幸運で、開かなければフレームワークをフォークすることになります。
  • バージョン固定が不可能なとき。 複数の上位ツールが同じ下位ライブラリの異なるバージョンを要求する状況が実際に起こります。コンテナイメージを自分で作りロックファイルをコミットする以外に方法がありません。
# 最低限これくらいは学習開始前にログに残してください
python - <<'PY'
import importlib.metadata as md
for p in ("torch", "transformers", "trl", "peft", "accelerate",
          "deepspeed", "flash-attn", "datasets"):
    try:
        print(f"{p:14} {md.version(p)}")
    except md.PackageNotFoundError:
        print(f"{p:14} (未インストール)")
PY
nvidia-smi --query-gpu=name,driver_version,memory.total --format=csv
python -c "import torch; print('nccl', torch.cuda.nccl.version())"

おわりに — 層は選ぶが、層に閉じ込められないでください

スタックを選ぶ基準は「何がもっとも良いか」ではなく「自分たちがどの層まで直接責任を負うか」です。事前学習をするならMegatron-CoreかPyTorch分散APIまで下りる必要があり、社内データでファインチューニングだけするならTRLかAxolotlの上で終わらせるのが合理的です。

ただしどの層を選ぶにせよ、データパイプラインと評価スイート、チェックポイントフォーマットはフレームワークの外に置いてください。torchtuneからtorchforgeへ、再びtorchtitanへとつながった二年の経緯が語っているのがそれです。フレームワークは取り替える部品であり、取り替えられるようにしておくことが設計です。並列化そのものの原理はマルチGPU学習の四つの並列化にまとめてあります。