JA EN
体系モデル系統図鑑
·無料·12分で読めます

DeepSeek系を1から — MoEと蒸留で殴り込んだ系譜

MoE・MLA・GRPO・蒸留という4つの道具でオープンLLMの勢力図を塗り替えたDeepSeekの系譜を、V2/V3/R1の設計判断に沿って前提知識ゼロから解説。話題になった学習コストの数字の読み方と、蒸留モデルの正しい使いどころまで。

対象textタスクmodel-guideモデル系統deepseek

全社員を会議に呼ぶ会社と、担当者だけ呼ぶ会社

ある会社では、案件の打ち合わせに毎回全社員が出席します。法務の話でも経理の人が座っている。別の会社では、議題ごとに関係する数人だけを呼びます。ただし呼ばれなかった社員も雇い続けています——給料は全員分かかる。

前者が普通のニューラルネット(dense モデル)、後者が MoE(Mixture of Experts、混合エキスパート) です。DeepSeekというモデル群を理解する入口はここにあります。彼らは「大きいのに1回あたりが安い」を、この会議の呼び方の違いで実現しました。

そしてもう1つ、この会社には特徴があります。ベテランが案件をこなす様子を新人に大量に見せて、新人だけで似た働きができるようにした。これが蒸留(distillation)で、DeepSeek-R1の派生モデルとして配られたものの正体です。

系譜: V2 → V3 → R1

大まかに3世代です。

その後もV3・R1には改訂版が出ていますが、骨格はこの3世代でほぼ説明できます。

設計判断1: MoE —「総数」と「活性数」を分ける

MoEでは、Transformerブロックの中の全結合層(FFN)を、小さなFFNの集まり(エキスパート)に置き換えます。トークンごとにルーターが「どのエキスパートに送るか」を点数付けし、上位k個だけを実際に通します。

CtokenNact,MweightsNtotalC_{\text{token}} \propto N_{\text{act}}, \qquad M_{\text{weights}} \propto N_{\text{total}}
(1)

日本語に直すと、1トークンを処理する計算量は「その回に動いたパラメータ数」に比例し、GPUに載せておくメモリは「総パラメータ数」に比例する、ということです。V3なら計算は37B相当なのに、メモリは671B相当を用意しなければならない。この非対称性がMoEの得と損の全部です。

DeepSeekMoEの工夫は2つ。1つはエキスパートを細かく割ること。大きいエキスパート8個から1個選ぶより、小さい64個から8個選ぶほうが組み合わせが桁違いに増え、役割分担が細かくなります。もう1つは共有エキスパート。どのトークンも必ず通る係を用意して「誰にでも要る一般知識」を集約させれば、残りの専門家は専門に集中できます。V3のMoE層は共有1個+ルーティング対象256個から8個、という構成でした。

問題はルーターが偏ることです。人気のエキスパートにトークンが集中すると、残りは遊んだまま学習されません。従来は「均等に使え」という補助損失を足して矯正しますが、これは本来の目的(次のトークンを当てる)を歪めます。V3が採ったのは 補助損失なしの負荷分散——エキスパートごとの小さなバイアスをルーターの点数に足し引きし、混みすぎたら下げ、空いていたら上げる。バイアスは選択にだけ効いて勾配には混ざらないので、損失関数は汚れません。

FIG 1ルーターがエキスパートに付ける点数の分布。尖らせると常に同じ数人だけが呼ばれ(負荷が偏る)、平らにすると誰でもいい状態になって専門分化が起きない。この綱引きを調整するのが負荷分散の仕事です

MoE自体の仕組みはMixture of Experts を1から理解するで扱っています。

設計判断2: MLA — KVキャッシュを畳む

生成中のLLMは、過去のトークンのKeyとValueを覚えておきます(KVキャッシュ)。これが長文で効いてくる。普通のマルチヘッド注意では、1トークン1層あたり「ヘッド数 × ヘッド次元 × 2(KとV)」の数値を保存します。

