LLMの訓練方法
大きな言語モデル(LLM)を「知的に聞こえるアシスタント」に仕立てる作業は、粘土で彫刻を作る反復プロセスに似ています。まず塊を扱いやすい形に整え、徐々に細部を削り出して完成品に近づけていく。最終段階に近づくほど細かな仕上げが結果を大きく左右します — 傑作と不気味の谷の差はその辺にあります。
細部に手を付けるには、まず大まかな形を作る必要があります。同様に、事前学習のない素のアーキテクチャをそのまま好みの挙動に放り込んで最適化することはできません。モデルが報酬を受け取って安定した方向に動くための基盤がまず必要です。
この「粘土を成形する」過程は現在も活発に研究されている分野で、完全な“超整合化された真理探索型アシスタント”という聖杯にはまだ到達していませんが、ここ数年で我々の知見は大きく進みました。🚀
Kimi と Deepseek の論文は、事前学習から監視付き微調整、強化学習を積み重ねてLLMの有用性を継続的に高めるための実践的知見を多く公開しました。
参考として、Deepseek V3 は 14.8 trillion tokens(約1.23億冊分の平均的な長さの小説に相当)で学習しました。規模感を掴むために、2010年に Google が 人類によって書かれた本の総数を129百万冊と推定したことが比較指標になります。
エンドツーエンドのモデル訓練フローは、すべてのモデルに同じ段階が必要なわけではありませんが、最も完全なフローは事前学習の後に一つ以上のポストトレーニング段階と整合化ステップを踏む形になります。
モデル訓練手法:LLM彫塑家の道具箱
Chain-of-thought(CoT)推論や外部ツールの活用といった複雑な言語振る舞いを得るために、LLM は基本的に「三つの連動するループ」で訓練されます。
自己教師あり事前学習(Self-Supervised Pre-Training)
粘土の形を整えるのと同様、複雑な推論や会話的振る舞いを引き出す前に、モデルはまず言語の基礎を学ぶ必要があります。事前学習は大量の自己教師あり学習を通じて一般的な素地(priors)と生の能力をもたらします。モデルはコード、百科事典、教科書、Webページなど多様なドメインのテキストを大量に与えられ、テキストの一部を隠してそれを埋めることで人間の言語の傾向を学びます。
現代のスタックは、性能と効率を両立するためにアーキテクチャとシステムの工夫を多用します。具体例としては、密なコストを抑えながら容量を増やすための Mixture-of-Experts (MoE)、注意メモリを縮小する Multi-head Latent Attention (MLA)、高スループットの数値演算を安定させる FP8/MuonClip、目的関数を濃密化して投機的デコードを速める Multi-Token Prediction (MTP) などです。これらは、GPUを燃やしたり損失曲線を爆発させたりしないように訓練を工学的に設計するための手法群です。🔧
ポストトレーニング(Post-Training Fine-Tuning)
第二のループであるポストトレーニングは、ベースモデルに指向性とスタイルを与えます。一般的にチームはまず instruction、JSON フォーマット、ツール呼び出しトレースに対する supervised fine-tuning (SFT) を行い、モデルに指示の従い方やユーザーとの対話の形式を教えます。微調整がなければ、LLMは単に無限にテキストを継続生成して訓練データの断片を吐き出すだけです。指示に従う形の対話データセットを合成して、モデルのトークン生成を「命令」フォーマットへ誘導する必要があります(これが Instruction Fine-Tuning)。
チャット形式で応答できるようになったら、次に Direct Preference Optimization や Group Relative Policy Optimization (GRPO) のような繊細な強化学習(RL)手法を適用して、トーン、安全性、スキーマ順守を整えます。ここが「整合化(alignment)」の核心で、人間にとって有益な出力を生むようモデルの振る舞いを形成していくフェーズです。⚖️
さらに、数学やコード、出力フォーマットに厳密に報酬を与える Reinforcement Learning with Verifiable Rewards のような手法や、Chain-of-Thought 推論に焦点を当てた RL(o1/R1 系)により、長い生成と推論時の計算を通じて問題解決力を高めることが可能です。
ツール利用のための訓練(Training for Tool Use)
思考パターンが強化学習で形成されるのと同様に、ツールの使用も訓練で自然に現れる生成パターンの一種です。システム統合を正しく呼び出す出力を得るために、我々は「エージェント/ツールループ」を実行します。ここでは高カバレッジの tool-call トレースを大量に用意し、厳密なスキーマを適用して、ブラウザ、ターミナル、リポジトリなどのサンドボックス環境で「知っている」から「できる」へとギャップを埋めます。joint RL を少し併用すると成功率とレイテンシ改善に寄与しますが、多くは良いトレースと厳格なスキーマによって信頼性が担保されます。
最近の報告では、OpenAI の o3 系推論モデルが、ツールコール学習ループと推論微調整を組み合わせることで、推論テキストとツール利用を自発的に混ぜた生成が可能になってきているとされています。
オープンソース領域からの具体例を挙げると、DeepSeek-V3 は 671B パラメータの MoE(トークン当たり約 37B active)で 14.8T トークンを事前学習し、FP8 と MTP を層として取り入れて訓練の安定性と推論速度を両立させています。一方 Kimi K2 は ~1.04T パラメータ MoE(トークン当たり約 32B active)で 15.5T トークンを事前学習し、MuonClip による損失スパイク回避と大規模なツール利用合成および joint RL に重心を置いています。
実務的には:事前学習が言語に対する一貫した理解を作り、ポストトレーニングがツール利用、推論、役割演技といった振る舞いを付与します。
微調整とプロンプト(Fine-Tuning vs Prompting)
「なぜ微調整するのか。十分に命令調整されたモデルに完全な指示セットを与えてプロンプトだけで済ませられないのか?」という疑問がよくあります。
その理由は、instruction fine-tuning だけでは限界があるからです。プロンプトであり得る命令の空間は巨大で、モデルはツール呼び出しに関する以前の指示と新規データから来る後続の情報を同時に扱わなければなりません。短時間でコンテキストは混乱し、attention が枯渇します。
どの情報をいつどのように重視するかを学習していないと、instruction-tuned モデルはエージェント的なツール利用シナリオで崩壊しやすいです。非ツール呼び出しモデルの制約を工夫で回避する方法はありますが、指示従い、推論、ツール利用の複雑な空間を成功裏に航行するよう報酬付けされたモデルを導入する方が、一般的には遥かに効果的です。💡
形を作る手:データはどのような形をしているか?
LLM訓練で最も重要なのはデータそのものです。言語をモデル化するのに十分なデータを取得し、保存し、参照・注釈し、固定長シーケンスに分割してモデルに与えるまでには高度に洗練された工程があります。
私のバイオインフォマティクス経験から言うと、この過程は DNA シーケンシングの前処理に似ています。DNA を読み取れる状態にするには長く繊細な前処理プロトコルがあり、シーケンサーは配列長や品質に厳しい要件を持ちます。同様に、LLM でもテキストコーパスを効率よくチャンク化し、品質管理された注釈付きの固定長を与えて大規模な並列処理を可能にする必要があります。
データ処理のエンドツーエンド経路は、生のソースから固定長シーケンスへと整形され、最終的に Python の DataLoader にトークンIDとしてロードされるまでを含みます。この記事の範囲では全工程を詳細に解説しきれないため、主要な前処理フェーズを簡潔にまとめます。
- Sourcing(収集): スクレイパーの作成、ライセンス購入、公開データダンプへのアクセスなど。データは単一のコーパスからは来ないため、収集時点のスナップショットとして固定化する必要があります。事前学習が始まった後にモデルが新情報へアクセスする手段は、主にツール利用とコンテキストエンジニアリングになります。
- Extraction, Normalization, and QA(抽出・正規化・品質保証): PDF、HTML、GitHub のコードなどからテキストを高品質に抽出し、「garbage in, garbage out」を防ぐフィルタリングを行います。完全にノイズフリーにすることは不可能ですが、自己教師あり学習で収束(安定学習)できるレベルまでデータの論理性と一貫性を確保することが目標です。
- Annotation and Structuring(注釈と構造化): 自動アルゴリズムでクリーンなサンプルにラベルやフレーム、ドキュメント長、フォーマット情報(markdown, javascript, html など)を付与して保存します。これらは訓練時のサンプリングやデバッグに有用な要約統計を提供します。
- Chunking, sharding, and padding(チャンク化・シャーディング・パディング): ドキュメントの境界を示す特殊トークンを使ってコンテンツを切り、トークン化して数値IDにし、一定長にパディングします。等長シーケンスに揃えることで多くのシーケンスを同時にモデルに投げて大規模に並列化できます。
以下に主要フェーズを簡潔に示す表を追加します(参考):
| フェーズ | 目的 | 具体例 |
|---|---|---|
| 収集 (Sourcing) | 広範なデータ確保 | Webスクレイプ、データセット購入、公開ダンプ |
| 抽出・正規化 (Extraction) | ノイズ除去と統一化 | PDF→テキスト、HTML除去、エンコーディング正規化 |
| 注釈 (Annotation) | メタ情報付与 | フォーマット、言語、段落分割、スキーマタグ |
| チャンク化 (Chunking) | 訓練効率化 | トークン、等長パディング、シャード分割 |
注: プライバシーや法的リスク(PII、著作権、国別規制)はデータ収集・利用において重要な落とし穴です。特に商用利用を想定する場合、training の可否を示す policy_flags や著作権センシティビティの検査を組み込むことを強く推奨します。⚠️
私はこの長いデータ処理の流れについては別の記事でさらに詳述する予定です。📝
次に、事前学習の具体例を二つの公開プレプリント(Deepseek と Kimi)を通じて見ていきます。
Pre-training(事前学習):粘土の成形
ここでは公開プレプリントで共有された二つの事例、Deepseek と Kimi を取り上げます。
DeepSeek-V3
DeepSeek V3 は 671 billion パラメータの MoE で、トークンあたり約 37 billion の active パラメータを持ちます。MLA を用いて KV を圧縮しメモリ/レイテンシを改善、aux-loss-free なロードバランシング、FP8 を使った混合精度の検証を大規模で行っています。
学習データは 14.8 trillion tokens で、工学的な共同設計により事前学習・コンテキスト拡張・ポストトレーニングを通した総コストは 約 2.788M H800-GPU 時間に相当すると報告されています。
(以前にこのアーキテクチャを直感的に解説したことがありますが、詳細な参照リンクはこの文書では削除しています。)
Kimi K2
Kimi K2 は約 1.04 trillion パラメータの MoE で、トークンあたり約 32 billion の active パラメータを持ちます。こちらも MLA を採用し、384 個の experts を持ち token ごとに 8 個を選択する構成を取っています。最大コンテキストウィンドウは 128K トークンです。
Kimi K2 は 15.5 trillion tokens で事前学習され、Mu onClip(Muon + QK-Clip)を利用して兆単位のパラメータスケールで生じうる損失スパイクを抑えています。トークン効率を第一のスケール指標として重視している点が特徴です。
DeepSeek V3 と異なり、Kimi K2 のポストトレーニングは明確にエージェンティックで、大規模なツール利用合成と joint RL に重心を置いています。
コンテキスト拡張:感覚過負荷の管理
DeepSeek V3 のアーキテクチャでは rotary positional encodings(RoPE)を注意メカニズムに用いて、トークンの相対位置情報を与えることで同一トークンの位置差を識別できるようにしていました。こうした相対距離を学習に取り込む仕組みがあると、入力長を変えた場合にモデルが訓練時の最大 attention 範囲を超えたテキストに対して注意を適切に払えなくなる問題が生じます。
この問題に対処するために、訓練時には「Context Extension(コンテキスト拡張)」というカリキュラムが用いられます。これは短いシーケンス(例えば 8k トークン)から始め、段階的に 16k、32k、さらに長いシーケンスへと再調整していく方式です。
最前線のモデルは通常、128K 以上をステージング(短→長のカリキュラム)で扱えるように positional/attention の調整と「ニードル」的なストレステストを入れて長期シーケンスでの退化を防ぎます。DeepSeek V3 の論文は 8k→32k→128k の二段階拡張を報告しています。
一方、Kimi K2 は対照例で、2025年10月時点で Kimi K2 の技術論文は最初から 128K をサポートしており、MLA、long sequence RoPE、MuonClip により兆級パラメータでの長文訓練を管理していると述べています。これは一年程度の間に起こった訓練イノベーションの一例で、従来の長コンテキスト事前学習の前提を更新しうる事例です。
ポストトレーニング:細部の彫刻
「ポストトレーニング」フェーズでモデルの振る舞いは具体化します。事前学習前のモデルは単なる次トークン予測器に過ぎませんが、ポストトレーニングを通じて指導や強化によってデータにない行動様式(指示従い、チャット、推論、ツール呼び出し)を強制することができます。
監視付き微調整(Supervised Fine-Tuning, SFT)
SFT は教師強制による次トークン予測で、キュレーションされた会話やデモンストレーション上で cross-entropy を最小化することでモデルを望ましい出力へと合わせ込みます。事実上の「報酬」は、例示データと同じテキストを生成することに最大報酬が与えられる仕組みです。
モデルが学ぶ内容は次のように制御します:
- どのトークンにラベルを付けるか(役割やフィールドによる損失マスキング)
- 特定パターンの出現頻度(ミックスウェイト、カリキュラム)
- 構造の厳密さ(データビルド時のバリデータ)
具体的には、会話をシリアライズしてトークン化し、模倣したい部分(通常はアシスタントの応答やツールの function-call オブジェクト)だけに対して損失を計算します。ユーザーの発話や生のツール出力には通常損失を計算しません。
多くの場合、まず instruction tuning を行ってモデルをアシスタントらしく振る舞わせるようにします。SFT に投入するデータは以下のような形式になります(以下はコードブロック内なので原文のままです。ブロック内は変更していません):
{ "id": "sft-0001", "system": "You are a concise assistant.", "messages": [ {"role": "user", "content": "Explain dropout in one paragraph."}, {"role": "assistant", "content": "Dropout randomly zeros units ..."} ], "loss_mask": { "assistant": true, // label these tokens "user": false // don't compute loss here }, "tags": ["instruction", "science.explain", "concise"]}
(注)上の例は SFT 用データの典型的なスキーマを示しています。実務ではさらに厳格なバリデーション、レート制御、メタ情報の管理が必要になります。
補足(エッジケースと運用上の注意):
- データ汚染(データセットと評価セットの重複)はモデル能力の過大評価につながるため、n-gram/regex ベースのデコンタミネーションやハッシュベースの重複検出を徹底してください。🔎
- PII(個人情報)の検出と除去、著作権に敏感なコンテンツの扱いは法的リスク管理の要です。CI/CD パイプラインに法務チェックを組み込むことを推奨します。⚠️
- 長コンテキストの訓練コスト、データ転送、GPUメモリ管理は実装のボトルネックになりやすく、トレードオフを事前に評価しておくことが重要です。
(続きは次パートで、ポストトレーニングの続きとツール訓練の実装ディテール、及び評価フレームワークについて掘り下げます。)
トレーニング中、構造化データは単一のトークン列にシリアライズされ、ユーザートークンにはマスクがかけられます。これにより、会話におけるアシスタントの振る舞いにモデルが合わせられます。
ChatML 風テンプレートで単一文字列の会話を表すと、次のようになります。
<BOS><|system|>You are a concise assistant.<|eot|><|user|>Explain dropout in one paragraph.<|eot|><|assistant|>Dropout randomly zeros units ...<|eot|>
この段階が「supervised」なファインチューニングと呼ばれる理由は、ラベルをアンマスクされたトークンとして明示的に与え、アシスタントがまさにそのトークンを生成することを目的(損失最小化)として求める点にあります。
選好最適化(低コストで安定した制御)
Direct Preference Optimization (DPO) は、正解そのものではなく「比較」から学ぶ、選好ベースのポストトレーニング手法です。
各プロンプトに対して、あなたは「chosen(選ばれた)応答」と「rejected(却下された)応答」を提供します。モデルは、固定の reference policy(通常は SFT チェックポイント)を基準として、chosen の確率が rejected よりも高くなるよう学習します。ここではクリティック/報酬モデルや PPO のループは使わず、安定したオフライン目的関数だけを用います。
SFT が「何を言うか」を教えるのに対し、DPO は「どちらの選択肢がより良いか」を教えます(トーン、安全性、簡潔さ、フォーマットの正確性など)。コストが低く、ロバストで反復が容易なため、多くのスタックがまず DPO(場合によっては二値的代替である KTO と併用)を採用し、その後(あるいは代わりに)RLHF を行います。
DPO の各サンプル入力は通常、次のような形式になります。
{ "id": "dpo-00421", "prompt": "<BOS>\n<|system|>\nYou are a concise assistant.\n<|eot|>\n<|user|>\nExplain dropout in one paragraph.\n<|eot|>\n", "chosen": "<|assistant|>\nDropout randomly masks units ... (clear, concise)\n<|eot|>\n", "rejected": "<|assistant|>\nDropout is a technique that was first... (rambling / off-spec)\n<|eot|>\n", "meta": {"reason": "conciseness/style", "source": "human_label"}}
ここでは、モデルに対する入力が ChatML でシリアライズされたプロンプトになっている点で、instruction tuning(指示調整)を発展させていることがわかります。
(補足)DPO はラベル付け済みの比較ペアがあれば簡単に運用でき、モデルのトーンや形式の好みを安定的に制御するのに向いています。💡
以下は DPO を適用する際の Python 擬似コードの分解です(実装時は該当関数・ローダー等を用意してください):
import torchimport torch.nn.functional as F# This is pseudocode, but require that these exist for a real implementation:# - dpo_loader: yields batches with fields .prompt_ids, .chosen_ids, .rejected_ids, .assistant_mask# - policy: trainable model (θ)# - reference_policy: frozen reference model (θ_ref), typically the SFT checkpoint# - seq_logprob(model, prompt_ids, response_ids, mask, length_normalize=True): returns# the sequence log-prob over ONLY the masked assistant tokens (optionally length-normalized)beta = 0.1 # strength of preference separationfor batch in dpo_loader: prompt_ids = batch.prompt_ids # [B, T_prompt] chosen_ids = batch.chosen_ids # [B, T_answer] rejected_ids = batch.rejected_ids # [B, T_answer] assistant_mask = batch.assistant_mask # [B, T_answer] bool (loss only on assistant tokens) # --- Sequence log-probs under the current policy (θ) --- logp_chosen = seq_logprob(policy, prompt_ids, chosen_ids, mask=assistant_mask) logp_rejected = seq_logprob(policy, prompt_ids, rejected_ids, mask=assistant_mask) # --- Sequence log-probs under the frozen reference (θ_ref) --- logp0_chosen = seq_logprob(reference_policy, prompt_ids, chosen_ids, mask=assistant_mask).detach() logp0_rejected = seq_logprob(reference_policy, prompt_ids, rejected_ids, mask=assistant_mask).detach() # --- DPO margin: encourage policy to widen the chosen-vs-rejected gap relative to the reference --- margin_current = (logp_chosen - logp_rejected) # under θ margin_reference = (logp0_chosen - logp0_rejected) # under θ_ref (no grad) z = beta * (margin_current - margin_reference) # Numerically stable: -log σ(z) == BCEWithLogits(z, target=1) loss = F.binary_cross_entropy_with_logits(z, torch.ones_like(z)) # Standard optimizer step policy.zero_grad(set_to_none=True) loss.backward() torch.nn.utils.clip_grad_norm_(policy.parameters(), max_norm=1.0) # optional but helpful for p in policy.parameters(): if p.grad is not None and torch.isnan(p.grad).any(): raise RuntimeError("NaN in gradients") policy.optimizer.step()
各サンプルについて、学習中のモデルは次のような挙動を最大化されます。
- chosen テキストと完全に一致すること
- rejected テキストとはまったく一致しないこと
- 元にした reference(instruction-tuned な SFT チェックポイント)との性質から大きく乖離しないこと
十分な比較ペアを与えると、新しいチェックポイントは SFT のコアな振る舞いを保持しつつ、監督学習の例に厳密に従うだけでなくユーザーの好みに従うようになります。
しばしば、ユーザー入力を取り込むことは、チーム内部で合成・キュレーションされたプロンプトだけでは得られない開放世界での「使い勝手」を形成する上で重要です。
強化学習(Reinforcement Learning)
現代のスタックでは、RL は大きく二つの用途で現れます:自動採点可能なエンドポイント(数学・コード・フォーマットなど)と、長期的推論(long-horizon reasoning、o-series/R1 スタイル)です。効率のために、どちらも通常は PPO の完全な価値関数ループではなく、Group Relative Policy Optimization(GRPO)系列の「グループ相対・クリティック不要」な更新を使います。
グループ相対ポリシー最適化(GRPO)
GRPO は、ラベルを与えずとも rewarder 関数を使ってモデル同士で自己比較させ、効率的に最良の挙動を見つける手法です。
PPO と違い、別のクリティックモデルは不要です。モデルに複数の候補答を生成させ、それらを自動チェックで採点し、最もスコアの高い答えに報酬を与えます。自動チェックは「正確な答えの有無」「ユニットテストの合格」「データスキーマの妥当性」などを判定し、場合によっては長さやレイテンシの罰則を与えることもあります。
重要なのは、スコアがグループ内で「相対化」される点です。これによりサンプル自体から低分散のアドバンテージ信号が得られ、別の大規模言語モデルを走らせて評価する必要がなくなります。結果として PPO と比べて計算コストが大幅に下がります。PPO 風の clipping を入れて trust region を保ち、シーケンス全体の長さ正規化されたログ確率で生成全体を報酬対象にすることで、単純で安定したループが得られます。グループサイズを増やせば信号が鋭くなり、モデルは徐々に採点基準を満たす出力へと移行します。🚀
以下は概念を掴むための擬似コードです:
# Hyperparamsgroup_size = 8 # Kclip_epsilon = 0.2temperature = 0.8top_p = 0.95for prompt in prompt_batch: # 1) Propose K candidate completions from the *old* policy candidates = sample_candidates(old_policy, prompt, group_size, temperature=temperature, top_p=top_p) # 2) Score each candidate with your programmatic reward function rewards = [compute_reward(prompt, completion) for completion in candidates] # 3) Group-relative advantages (z-score within the K samples) advantages = zscore(rewards) # (r_i - mean) / (std + eps) # 4) Policy-gradient update with PPO-style clipping (sequence-level, length-normalized) for completion, advantage in zip(candidates, advantages): logprob_new = sequence_logprob(policy, prompt, completion, mask="assistant", length_normalize=True) logprob_old = sequence_logprob(old_policy, prompt, completion, mask="assistant", length_normalize=True).detach() likelihood_ratio = torch.exp(logprob_new - logprob_old) loss += -torch.clamp(likelihood_ratio, 1 - clip_epsilon, 1 + clip_epsilon) * advantage optimizer.zero_grad() loss.backward() optimizer.step() # 5) Trust-region bookkeeping (standard PPO-style: refresh the old policy) old_policy.load_state_dict(policy.state_dict())
検証可能な報酬を用いた強化学習
「答えが良いかどうかを自動判定できる」場合、RL は安価かつ安全にスケールします。ただし、大規模モデルでは挙動を変えるために数百万の例、数億の候補、数兆トークンの生成が必要になることがあり、人手で全てを確認するのは現実的ではありません。そこで「検証可能な報酬(verifiable rewards)」が重要になります。これは、モデルが行ったタスクの達成を自動的に判定する手段がある報酬です。
SFT/DPO が完全にオフラインで行われるのに対し、RL タスクは「プロンプト + 自動採点器(grader)」です。各例は、完了結果をプログラム的に検証できるタスクや問題を含みます。
コードではユニットテストやリンティング、実行時チェックで判定できます。数学では期待解答の式や論証の正確性を部分的に一致で判定することができます。
最小限の JSON サンプル(数学とコード)例は次の通りです。
Math
{ "id": "rl-math-0007", "prompt": "<BOS>\n<|system|>Answer with just the number.<|eot|>\n<|user|>What is 37*91?<|eot|>\n", "rewarders": [ {"type": "exact_answer", "target": "3367"}, {"type": "format_regex", "pattern": "^[0-9]+$"}, {"type": "length_penalty", "alpha": 0.001} ]}
Coding
{ "id": "rl-code-1031", "prompt": "<BOS>\n<|system|>Write a Python function solve() that reads stdin and prints the answer.<|eot|>\n<|user|>Given N, output the sum 1..N.<|eot|>\n", "rewarders": [ {"type": "unit_tests", "tests": ["tests/sum_to_n_*.txt"], "timeout_ms": 2000}, {"type": "runtime_penalty", "beta_ms": 0.0005}, {"type": "format_regex", "pattern": "def solve\\("} ], "sandbox": {"image": "py3.11", "mem_mb": 512}}
rewarders は生成テキストに対してどのように報酬を与えるかを評価するプログラムです。人間の期待に沿う結果には高い報酬を与え、乖離する結果には罰を与えます。
注: モデルの「alignment(整合性)」研究は、報酬器と人間の期待の一致を検討します。報酬器をハックして高得点を出す生成(例:数学で答えだけを丸暗記する、ユニットテストをかろうじて通す脆弱な関数を書く)を防ぐのは難しい問題です。⚠️
Chain-of-Thought(思考過程)を伴う強化学習(o-series / R1 スタイル)
長期的な問題で最終的な正確性を最適化するためには、モデルに内部的な深い計算を「誘導」して恒常的な振る舞いとして獲得させる必要があります。これは、報酬が最終結果の正誤のみで与えられる状況で、モデルが自ら構造化された思考パターン(chain-of-thought)を学習することで実現します。
思考過程のファインチューニングは、段階的なステップに対して報酬を与えず、最終的な正誤のみで報酬を与えるタイプの検証可能な報酬 RL の一種です。ここでは「補助輪を外す」ように、最終報酬に至る過程そのものをモデルに学ばせます。
よく使われる追加設定の例:
- Language/format reward(言語/フォーマット報酬):例「回答は英語で、最終行は
Final Answer: ...とする」 - Process shaping(工程形成、任意):中間チェック(サブゴール、ツール不要の演繹)に小さなボーナスを与える。ただし推論時にステップバイステップ解答を公開するわけではない。
DeepSeek の R1 は、強力な事前学習ベース(SFT で冷開始しない)から純粋な reasoning RL を行い、長期推論を引き出した例です。その後、少量の SFT と追加 RL で仕上げ、最終的に R1 の思考パターンをチャットモデルに蒸留(distill)しています。OpenAI の o1 系も、大規模 RL を中心に Chain-of-Thought を扱う手法をとっています。
CoT トレーニング用の GRPO スキーマ例は次の通りです。
{ "id": "rl-reason-2203", "prompt": "<BOS>\n<|system|>Provide only the final numeric answer after thinking.\n<|eot|>\n<|user|>If f(x)=..., compute ...<|eot|>\n", "rewarders": [ {"type":"equality_modulo","target":"(2*sqrt(3))/5"}, {"type":"format_regex","pattern":"^Final Answer: "}, {"type":"language","lang":"en", "gamma": 0.05} ], "sampling": {"K": 8, "temp": 0.9}}
このスキーマは検証可能な報酬とよく似ていますが、モデルが最終答えに到達するために内部ロジックを自発的に発展させる必要がある点で難易度が高くなっています。結果として、思考過程のモノローグはトレーニングを通じて「出現(emergent)」することがあります。LLM は思考モノローグの生成方法を明示的に教えられるわけではありませんが、最終報酬を得るためにそれを必要とするようになります。
これらのタスクは検証可能報酬のサンプルよりも慎重にキュレーションされる必要があり、サンプルごとの生成トークン数は通常より多くなります。
注: reasoning-focused な RL と検証可能報酬を使った RL には共通点が多く、報酬器が明確に評価できない「unverifiable」な報酬を扱う superalignment の分野もあります。これは記事の範囲外ですが、ヒトの期待や安全性にモデルを合わせる最前線の研究領域です。🔬
LLM を実世界と接続する:ツール利用
多くの「ツール利用に関するアラインメント」は RL の前段階で解決されます。まず SFT でツールのスキーマやトレースを教え、次に RL で微調整します。
SFT では、モデルが特定のツール利用スキーマ(多くは XML/JSON)を生成するサンプルを追加し、会話に「tool」ロールを導入してツールからの実世界フィードバックをキャプチャします。一般に、モデルにはプログラムや統合先とやり取りするための構造化スキーマを生成することを学習させ、これがさまざまなツールやスキーマに一般化することを期待します。これにより、ビジネス固有のユースケースに合わせたカスタムプロンプトでもモデルが適切に振る舞えるようになります。🔧
外為レート参照の JSON サンプルは次のようになります。
{ "id": "sft-tool-0219", "system": "You can call tools. Prefer JSON answers.", "tools": [{"name":"fx.lookup","schema":"fx.lookup.input_schema"}], "messages": [ {"role":"user","content":"What's the EUR→CAD rate right now?"}, {"role":"assistant","tool_call":{"name":"fx.lookup","arguments":{"base":"EUR","quote":"CAD"}}}, {"role":"tool","name":"fx.lookup","content":{"rate":1.47,"timestamp":"2025-08-09T10:22:01Z"}}, {"role":"assistant","content":"{\"pair\":\"EUR/CAD\",\"rate\":1.47}"} ], "loss_mask": { "assistant.tool_call": true, // learn name+args JSON "assistant.text": true, // learn final summary/JSON "user": false, "tool.content": false // don't memorize raw tool output }}
このデータは次のようにシリアライズされ、モデルは assistant メッセージを正確に完成させることを学びます。
<BOS><|system|> You can call tools. Prefer JSON answers. <|eot|><|user|> What's the EUR→CAD rate right now? <|eot|><|assistant|><|tool_call|>{"name":"fx.lookup","arguments":{"base":"EUR","quote":"CAD"}}<|eot|><|tool|><|fx.lookup|>{"rate":1.47,"timestamp":"2025-08-09T10:22:01Z"}<|eot|><|assistant|>{"pair":"EUR/CAD","rate":1.47}<|eot|>
その後、サンドボックス内で検証可能な報酬を用いた GRPO RL で仕上げを行うことができます。
{ "id": "rl-tool-0817", "prompt": "<BOS>\n<|system|>Use tools only if needed. Respond in JSON.\n<|eot|>\n<|user|>What's the current EUR→USD rate?\n<|eot|>\n", "tools": ["fx.lookup"], "environment": { "sandbox": "http", "rate_limits": {"fx.lookup": 5}, "secrets_policy": "none_leak" }, "rewarders": [ {"type":"tool_success", "name":"fx.lookup", "checker":"value_in_range", "range":[1.3,1.7], "weight":1.0}, {"type":"schema_valid", "target":"assistant_json", "weight":0.2}, {"type":"latency_penalty", "beta_ms":0.0003}, {"type":"no_op_penalty", "delta":0.1}, // punish unnecessary calls {"type":"arg_semantics", "rule":"base!=quote", "weight":0.2} ], "limits": { "max_calls": 2, "max_tokens": 512 }}
強化学習で最も難しい点は、実世界のツール利用例に対して「鋭く検証可能な」報酬を用意することです。現実世界の複雑さでは、報酬をハックして高得点を得る方法の数が、正当な完了経路の数を大きく上回ることが多く、これがモデルの「ロールプレイ」的な振る舞い(報酬は得られるが実際の環境や論理を正しく反映しない挙動)を生みます。⚠️
私見としては、次の AI 能力の進化は単に計算量や事前学習規模から生まれるのではなく、報酬ハッキングを防ぎ、モデルが正当に報酬を得るための軌道を狭めるポストトレーニングの継続的な改良から生まれると考えています。
報酬ハッキング対策の実務的注意点(補足)
- 多様な rewarder を組み合わせる:単一のチェックだけでは回避可能なケースが生まれるため、フォーマット・値域・テスト・セマンティクスなど複数の視点で評価する。
- サンドボックスでの異常検知:異常なリクエストパターンや短期的な性能ジャンプを自動でフラグする。
- ヒューマン・イン・ザ・ループのスパース監査:全サンプルは見られなくても、ランダムサンプリングで品質チェックを継続する。
- 報酬のロバスト化:報酬関数自体を敵対的検査でテストし、「ハックしやすい」報酬設計を見つけて修正する。🔍
手法比較(簡易まとめ)
| 手法 | ラベル必要性 | コスト | 得意領域 |
|---|---|---|---|
| SFT | 明示ラベル(教師) | 低〜中 | 指示への忠実な生成、基本的な振る舞い |
| DPO | 比較ラベル(chosen/rejected) | 低 | トーン・簡潔さ・形式の選好制御 |
| GRPO(RL, verifiable) | 自動判定器(報酬) | 中〜高 | 自動採点可能なタスク(コード・数式等) |
| CoT RL(長期推論) | 最終正答のみ可 | 高 | 長期的推論や思考過程の誘導 |
事例:DeepSeek-V3 による RL と蒸留
(ここは原著のケーススタディの導入部に相当する節です。実装詳細や評価指標、蒸留の具体的手順などはプロジェクトごとに異なるため、実務では次の点を確認してください:データセットの多様性、報酬器の堅牢性、蒸留時の教師信号の品質、デプロイ後のモニタリング体制。📝)
- 蒸留の一般的な流れ:大規模な RL-trained model(例:R1)で得られた推論スタイルを、小さなチャットモデルに教師信号として与えて模倣させる。
- 実務上の注意:蒸留後も思考の透明性・安全性は再評価する(報酬ハッキングや不整合が転写される可能性があるため)。
最後に、ポストトレーニングは単一の魔法の手法ではなく、SFT / DPO / GRPO / CoT-RL を組み合わせて目的に応じて使い分け、かつ運用での監視と改善を継続する工程です。継続的な小さな改善の積み重ねが、より実用的で安全な LLM の動作に繋がります。
Deepseek-V3は671BパラメータのMoEで、トークンあたりアクティブなパラメータは約~37Bです。コンテキストをメモリ効率よく扱うためにMulti-head Latent Attention(MLA)を中心に設計され、学習目標はマルチトークン予測(multi-token prediction、MTP)です。MTPの要点は重要で、モデルは連続した2つのトークンを同時に予測します。スペキュレーティブデコーディング時に2番目のトークンが受け入れられる確率は~85–90%で、これにより推論時のスループットが品質を損なうことなく概ね1.8× tokens-per-secondに向上します。要するに、未来のトークンを「合法的に先回りして」高確率で成功させることでスピードを稼いでいるイメージです 🚀。
スケール面では、V3は事前学習で14.8T tokensを消費し、エンドツーエンドの合計で~2.788M H800 GPU-hoursを要しました。この数値にはロングコンテキスト拡張とポストトレーニングが既に含まれています。トレーニングは混合精度のFP8を用い、膨大なボリュームでコスト効率と安定性を両立させています。これは単に「ノブを右に回す」だけでは達成できないもので、レポートでは「回復不能な損失スパイクがない安定実行」や「整ったインフラ設計」の重要性が強調されています ⚠️。
ポストトレーニング段階でV3の性格や推論能力が磨かれます。チームはまず教師ありファインチューニングと強化学習(RL)を適用し、さらにR1シリーズから推論行動を蒸留してチャットモデルへ戻すというアプローチを取っています。つまり、SFTを介さずに事前学習ベース上で直接RLを用いて高度に議論(reasoning)させ、その得られた挙動を圧縮してベースモデルへ反映させる、という循環を回すことでベースモデルを段階的に改善していきます。こうした反復的なRL→蒸留のサイクルにより、継続的な改善が可能になります。
ケーススタディ:Kimi K2 によるエージェンティックなツール利用
Kimi K2はチャット専用ではなく、明確に「エージェンティック(agentic)」な動作を意図して設計されています。内部は1.04T-parameter MoEで、トークンあたり~32B active、MLAを採用。アクティブなFLOPsを抑えつつエキスパートプールを大きくするためにスパース性に依存したアーキテクチャになっています。具体的には総エキスパート数を384(k=8 active)に増やし、V3と比べてアテンションヘッド数を半分の64にしています。このトレードオフによりスループットを抑制しつつ、スパースネスに関するスケーリング則の下で検証損失が改善されています。標準でのコンテキスト長は128Kです。
K2はMuonClipという仕組みを導入しています。これはMuonにQK-Clip機構を組み合わせ、query/key投影をリスケールすることでattention-logitの暴走を抑えます。その結果、15.5T tokensにわたる事前学習を損失スパイクなしで行えたとされています。兆単位規模の学習で一部のヘッドが爆発して全体が揺らぐ――という事態を目にしたことがあるなら、この実用的な対策がいかに有効か想像しやすいでしょう。
ポストトレーニングでは「大規模なツール利用」に重点を置いています。まず、ツール仕様、マルチターンの軌跡、ルーブリックに基づく評価を生成する大規模な合成/実データのエージェンティックデータパイプラインを整備し、次に「共同RL(joint RL)」を適用します。ここでは実証可能な報酬(APIコールが成功したか、返却したJSONが妥当か)と、自己批評(self-critique)ルーブリックを混合して、静的なトレースだけでは学べない行動を形成しています。
開発者向けに役立つ点として、K2は関数呼び出し用のトークンテンプレートを公開しており、生成時に宣言されたスキーマに一致することを保証する**「enforcer」制約付きデコーダ**の解説も行っています。壊れやすい関数呼び出しフォーマットで苦労したことがあるチームには有用です 🔧。
最後に、K2は製品としての配布も考慮されています。Open-weight checkpoints(base と instruct)はblock-FP8で公開され、vLLM, SGLang, TensorRT-LLM向けのデプロイ例が添えられているため、評価や本番運用の「hello world」への道が短くなっています。既存のスタックがOpenAI/AnthropicスタイルのAPIに準じている場合の互換性や温度(temperature)対応の注意点もリポジトリに記されています。
モデル比較の簡易サマリ(読みやすさのために追加しました):
| 項目 | Deepseek-V3 | Kimi K2 |
|---|---|---|
| 総パラメータ | 671B | 1.04T |
| アクティブ(トークンあたり) | ~37B | ~32B |
| アーキテクチャ | MLA中心のMoE | MLA + MuonClip のMoE |
| 事前学習トークン量 | 14.8T | 15.5T |
| コンテキスト長 | 長コンテキスト(拡張あり) | 128K |
| 特徴 | MTP + スペキュレーションで推論高速化 | ツール指向、エンフォーサ付きデコーダ、実証可能報酬の強化 |
1ページのビジュアル要約(代替テキスト)
- Deepseek-V3:MTPで推論を高速化し、FP8で大規模安定学習を達成。
- Kimi K2:ツール利用に最適化されたエージェント志向モデル。MuonClipで損失スパイクを回避し、関数呼び出しの厳格な保証機構を提供。
- 共通点:大量データ、混合精度、RL→蒸留のループで性能と挙動を磨く。💡
まとめ(要点整理)
LLMを彫刻に例えるなら、事前学習がブロックを形作り、ポストトレーニングが細部と個性を刻む工程です。LLM構築は容易ではなく、豊富なリソース、データ、計算、そして人手が必要です。
トレーニング工程を要約すると次の通りです:
- ウェブ、コード、百科事典、書籍など多様なソースからデータを収集する
- QAと前処理を行い、注釈を付けたチャンクにまとめる
- 事前学習で自己教師ありの言語モデル能力を付与する(autoregressive)
- SFTでチャットや関数呼び出しの振る舞いを指導する
- 強化学習とリワーダー関数で数学やコーディングなどの検証可能な報酬を改善する
- 推論中心のRLで最終アウトカムに重きを置き、推論行動や高度なツール利用を促進する
これらを蒸留でベースモデルに戻す循環を回すと、LLMの挙動は継続的に向上します。
しかしプロセスには限界と課題があります:
- 報酬ハッキングが大規模では蔓延しやすく、数百万の例を堅牢に監督するのは困難です。検証可能な報酬に頼ることでより複雑な振る舞いを形成していますが、それでも人間が期待する多くの現実世界タスクでは報酬を定量化しづらく、十分に扱えないケースが残ります。
- 長期タスクで最終的な完了を重視して推論を強制すると、必ずしも論理的一貫性を持った思考が形成されるとは限りません。一般に見られるパターンですが、CoT(Chain-of-Thought)推論は分布外タスクで崩壊しやすく、次の研究で議論されているような問題が生じます(こちらの論文、こちらの報告)。思考過程が論理的に循環したり一貫性を欠くことがあり、正しい結論に偶発的に辿り着く「正しいが誤った理由」のケースは大規模スケールで評価するのが非常に難しいです。
- 人類の知見の最前線に寄与するためには、「検証不可能(unverifiable)」な報酬をどう生成して学習に組み込むかが鍵になります。新規発見や推論に対する評価を何百万の例、何億の軌跡に対して行うのは、根本的な手法改善がなければ現実的ではありません。これはスーパアライメント研究の一部領域で継続的に取り組まれている課題です ⚠️。
人類はここ数年で知的機械の開発において大きく前進しました。数年前には、人間のテキスト入力の多様性に広く対応できるチャットボットは想像しづらかったでしょう。現在は、マルチモーダル入力や多言語の一貫した扱いが可能な複雑なアーキテクチャが存在し、「魔法」を起こせるスケールに到達しています。しかし残る課題は、数兆次元空間で最適ポリシーを見つけるために、人間の知見を巧妙に織り交ぜながら探索を続けることです。
ユーザーが現在感じる不満の核は、モデルの「真の意図」や「真実追究行動」が欠けている点です。問題の根底に深く掘り下げ、確実な証拠で修正を検証するようモデルを動機付ける仕組みを、スケール可能な報酬プログラムとして定義するのは極めて難題です。
とはいえ今のアーキテクチャは高度で、適切に設計すれば多様な入力と多言語を高い整合性で扱えます。必要なスケールには到達していますが、残りは人間の知能と協調して探索を続け、徐々に探索領域を狭めて最適解に近づけていく作業になります 💡。
追加の運用・実践メモ(短めの指針):
- デプロイ時はFP8やblock-FP8の取り扱いに注意。数値精度の微妙な変化が推論挙動に影響することがあるため、検証パイプラインを整備すること。🔧
- 長コンテキストのコスト管理:128Kやそれ以上の文脈を扱う場合、メモリとレイテンシのトレードオフを事前に評価すること。
- 評価:検証可能報酬だけでなく、人間のランダムサンプリングによる質的評価も組み合わせること。
- セキュリティとスキーマ保証:関数呼び出しや外部API連携では、生成時のスキーマ整合性チェック(enforcerなど)を組み込み、脆弱性を減らすこと。⚠️
(注:本文中の参考リンクは原文の出典を保持しています。)