本記事の執筆には Anthropic の Claude とそのリサーチ機能を使用しています。
はじめに
前回、MoEは「専門家の選択」ではないです という記事で、MoE の本質は FFN ブロックの構造化スパース性であり、疎性で減るのは FLOPs とバッチ1デコード時の重み読み出しだけで、メモリ常駐量は総パラメータに従う、という構造の話を書きました。
また、DeepSeek V4 Flash の Dwarf Star 量子化版について調べてみた では、antirez 氏による専用推論エンジン ds4 と、その非対称量子化レシピを紹介しました。
今回はその続編として、静的な構造論から一歩踏み込み、1 つのトークンが embedding から logits まで実際にどう計算されて出力に至るのか、という動的な計算フローを追いかけます。題材は引き続き DeepSeek-V4-Flash の Dwarf Star (ds4) 量子化版です。
そしてもう一つ、実利的なゴールがあります。手元の M5 Max 128GB で、routed expert を Q4 に上げる層を限界まで増やしたい、という話です。全層 Q4 は 128GB に載りませんが、q2 ベースから何層かを Q4 に上げる余地はあります。それが何層なのか、config.json の実数値から試算します。
なお本記事のメモリ計算はすべて試算例であり、実効値は環境依存です。前提と計算式を明示しますので、読者の環境で数字を差し替えて再計算できるようにしています。
まず前回記事の訂正から
前回の Dwarf Star 記事で、V4 Flash のアテンションを MLA(Multi-head Latent Attention)と説明しましたが、一次情報を確認したところこれは誤りでした。お詫びして訂正します。
DeepSeek-V4 テクニカルレポート(arXiv:2606.19348)および Hugging Face の config.json(deepseek-ai/DeepSeek-V4-Flash、commit fd53f94)によれば、V4 Flash は MLA ではなく、次の構成を採っています。
- アテンション: GQA ベース(64 ヘッド、KV は 1 ヘッドを全ヘッドにブロードキャスト)に、Q-LoRA(rank 1024)とグループ化 O-LoRA(rank 1024、8 グループ)を組み合わせた低ランク射影
- 圧縮機構: 最初の 2 層は sliding window(窓 128)、以降は CSA(圧縮率 4、lightning indexer で top-512 選択)と HCA(圧縮率 128)の交互配置
- 残差: mHC(Manifold-Constrained Hyper-Connections、残差ストリーム 4 本、Sinkhorn 20 反復)
- ルーティング: 最初の 3 層はハッシュルーティング(学習済みルックアップテーブルによる静的割当)
つまり V3 世代の MLA + DeepSeekMoE、V3.2 の MLA + DSA という系譜からさらに変わっていて、V4 は圧縮アテンションと mHC を柱とする別物のアーキテクチャと考えるのが正確なようです。以降の説明はこの訂正済みの理解に基づきます。
DeepSeek-V4-Flash の実像(config.json の数値)
まず土台となる数値を押さえます。出典は config.json(commit fd53f94)と DeepSeek-V4 テクニカルレポート(arXiv:2606.19348、2026 年 6 月)です。
| 項目 | 値 |
|---|---|
| 総パラメータ / 活性パラメータ | 284B / 13B |
| 層数(num_hidden_layers) | 43 |
| hidden_size | 4,096 |
| moe_intermediate_size(expert あたり) | 2,048 |
| routed expert 数 / shared expert 数 | 256 / 1 |
| トークンあたり選択 expert 数(top-k) | 6 |
| router スコアリング | sqrtsoftplus + noaux_tc(bias によるロードバランス) |
| routed_scaling_factor | 1.5 |
| アテンション | 64 heads / KV 1 head / head_dim 512 / q_lora_rank 1024 / o_lora_rank 1024(8 グループ) |
| 圧縮アテンション | 層 0–1: sliding window 128、以降 CSA(圧縮率 4)と HCA(圧縮率 128)の交互 |
| RoPE | 非圧縮側 theta 10,000 / 圧縮側 theta 160,000 + YaRN |
| 残差 | mHC(hc_mult 4、Sinkhorn 20 反復) |
| ハッシュルーティング層 | 最初の 3 層 |
| 語彙サイズ | 129,280 |
| MTP 深度(num_nextn_predict_layers) | 1 |
| tie_word_embeddings | false(lm_head は embedding と別テンソル) |
活性 13B の内訳もここから概算できます。routed expert 1 個は SwiGLU の 3 行列(gate/up/down、4,096→2,048→4,096)で 25,165,824 ≈ 25.17M パラメータ。トークンあたり 6 個 × 43 層で約 6.49B、shared expert が全層で約 1.08B、アテンション系その他が約 4.8B、合計約 12.4B となり、公称 13B とおおむね整合します。
参考までに、上位版の V4-Pro との対比も置いておきます(テクニカルレポート記載の範囲で、裏の取れていない項目は割愛します)。
| 項目 | V4 Flash | V4 Pro |
|---|---|---|
| 総 / 活性パラメータ | 284B / 13B | 1.6T / 49B |
| 層数 | 43 | 61 |
| hidden_size | 4,096 | 7,168 |
| routed expert 数 | 256 | 384 |
| moe_intermediate_size | 2,048 | 3,072 |
| o_lora グループ数 | 8 | 16 |
Flash は Pro の単純な縮小版というより、同じ設計思想(圧縮アテンション + mHC + 大規模 MoE)を 128GB 級のローカル機で扱える規模に切り出した構成、と見るのが実態に近そうです。ds4 にも pro 系の分割ビルド(pro-q2-imatrix、pro-q4 の 2 分割など)が存在しますが、本稿では Flash に絞ります。
1 トークンの旅: 全体フロー
デコード時(逐次生成時)に、1 トークンがどう処理されるかを図にしました。右側の注記は Dwarf Star q2 版のビット割当です(後述)。
流れを言葉にすると次の通りです。
- トークン ID で embedding テーブル(129,280 × 4,096、F16)を引き、4,096 次元の隠れ状態を得る
- mHC が残差ストリームを 4 本に拡張する
- 43 層の Transformer ブロックを順に通る。各ブロックは RMSNorm → アテンション → mHC 混合 → RMSNorm → MoE FFN → mHC 混合、という構成
- 最終 RMSNorm を経て lm_head(4,096 × 129,280、embedding とは非共有)で 129,280 次元の logits に射影
- サンプリングで次トークンを 1 つ選ぶ
これを出力トークンの数だけ繰り返すのが自己回帰生成です。1 トークンあたり 43 層 × (アテンション + MoE FFN) の計算が走り、そのたびに必要な重みがメモリから読み出されます。この「読み出し」が後半のメモリ試算とデコード速度の話に直結します。
アテンション部の中身
V4 Flash のアテンションは、長コンテキストのコストを圧縮で抑える設計です。ハードウェア屋の視点では、KV キャッシュという「状態メモリ」をどう間引くか、という話だと捉えると分かりやすいと思います。
- 層 0–1 は窓幅 128 の sliding window アテンションで、直近のローカル文脈だけを見ます
- 以降の層は CSA と HCA が交互に並びます(層ごとの割当は config.json の compress_ratios 配列で指定されています)。CSA は KV を圧縮率 4 で間引いた上で、lightning indexer(64 ヘッド、ヘッド次元 128)が過去トークンから top-512 を選び、そこだけにアテンションします。HCA は圧縮率 128 でさらに大胆に間引いた要約 KV を見ます
- Q 側は Q-LoRA(4,096 → rank 1,024 → 64 ヘッド × head_dim 512)、出力側はグループ化 O-LoRA(8 グループ、rank 1,024)で射影パラメータを低ランク化しています
- RoPE は非圧縮側と圧縮側で base を分けた dual 構成(10,000 / 160,000 + YaRN)です
この圧縮のおかげで、ds4 の README(commit c463029 時点)によれば 1M トークンのフルコンテキストでも KV キャッシュは約 26GB(うち indexer 分が約 22GB)に収まるとされます。MLA とは別のアプローチで KV を小さくしている、というのが V4 の特徴と言えそうです。
もう一つ、層をまたぐ配線が mHC です。通常の残差接続(1 本の残差ストリーム)を 4 本に拡張し、層ごとに学習された混合行列でストリーム間を混ぜます。混合行列は Sinkhorn-Knopp 反復(20 回)で二重確率行列に射影され、信号の発散・消失を防ぐ設計です(arXiv:2512.24880 系の Hyper-Connections の発展形とされています)。推論時のコストは行列が小さいため軽微ですが、GGUF 上は HC 系テンソルとして存在し、Dwarf Star では F16 のまま保持されます。
MoE FFN 部の中身: router → top-6 → expert → 加重和
続いて本題の MoE FFN です。1 層・1 トークンあたりの計算を図にしました。
計算の順序は次の通りです。
- 隠れ状態 h(4,096 次元)を router の線形層(4,096 × 256、F16)に通し、256 個の routed expert それぞれのスコアを得ます。スコア関数は config 上 sqrtsoftplus で、topk_method は noaux_tc です。noaux_tc は V3 で導入された補助損失なしロードバランスの系譜で、選択判定にはバイアス項を加えたスコアを使い、ゲート値そのものにはバイアスを含めない、という方式が踏襲されていると考えられます(実装詳細は Hugging Face の modeling コードが一次情報です)
- スコア上位 6 個の expert を選び、選ばれた 6 個のスコアを正規化してゲート重み g_i とします(norm_topk_prob=true)
- 選ばれた 6 個の routed expert がそれぞれ SwiGLU を計算します。E(h) = W_down · (SiLU(W_gate h) ⊙ (W_up h))、次元は 4,096 → 2,048 → 4,096 です
- shared expert(1 個、同じ SwiGLU 構造)は router を通らず全トークンで必ず計算されます
- 出力は y = shared(h) + 1.5 × Σ g_i · E_i(h) として合算され(routed_scaling_factor=1.5)、残差に加算されます
なお最初の 3 層(層 0–2)だけは router がなく、トークン ID から expert ID を引く静的なハッシュルーティング(tid2eid テーブル)です。この 3 層は「どの expert に行くかが入力トークンで決まっている」特殊な層で、後述の量子化戦略でも扱いを分けて考える余地があります。
前回記事の言葉で言い直すと、256 個の expert は「専門家」ではなく、router が学習したパーティションに従って使い分けられる FFN の断片です。1 トークンは 256 個中 6 個 + shared 1 個、つまり FFN 容量の約 2.7% しか通りません。この極端な疎性が、次のメモリアクセスの話につながります。
プリフィルとデコードで何が違うか
MoE の計算フローを理解する上で、プリフィル(プロンプト一括処理)とデコード(1 トークンずつの生成)の非対称性は外せません。
| 観点 | プリフィル | デコード(バッチ 1) |
|---|---|---|
| 処理単位 | 多数トークンを一括 | 1 トークンずつ |
| expert の活性 | トークンごとに違う 6 個が選ばれ、バッチ全体では大半の expert が起動 | 6 個だけ |
| 律速要因 | 演算(GEMM)寄り | メモリ帯域寄り |
| 読み出す routed 重み | ほぼ全 expert 分 | 6/256 の expert 分のみ |
プリフィルでは、バッチ内の各トークンが別々の expert を選ぶため、活性 expert の和集合はすぐ 256 個に近づきます。ELDR(arXiv:2607.00466)は、MoE のレイテンシが各ステップで起動する expert の和集合サイズで決まると整理しています。MoE-CAP(arXiv:2505.11415)の DeepSeek-R1 での試算では、バッチ 1 なら約 1,040 GB/s 相当の帯域で済む読み出しが、全 expert 活性だと約 18,901 GB/s 相当まで膨らむとされ、疎性の効き方がバッチサイズで劇的に変わることが分かります。
デコード時のメモリアクセスを V4 Flash + Dwarf Star q2 の数字で見てみます。どの expert が選ばれるかは router を計算するまで分からないため、256 個 × 43 層の routed 重みは全て常駐させておき、トークンごとに 6 個 × 43 層分だけを読みます。1 層あたり 6 × 25.17M ≈ 151M パラメータ、q2 ミックス(実効約 2.2 bpw、後述)なら約 42MB、43 層で約 1.8GB です。つまり 1 トークン生成するたびに routed 重みだけで約 1.8GB をメモリから読む計算になります。メモリは総パラメータ、速度は活性パラメータ、という前回の主張の実装レベルの姿がこれです。
計算量の側からも裏を取っておきます。router の行列積は 4,096 × 256 ≈ 1.05M 積和/層と誤差の範囲で、トークンあたりの総 FLOPs は概算で 2 × 活性 13B ≈ 26 GFLOPs です。一方でトークンあたりの重み読み出しは、routed の約 1.8GB に加え、毎トークン必ず読む非 routed 部(shared、attention 系、lm_head)が約 6GB 乗ります。ディスク上の非 routed 重みは約 7.1GB ですが、embedding は該当 1 行しか読まないため、その分を除いた量です。合わせて約 8GB/トークン、演算強度は 26 GFLOPs ÷ 8GB ≈ 3 FLOPs/byte 強しかなく、GPU の機械バランスを大きく下回りますから、デコードが帯域律速であることは数字の上でも裏付けられます(bpw 実効値の揺れがあるため概算です)。
MTP(Multi-Token Prediction)にも触れておきます。V4 Flash は MTP 深度 1 のモジュールを持ち、DeepSeek-V3 世代では第 2 トークンの受理率 85〜90%、TPS で 1.8 倍という数字が報告されています(arXiv:2412.19437 §2.3.3、あくまで V3 の自己申告値です)。ただし ds4 では MTP は experimental 扱いで、README にも高速化はわずかと明記されており、別ファイルの GGUF(約 3.8GB)を追加ロードする形です。本記事のメモリ試算では MTP は載せない前提とします。
Dwarf Star の量子化の工夫
ここからが後半の主題です。ds4 は llama.cpp 互換の GGUF フォーマットを使いつつ、V4 Flash の 43 層固定レイアウトに厳密一致するファイルだけをロードする単一モデル特化エンジンです(mmap ベース、ロード時に厳密検証)。量子化の精度はロードする GGUF のレイアウトで決まり、実行時オプションでは変えられません。
q2 系ビルドのテンソル別ビット割当は次の通りです(DS4 テクニカルレポートおよび README、commit c463029 時点)。
| テンソル | 精度 | 実効 bpw の目安 |
|---|---|---|
| routed expert up/gate | IQ2_XXS | 約 2.06 |
| routed expert down | Q2_K | 約 2.6 |
| shared expert | Q8_0 | 約 8.5 |
| attention projection(Q/KV/O 系) | Q8_0 | 約 8.5 |
| output head(lm_head) | Q8_0 | 約 8.5 |
| router / embedding / compressor / indexer / HC 系 | F16 | 16 |
| norm / attention sinks | F32 | 32 |
見ての通り、徹底的に潰されているのは routed expert だけです。router、shared expert、アテンション、embedding/lm_head、圧縮機構はほぼ無傷で残されています。antirez 氏自身が X で述べている設計思想を要約すると、router と shared は 2bit 化に耐えないが、個々の routed expert は激しく圧縮しても tool calling が実用になる程度に踏みとどまる、というものです。
さらに imatrix(importance matrix)によるキャリブレーションが routed パスに適用されています。約 1M トークンの活性化統計で量子化グリッドを重み付けするもので、antirez/deepseek-v4-gguf の公開比較(Q4 での測定)では、DeepSeek 公式 API の継続 100 件に対する平均 NLL が 0.177357819 → 0.173895148(−1.95%)、ケース勝率 46 → 54、first-token 一致 81 → 83 と改善しています。q2 での q2 対 q2-imatrix の比較は公開されていない点は留意が必要ですが、128GB 機向けの推奨ビルドは q2-imatrix とされています。
フォーマットの中身にも少しだけ踏み込んでおきます。Q8_0 は 32 要素ブロックごとにスケール 1 個を持つ対称形式、Q2_K / Q4_K はスーパーブロック内のサブブロックごとにスケールと最小値を持つアフィン形式で、おおむね w ≈ d·q + m の形で復元されます。IQ2_XXS はこれらと系統が異なり、8 要素ベクトルを E8 格子由来のコードブックに割り当てる方式で、約 2.06 bpw という数字はここから来ています。imatrix は、これらのスケールやコードブック割当の決定を活性化統計で重み付けする位置づけです(実装詳細は ggml / llama.cpp のコードが一次情報です)。なお本稿で言う非対称レシピとは、テンソル種別ごとに精度配分を変えるという意味の非対称性で、量子化式にゼロポイントを持たせる意味での asymmetric quantization とは別の話です。用語が紛らわしいので念のため補足しておきます。
なぜ routed expert だけが潰せるのか。一つの説明は、各 expert がトークン空間の狭いパーティションだけを担当しており、量子化ノイズが 256 個の expert に分散する(1 トークンが触るのは 6 個だけ)ため、モデル全体としての劣化が緩やかになる、というものです。逆に router や shared expert は全トークンが必ず通る単一路であり、ここのノイズは全出力に乗ります。この非対称性こそが Dwarf Star レシピの核心と言えそうです。
なお V4 Flash はネイティブ配布形式からして FP4(routed expert)+ FP8(その他)の混合であり、routed expert は量子化認識学習(QAT)済みと見られます(Unsloth の解説では UD-Q8_K_XL が公式重みとビット一致するとされています)。元から低精度前提で訓練された expert だからこそ、さらに 2bit へ落とす余地があった、という見方もできそうです。
どの層・どのテンソルが量子化に弱いか
Q4 層を増やす前に、量子化感度の定石を整理します。複数の研究・実装から見えてくる傾向は次の通りです。
| テンソル | 低ビット耐性 | 根拠 |
|---|---|---|
| routed expert up/gate | 高い | ds4 の IQ2_XXS 実績、Unsloth dynamic quants |
| routed expert down | 中(前方層に要注意) | Super Weights(arXiv:2411.07191) |
| shared expert | 低い | APEX の分布分析(尖度 13.10、routed の約 4 倍) |
| attention projection | 低〜中 | llama.cpp K-quant の慣行、Unsloth の V3.1 知見 |
| router / gate | 極めて低い | ds4・Unsloth とも F16/高精度維持 |
| embedding / lm_head | 低い | llama.cpp の token-embedding / output 特別扱い |
| norm | 量子化しない | ds4 は F32 |
特に重要なのが Super Weights の知見です。Yu らの研究(arXiv:2411.07191、2024 年 11 月)は、モデルの出力品質を左右する少数の超重要重み(多くのモデルで 6 個以下)が、常に mlp.down_proj にあり、常に前方の層にあると報告しています。この 1 スカラーを壊すだけで perplexity が 3 桁悪化し、生成が崩壊するとされます。原因は SwiGLU が生む massive activation です。Unsloth の DeepSeek-R1 dynamic quant が最初の 3〜6 層の MoE down_proj を高精度に残すのは、この知見を踏まえたものです。
MoE 全体を一律低ビット化した場合の崩れ方も報告されています。Mixtral-8×7B を一律 INT2 にすると平均精度が 70.03% → 34.41% まで落ち、上位 expert だけ精度を戻すと大きく回復する、という結果(arXiv:2512.17073)は、routed expert の低ビット化にも限度があること、そして選択的に精度を戻す価値があることを示しています。Dwarf Star の q2 は IQ2_XXS/Q2_K でギリギリを攻めている構成であり、ここから Q4 へ上げる余地は品質面のアップサイドとして残されている、と読めます。
ここで一つ視点の整理をしておきます。よくある量子化の議論は「どこまで下げても壊れないか」ですが、今回やりたいのは逆で、q2 まで下がっている routed expert を、メモリの許す範囲で Q4 に上げる話です。したがって優先すべきは、q2 で最も痛んでいる(=感度の高い)層から順に Q4 化することになります。下げる話と上げる話では優先順位の向きが逆になる、という点は後の戦略に効いてきます。
パラメータはどこにあるか: 層別の内訳
config.json から層別・テンソル別のパラメータ数を計算すると、次のようになります。
| 構成要素 | パラメータ数 | 総量比 |
|---|---|---|
| routed expert 1 個(3 × 4,096 × 2,048) | 25,165,824(約 25.17M) | ― |
| routed expert 1 層分(× 256) | 約 6.44B | ― |
| routed expert 全 43 層 | 約 277.0B | 約 97.5% |
| shared expert 全 43 層 | 約 1.08B | 約 0.38% |
| attention 系 + indexer + router + mHC + norm(全 43 層) | 約 4.8B(約 110M/層) | 約 1.7% |
| embedding(129,280 × 4,096) | 約 0.53B | 約 0.19% |
| lm_head(非共有) | 約 0.53B | 約 0.19% |
routed expert が総量の約 97.5%(計算値)を占めます。Unsloth の解説では約 96% と表記されており、この差は初期に少数の dense 層が存在する可能性を示唆しますが、config.json の範囲では確認できませんでした。実務上は「routed が 96〜97% 台」と押さえておけば十分と考えられます。
ビット幅ごとの routed expert 1 層分(6.44B パラメータ)のサイズは次の通りです。パラメータ数 × bpw ÷ 8 の単純計算です。
| 精度 | 実効 bpw の目安 | routed 1 層分のサイズ |
|---|---|---|
| q2 ミックス(up/gate IQ2_XXS + down Q2_K) | 約 2.2 | 約 1.8GB |
| Q4_K | 約 4.5 | 約 3.6GB |
| Q8_0 | 約 8.5 | 約 6.8GB |
| F16 | 16 | 約 12.9GB |
表の bpw とサイズは丸め値で、積算には 1.85GB/層(約 2.3 bpw)を用います。43 層で約 79.6GB となり、後述の実ファイルとの突き合わせに使う数字です。1 層を q2 から Q4_K に上げるコストは、この丸めの範囲で約 1.8GB/層です。実ファイルでの裏も取れます。q2-imatrix の公開 GGUF は実サイズ約 86.7GB で、routed の計算値約 79.6GB を引いた残り約 7.1GB が非 routed 部分(Q8_0/F16/F32 混在)に相当します。なお README やプレス記事では約 81GB と丸められていますが、試算は実ファイルの 86.7GB を採るのが安全です。bpw の実効値には量子化ブロックのメタデータ等で ±数% の幅がある点はご了承ください。
128GB にどう収めるか: Q4 層数の試算
いよいよ本題の試算です。先に規模感を押さえておくと、284B を素朴に F16 で持てば約 568GB、公式ネイティブの FP4/FP8 混合をロスレス相当で GGUF 化した UD-Q8_K_XL でも実測約 162GB あり、いずれも 128GB には遠く及びません。量子化レシピの工夫が前提の世界です。
まず器の側、M5 Max 128GB の実効天井を確認します。
macOS の Metal は recommendedMaxWorkingSetSize として GPU に割り当て可能なメモリをおおむね総 RAM の 75%、つまり 128GB 機で約 96GB に制限しており、llama.cpp 系ランタイムはこれを事実上の上限として扱います。この上限は sudo sysctl iogpu.wired_limit_mb=122880 のように引き上げられます(再起動でリセット、SIP 無効化は不要)。OS 側に 8〜16GB は残すのが定石なので、本記事では実効天井を約 118GB と置きます。
KV キャッシュとランタイムの取り分も確保します。V4 の圧縮アテンションのおかげで KV は小さく、1M コンテキストで約 26GB(README 値)ですから、100〜300k 運用なら数 GB 台と見込まれます。ここでは余裕を見て KV + ランタイム + アクティベーションで 15GB を確保します。
以上を積み上げたのが次の図です。
計算を式で書くと次の通りです。
- 実効天井 118GB − KV/ランタイム 15GB = 重みに使える枠 103GB
- 103GB − q2 実ファイル 86.7GB = Q4 化に回せる余地 約 16.3GB
- 16.3GB ÷ 1.8GB/層 ≈ 9.0 → 約 9 層を Q4_K に上げられる
層数を横軸に取ると次のようになります。
| Q4 層数 | 重みファイル | 重み + KV/ランタイム 15GB | 判定 |
|---|---|---|---|
| 0(q2 純正) | 86.7GB | 101.7GB | 可(要 wired_limit 引き上げ) |
| 6(純正 q2-q4 相当) | 97.5GB | 112.5GB | 可 |
| 9 | 102.9GB | 117.9GB | 可(天井 118GB とほぼ一致) |
| 10 | 104.7GB | 119.7GB | KV 枠を 3GB 程度絞れば可 |
| 43(全層 Q4) | 約 164GB | 約 179GB | 不可 |
結論としては、9 層が目安、コンテキストを 100k 程度に絞って KV 枠を削れば 10 層まで、という見立てになります。ちなみに ds4 には既製の q2-q4-imatrix ビルド(末尾 6 層=層 37–42 の routed expert だけ Q4_K)が存在し、上の表の 6 層の行がまさにそれです。つまりやりたいことの既製版が 6 層版としてすでにあり、本試算はそこからあと 3〜4 層積める、という話になります。
なお全層 Q4 の約 164GB は本試算の線形モデルの値で、Unsloth の UD-Q4_K_XL 実測は約 155GB です。レシピ(非 routed 部の精度配分)が異なるための差と考えられます。
副作用にも触れておきます。Q4 化した層はトークンあたりの読み出し量が増えます。9 層 Q4 化で routed 読み出しは約 1.8GB → 約 2.2GB(+2 割強)ですが、前述の通りトークンあたりの総読み出しは非 routed 分を含めて約 8GB ですから、全体で見れば +5% 弱に留まります(図 4)。帯域律速の仮定なら、デコード速度の低下も数%程度、前回記事の M5 Max 実測(約 26 t/s)基準で 25 t/s 前後に収まる見込みです。routed だけを見て 2 割減と早合点しかけたのですが、総読み出しベースで見直すとかなり分の良い取引でした。メモリと数%の速度で精度を買う、という整理になります。
どの層から Q4 に上げるか、どう作るか
残る問題は 2 つ、層の選び方と作り方です。
層の選び方について、V4 Flash 固有の層別感度データは公開されておらず、以下は定石からの仮説にとどまります。前述の通り「上げる」話なので、q2 で最も痛んでいる層を優先するのが効率的です。候補の考え方は次の通りです。
- 純正踏襲: まず ds4 純正の末尾 6 層(層 37–42)をそのまま使う。出力に近い層の routed expert を高精度化するという antirez 氏の経験的判断が入っていると考えられ、既製 GGUF + imatrix 済みという実務上の利点が大きい
- 末尾を延長: 7〜9 層目として層 34–36 を追加し、末尾 9 層を Q4 とする案。純正の思想の素直な延長
- 前方に振る: Super Weights の知見(超重要重みは前方層の down_proj に集中)を重視し、ハッシュルーティング層(層 0–2)を除いた前方層(層 3–8 あたり)の down_proj を含めて Q4 化する案
候補を層マップにするとこうなります。色分けはあくまで仮説段階の整理です。
2 と 3 のどちらが効くかは、正直なところ実測しないと分かりません。私の用途では SystemVerilog/UVM コード生成の構文正確性と tool calling の信頼性が指標になるので、自前ベンチで末尾延長案と前方案を突き合わせる予定です。判断のしきい値としては、(a) q2-q4 6 層版と 9 層版でベンチに有意差が出るか、(b) wired_limit 引き上げ後に Activity Monitor のメモリ圧が黄色・赤にならないか、(c) 100k コンテキストでのデコード速度が許容範囲(20 t/s 台)に収まるか、(d) コンテキスト長を振ったときの t/s 推移が素直か(KV とディスク I/O の影響の切り分け)、の 4 点を見るつもりです。結果は、横軸メモリ・縦軸ベンチスコアのトレードオフ散布図と、層 × テンソル種別の感度ヒートマップに整理して続報で共有する予定です。環境・量子化設定・スクリプトも明示して、再現できる形にします。差が出なければ純正 6 層で止めてコンテキスト余地に回す、明確に効くなら KV を削ってでも 10 層まで押す、という分岐です。
作り方について、ds4 は実行時に層別ビット幅を変えられないため、次の 2 経路になります。
- gguf-tools でのオフライン再量子化: llama.cpp の llama-quantize が持つ
--tensor-typeの正規表現指定に相当する層別・テンソル別のビット割当を行い、V4 Flash の固定レイアウトに合わせた GGUF を再生成する経路 - ds4-splice での継ぎ接ぎ: ds4 付属の splice ユーティリティ(commit 93d9d96 時点)で、q4-imatrix 配布物(256GB 機向け)から任意の層を抜き出し、q2-imatrix ベースに層単位で移植する経路。純正 q2-q4 ビルドもこの方式の産物と見られ、imatrix 適用済みの Q4 テンソルをそのまま流用できるのが利点
いずれの場合も、ds4 がロード時にレイアウトを厳密検証するため、テンソル名・形状・順序の完全一致が前提です。splice の詳細仕様は更新が速いので、実行時点の README を正とするのが安全です。
なお 128GB 一台に収まらない構成(例えば全層 Q4)を諦めきれない場合、ds4 には 2 台の M5 Max を Thunderbolt 5 で接続して Q4 版を分割ロードする分散モード(8,192 トークンで prefill 約 583 t/s、生成約 25 t/s との README 値)や、routed expert を SSD からストリーミングするモードも用意されています。ただし後者は速度低下が大きく、常用には向かないと見ています。
わかっていないこと
今回の調査で裏が取れなかった点を明記しておきます。
- V4 Flash 固有の Q4 対 q2 の品質差(perplexity やベンチマーク)は一次情報が見つかりませんでした。二次情報には「full Q4 の 95〜98% を維持」といった主張もありますが、根拠データを確認できていません。imatrix の −1.95% NLL 改善も Q4 での測定であり、q2 側の絶対的な品質水準は自前計測が必要です
- routed 比率の計算値 97.5% と Unsloth 表記の約 96% の差(初期 dense 層の有無)は config.json の範囲では解消できませんでした
- 非 routed 部分の内訳(約 7.1GB)はファイル実測との差分からの逆算で、テンソル別の厳密な積み上げとは ±1〜2GB 程度ずれる可能性があります
- 実効天井 118GB、KV/ランタイム 15GB はいずれも余裕を見た仮置きで、実機では起動ログのワーキングセットと Activity Monitor で詰める前提です
- どの層から Q4 化すべきかの優先順位は仮説段階です。実測結果は続報で共有できればと思います
まとめ
- MoE の推論は、トークンごとに router が 256 個中 6 個の expert を選び、shared 1 個と合わせた SwiGLU の加重和を 43 層繰り返す流れです。デコード時は 1 トークンあたり routed だけで約 1.8GB、非 routed 込みで約 8GB(q2 時)の重み読み出しが走り、演算強度は 3 FLOPs/byte 程度という帯域律速の世界で、メモリは総パラメータ・速度は活性パラメータという前回の話が実装レベルでも数字でも確認できました
- V4 Flash は MLA ではなく、CSA/HCA の圧縮アテンション + Q-LoRA/O-LoRA + mHC + ハッシュルーティング初期層という構成でした。前回記事の記述を訂正します
- Dwarf Star の量子化は、全トークンが通る単一路(router、shared、attention、embedding/lm_head)を守り、ノイズが 256 個に分散する routed expert だけを 2bit 台まで潰す非対称レシピです
- routed expert は総パラメータの約 97.5% を占め、1 層を q2 → Q4_K に上げるコストは約 1.8GB/層です。M5 Max 128GB では、wired_limit 引き上げと KV 15GB 確保の前提で約 9 層(KV を絞れば 10 層)まで Q4 化できる試算となりました。純正 q2-q4 ビルド(6 層)にあと 3〜4 層積める計算です
- 実現手段は gguf-tools での再量子化か ds4-splice での層単位移植で、どの層を選ぶかは末尾延長案と前方 down_proj 案を実機ベンチで比較する予定です
Appendix: 出力トークンはどこで増えるのか
本文の図 1 を見て、「1 トークン入れて 1 トークン出るなら、出力が入力より長くなるのはどの計算のせいか」という疑問を持つ方がいるかもしれません。答えを先に言うと、ネットワークの内部には出力トークンを増やす計算は一つもありません。増えるのはモデルの外側のループです。
Transformer の 1 回の順伝播は長さを保存します。N 個のトークンを入れると、各位置に対して「その次に来るトークン」の logits が N 組出るだけで、生成時に使うのは最後の位置の 1 組だけです。そこからサンプリングで 1 トークンを選ぶ。ここまでが図 1 に描いた 1 周です。
出力が入力より長くなるのは、この 1 周を自己回帰ループで回すからです。入力 N トークンをプリフィルで一括処理し、最後の位置の logits から 1 個目を生成する。その 1 個を系列の末尾に追記し、追記したトークンだけを embedding lookup から再び 43 層に通す(過去の文脈は KV キャッシュ参照)。2 個目を生成してまた追記する。この繰り返しで、自分の出力が次の入力になるため、系列は 1 周につき 1 トークンずつ伸びていきます。図 1 で言えば、いちばん下の「出力トークン」から先頭の「入力トークンID」へ戻る矢印が省略されている、と考えてください。
どこの計算で増えるかを厳密に言うなら、サンプリング直後の「末尾に追記」というただの配列操作であって、行列積のどこでもありません。計算グラフ側で唯一伸びるのは KV キャッシュで、1 周ごとにエントリが 1 つ増え、アテンションが参照する過去がその分だけ長くなります。本文のプリフィルとデコードの帯域律速の話は、まさにこのループのデコード側 1 周あたりのコスト(重み読み出し約 8GB)を数えていたことになります。
ループが止まるのは、モデルが EOS(終端トークン)をサンプリングしたとき、または上限トークン数に達したときです。EOS をどこで出すかは学習で身につけた振る舞いなので、出力は入力より長くも短くもなり得ます。
なお本文で触れた MTP(深度 1)を使う場合は、1 回の順伝播で 2 トークン目まで下書きし、受理されれば 1 周で 2 個進みます。とはいえ原理は同じ自己回帰で、出力を入力に戻すループが長さを作る、という構図は変わりません。
Appendix B: 過去のトークンの情報はどこにあるのか
Appendix A の続きとして、「新しい 1 トークンを作るには過去のトークンの情報も必要なはずだが、それはどこに入っているのか」という疑問にも答えておきます。結論から言うと、過去の情報が現在のトークンに流れ込む入口はアテンションただ一つで、過去そのものは KV キャッシュに住んでいます。
層を構成する要素のうち、MoE FFN、RMSNorm、mHC、embedding、lm_head は、いずれも各位置を独立に処理する演算で、過去を参照しません。expert が変換するのも「今の隠れ状態 1 本」だけです。位置をまたぐ計算はアテンションだけ、というのが Transformer の設計です。
仕組みは次の通りです。過去の各トークンが処理されたとき(プリフィルや過去のデコード周回)、各層でそのトークンの Key と Value が計算され、KV キャッシュに保存されています。新しいトークンの周回では、現在の隠れ状態から Query を作り、キャッシュ内の全 Key との内積でスコアを取り、softmax で重み付けして、対応する Value の重み付き和を取ります。この重み付き和が、過去の情報が今の表現に混ざる瞬間です。
Appendix A で「計算グラフで唯一伸びるのは KV キャッシュ」と書いたのは、この過去の置き場が 1 周ごとに 1 列ずつ増える、という意味でした。キャッシュが無ければ、毎周、過去の全トークンを 43 層で再計算することになります。アテンションが必要とする K と V だけを貯めておく、というのが KV キャッシュという最適化の正体です。
二つ補足します。第一に、キャッシュに入っているのは生のトークンではなく、各層が作った学習済みの表現です。第二に、層 L における過去トークンの K/V には、それより下の層のアテンションでさらに昔の文脈が既に混ざっています。層を重ねるほど文脈の統合が深まるのは、この積み重ねのためです。
なお V4 Flash は、過去を全部そのまま見るわけではありません。本文のアテンション章の通り、層 0–1 は直近 128 トークンの窓だけを見て、CSA は 4 倍圧縮した KV から lightning indexer が関連の深い top-512 を選んで参照し、HCA は 128 倍圧縮の要約を見ます。1M コンテキストでも KV キャッシュが約 26GB で済むのは、この「過去の読み方」の圧縮のおかげです。
ところで、この「位置をまたぐ計算はアテンションだけ」という骨格には、由来となった宣言があります。2017 年に Transformer を提案した論文のタイトル、Attention Is All You Need(Vaswani et al., arXiv:1706.03762)です。それ以前の系列モデルでは、過去の情報を運ぶ主役は RNN/LSTM の再帰(隠れ状態を 1 ステップずつ引き回す方式)や畳み込みで、アテンションはその補助機構という位置づけでした。この論文は、再帰も畳み込みも捨てて、系列方向の情報のやり取りをアテンションだけに任せる、という設計を宣言したもので、その判断が 9 年後の V4 Flash にもそのまま骨格として残っています。なお all you need と言いつつ FFN や正規化も実際には必要ですから、厳密には「系列方向の情報混合に関してはアテンションだけで良い」という趣旨です。CSA/HCA や sliding window も、この唯一の入口の「読み方」を効率化した変種であって、入口が一つという骨格は変わっていません。
計算機の側から見ると、このタイトルは一つのトレードオフの選択でもありました。RNN は過去を固定サイズの隠れ状態に圧縮して運ぶため、状態メモリは O(1) で済みますが、逐次処理のため学習の並列化が困難でした。Transformer は過去を圧縮せずすべて残して毎回読み返す方式を選び、学習の並列化で大規模化競争に勝った代わりに、KV キャッシュが 1 周ごとに伸び、デコードが帯域律速になる世界を引き受けました。本文と Appendix で数えてきたメモリと帯域の試算は、言ってみれば 2017 年のこの設計判断の請求書を、9 年後のローカルマシンで精算している作業とも言えます。
参考資料
- DeepSeek-AI, DeepSeek-V4 Technical Report, arXiv:2606.19348(2026 年 6 月)
- deepseek-ai/DeepSeek-V4-Flash, Hugging Face, config.json(commit fd53f94、2026 年 7 月時点)
- antirez, DS4 — DwarfStar 4 Technical Report / README(commit c463029、2026 年 7 月時点)
- antirez/deepseek-v4-gguf, Hugging Face(imatrix 比較データ、2026 年 7 月時点)
- ds4-splice ユーティリティ(commit 93d9d96 時点)
- Yu et al., The Super Weight in Large Language Models, arXiv:2411.07191(2024 年 11 月)
- DeepSeek-AI, DeepSeek-V3 Technical Report, arXiv:2412.19437(2024 年 12 月)
- Vaswani et al., Attention Is All You Need, arXiv:1706.03762(2017 年 6 月)
- MoE-CAP, arXiv:2505.11415(2025 年 5 月)
- ELDR, arXiv:2607.00466(2026 年 7 月)
- Mixtral の低ビット量子化と選択的復元に関する研究, arXiv:2512.17073(2025 年 12 月)
- MoEQuant, arXiv:2505.03804(2025 年 5 月)
- APEX(localai-org/apex-quant、2026 年時点)
- Unsloth, DeepSeek-R1 Dynamic Quantization ブログ(2025 年 1 月)および DeepSeek-V4 GGUF 解説(2026 年時点)
- HyperDFlash, arXiv:2606.26744(2026 年 6 月)