MLA(Multi-head Latent Attention) は、KとVをそのまま持たず、1本の低次元ベクトルに圧縮して保存します。使うときに行列を掛けて元の形に戻す。低ランク近似そのものです。

l2nhdh通常のMHA    l(dc+dr)MLA\underbrace{l \cdot 2\,n_h d_h}_{\text{通常のMHA}} \;\longrightarrow\; \underbrace{l \cdot (d_c + d_r)}_{\text{MLA}}
(2)

ll は層数、nhn_h はヘッド数、dhd_h は1ヘッドの次元、dcd_c は圧縮後の潜在ベクトルの次元、drd_r は後述する位置情報用の小さな取り分です。言い換えると、ヘッドの本数だけ膨らんでいたキャッシュを、ヘッド数と無関係な1本の細いベクトルに置き換えたということ。V2の論文は、同社の dense な67Bモデルと比べてKVキャッシュを93.3%削減したと報告しています。

FIG 2rank を下げると保存すべき数値の量が急に減り、それでも元の行列はかなり復元できる。MLAがKVキャッシュに対してやっているのは、まさにこの取引です

ひとつ厄介なのが位置情報です。RoPE(回転位置埋め込み)は位置に応じてKeyを回すので、「圧縮したまま計算をまとめる」トリックと相性が悪い。そこでMLAは、RoPEを掛ける専用の小さな次元だけを切り出して別に持つ(decoupled RoPE)という妥協をしています。drd_r はその分です。KVキャッシュの見積もり方はKVキャッシュを1から理解するが詳しいです。

V3の学習側と、コスト議論の読み方

V3で目立つのは、モデルより訓練インフラです。行列積をFP8(8ビット浮動小数)で回し、accumulate や正規化など壊れやすい所だけ高精度に残す混合精度。パイプライン並列の空き時間に通信を潜り込ませるDualPipe。そして次の1トークンではなく次の2トークンを予測させて学習信号を増やす Multi-Token Prediction。

ここから、よく引用される数字が出ます。技術報告書は総学習を 278.8万 H800 GPU時間、GPU 1時間あたり2ドルという仮定を置いて約557.6万ドルと記しています。ただし報告書自身が、これは最終的な学習実行だけの額であり、アーキテクチャ・アルゴリズム・データに関する事前研究やアブレーションの費用を含まない、と明記しています。

読むときの注意は3つ。仮定価格であって実際の支出でもクラスタの購入費でもないこと。V3は活性37BのMoEなので密な671Bとは必要FLOPsが桁で違い、「671Bを557万ドルで」と読むと誤読になること。失敗した実行・データ整備・人件費が入っていないこと。それでも設計通りに完走させた事実は残ります。驚くべきなのは金額そのものより、FP8で大規模学習を安定させた工程の方です。

R1: 教師なしで殴ったら思考が生えた

R1の出発点は R1-Zero という実験です。V3-Base に対して、お手本(教師あり微調整)を一切与えず、強化学習だけを回しました。報酬は人間の好みを学習したモデルではなく、規則ベース——数学なら答えが合っているか、コードならテストが通るか、あとは決められた形式を守っているか。報酬モデルを使わないので、モデルが採点者の癖を突く「報酬ハッキング」が起きにくくなります。

最適化には GRPO を使います。通常のPPOが必要とする価値関数(もう1つ別のモデル)を捨て、同じ問題に GG 個答えさせて、その集団の中での相対評価をそのまま学習信号にします。

Ai=rimean(r1,,rG)std(r1,,rG)A_i = \frac{r_i - \operatorname{mean}(r_1,\dots,r_G)}{\operatorname{std}(r_1,\dots,r_G)}
(3)

rir_iii 番目の回答の得点、AiA_i はその回答をどれだけ強めるかの度合いです。つまり 「同じ問題への他の自分の回答より上手くできたか」だけを見る。絶対点数の基準を持たなくていいので、価値関数モデルの分だけメモリと計算が浮きます。

結果として、誰も教えていないのに回答が長くなり、途中で「待てよ」と検算を挟むような振る舞いが現れました。ただしR1-Zeroは読みにくく、日本語と英語が混ざるなどの実用上の問題を抱えます。そこで製品版R1は、少量の整った長い思考例で冷やし始め(cold start)してからRLを回し、そこから良い出力を選り分けて再度SFT、最後にもう一度RL、という4段構えで整えられました。強化学習で言語モデルを整える一般論は指示チューニングとRLHFを参照してください。

蒸留モデル——名前に騙されない

R1と一緒に配られた DeepSeek-R1-Distill-* は、R1ではありません。R1に大量の問題を解かせて集めた約80万件の回答で、Qwen2.5系とLlama系の既存モデルを教師あり微調整しただけのものです。RLはかかっていません。サイズは1.5B/7B/8B/14B/32B/70Bの6本。

論文の重要な発見は、小さいモデルに直接大規模RLを回すより、大きい推論モデルから蒸留したほうが強いというものでした。推論の型は、自力で発見させるより真似させたほうが安上がりだということです。

実務上の意味は大きく2つあります。1つは動かしやすさ。中身はQwenやLlamaのアーキテクチャなので、vLLMでもllama.cppでも既存の推論スタックがそのまま使えます。もう1つはライセンス。R1本体はMITですが、蒸留版は土台のモデルの条件を引き継ぎます。Llama由来の8B/70BにはLlamaのライセンス条項が付いてくる。ここは配布・商用判断で必ず確認してください。

# 蒸留版は「普通のQwen/Llama」として動く。思考タグの扱いだけ特殊
from vllm import LLM, SamplingParams

llm = LLM(model="deepseek-ai/DeepSeek-R1-Distill-Qwen-14B")
out = llm.generate(
    ["<|User|>12x + 7 = 43 を解いて<|Assistant|><think>\n"],
    SamplingParams(temperature=0.6, max_tokens=4096),  # 思考の分だけ長く取る
)
text = out[0].outputs[0].text
answer = text.split("</think>")[-1].strip()   # 表示するのは </think> 以降だけ

現場ではこう使う

MLOps/推論基盤の担当者が自社GPUで動かす構成を決めるとき、最初に効くのが先の「活性 vs 総数」の非対称性です。V3級のMoEは活性37Bでも、重みはFP8で0.6TB超。80GBのGPU 1枚に載る話ではありません。「37Bだから4bit量子化すれば1枚で」という見積もりは、ここを取り違えた典型的な事故です。触るのは --tensor-parallel-size / --enable-expert-parallel(vLLM)、--max-model-len、そしてMLA対応バックエンドが有効かどうかです。

アプリ開発者が推論モデルをプロダクトに繋ぐときの落とし穴は3つ。第一に max_tokens を通常のチャット感覚で1024などに切ると、思考の途中で打ち切られて答えが1文字も出ません。第二に <think>...</think> はユーザーに見せないだけでなく、次のターンの履歴にも入れないのが公式リポジトリの推奨です(入れると文脈が思考で埋まり、挙動も崩れます)。第三に、公式は温度を0.6前後、システムプロンプトを使わず指示はユーザー側に書く、という運用を勧めています。greedy(温度0)は同じ語の反復に落ちやすい。

評価担当が蒸留版を検討するときは、名前のサイズだけで判断しないことです。1.5Bと7Bの土台は Qwen2.5-Math で、数学以外の一般タスクでは素直に伸びません。そして社内報告で「DeepSeek-R1をローカルで動かした」と書くとき、それが671Bの本体なのか7Bの蒸留版なのかを必ず区別してください。この取り違えは、公開直後に世界中で起きました。

まとめ

コメント

コメントにはログインが必要です