単一方向ステアリング・投機的デコード・評価基盤 ― DwarfStar の周辺ツール総ざらい【第8回/全8回・完】
DeepSeek V4 専用推論エンジン DwarfStar(ds4) を読む連載の最終回。本流から外して温存してきた「実験機構」と「周辺ツール」を一気に扱います。directional steering、MTP 投機的デコード、
ds4-eval/ds4-bench、そして自前のデータ構造まで。
連載「ds4.c を読み解く」全8回
- 第1回 なぜ専用エンジンを書くのか
- 第2回 非対称2bit量子化とimatrix
- 第3回 Metalグラフと圧縮KV
- 第4回 ディスクKVキャッシュ
- 第5回 サーバとDSMLツール呼び出し
- 第6回 TCPパイプライン分散推論
- 第7回 ネイティブエージェント
- 第8回 ステアリング・MTP・評価基盤(本記事)
TL;DR
-
directional steering: 「拒否は単一方向で媒介される」論文の応用。verbose/succinct 例の平均差分で方向ベクトルを抽出し、
y = y - scale·dir·(dir·y)を FFN/attn 出力に射影。ファインチューニングなしで冗長さやドメイン拒否を制御。 - MTP 投機的デコード: マルチトークン予測ドラフト+ターゲット検証。confidence margin ゲート付き。現状わずかな高速化に留まる理由をコードで説明。
- ds4-eval: GPQA Diamond / SuperGPQA / AIME2025 / COMPSEC を92問埋め込んだ回帰スイート。リーダーボードではなく「推論パスが壊れていないか」の検査。
- ds4-bench: 全体平均でなくコンテキストフロンティアごとの瞬間スループットを計測。
- エンジン以外も自前:
rax(基数木)、linenoise(REPL)、独自トークナイザ、official-vector 回帰テスト。
1. directional steering: 1本のベクトルで挙動を曲げる
1-1. アイデア
論文 Refusal in Language Models Is Mediated by a Single Direction の核心は、「モデルのある挙動(拒否など)は、活性化空間の単一方向で媒介されることがある」という観察です。DwarfStar はこれを実装し、ファインチューニングなしでモデルの挙動を曲げます。
You can use it to make the model more or less verbose, less likely to answer programming questions if it is a chatbot for your car rental web site ... much faster than fine-tuning. This is also useful for cybersecurity researchers who want to reduce a model's willingness to provide dual-use or offensive security guidance.
1-2. 方向の抽出
dir-steering/tools/build_direction.py は、対になるプロンプト集合(例: verbose な例 vs succinct な例)の活性化を比較します。
# build_direction.py(概念): N_LAYER=43, N_EMBD=4096
# 各ペアで活性化をキャプチャし、層ごとに平均
for layer in range(N_LAYER):
good_mean = mean(good_activations[layer]) # 望む状態(例: succinct)
bad_mean = mean(bad_activations[layer]) # 対照(例: verbose)
direction = normalize(good_mean - bad_mean) # 平均差分 → 正規化
# オプション: 対照平均への射影成分を除去(直交化)
if orthogonalize:
base = normalize(bad_mean)
direction = normalize(direction - dot(direction, base) * base)
活性化のキャプチャは Metal グラフのダンプ機構(環境変数 DS4_METAL_GRAPH_DUMP_*)で、層ごとの ffn_out または attn_out を吸い出します。出力は2ファイル。
-
verbosity.json: メタdata(shape[43, 4096]、component、正規化フラグ) -
verbosity.f32: 43層 × 4096 float のフラットバイナリ(層メジャー、約688KB)
1-3. 推論時の適用
エンジンは、各層のアテンション/FFN 出力に方向を射影して引きます。
// ds4.c: directional steering の射影(CPU 経路)
const float *dir = dirs + (uint64_t)il * DS4_N_EMBD; // この層の方向
for (each row xr) {
float dot = 0.0f;
for (i) dot += xr[i] * dir[i]; // 射影量 = dir·x
const float coeff = scale * dot;
for (i) xr[i] -= coeff * dir[i]; // x = x - scale·(dir·x)·dir
}
式は y = y - scale · dir · (dir·y)。これは「活性化ベクトル y から、方向 dir 成分を scale 倍だけ差し引く」射影操作です。
dir (この層の方向ベクトル)
↑
│ y (活性化)
│ ╱
│ ╱
(dir·y)│ ╱ scale=1 で dir 成分を完全に除去すると y' は dir と直交
│ ╱
│ ╱
└────────────→ y' = y - scale·(dir·y)·dir
dir 成分を差し引いた残り
- 正のスケール: その方向を抑制(例: 冗長さを抑える)
- 負のスケール: その方向を増幅(例: より冗長に)
適用箇所は engine option(ds4.h)の directional_steering_attn / directional_steering_ffn で attn 出力・FFN 出力それぞれにスケール指定できます。README は「FFN 出力が最初のターゲットとして通常最良」としています。Metal 側は metal_graph_apply_directional_steering_ffn/attn がグラフに組み込まれ、HC 展開の前段で適用されます。重みもファインチューニングも変えず、forward pass に1本のベクトル射影を足すだけで挙動を曲げられるのが強みです。
2. MTP 投機的デコード: なぜ「わずかな高速化」なのか
2-1. 位置づけ
MTP(Multi-Token Prediction)は DeepSeek V4 のオプション機構で、置換サンプラではなく投機的ドラフタです。コードのコメントが端的です。
MTP in DeepSeek V4 is a speculative drafter, not a replacement sampler. The target model still defines the exact output stream.
サイクルは「(1) 通常のターゲットトークンを1つ受理 → (2) MTP ブロックに短い続きを提案させる → (3) ターゲットモデルが複数提案位置をまとめて検証」という流れ。提案が役立つのは、ターゲットが複数位置を一括検証できる場合だけです。
2-2. ドラフトと検証
エントリは ds4_session_eval_speculative_argmax()。MTP は独立した小さな raw SWA キャッシュとピンポンバッファ(mtp_state_hc / mtp_next_hc)を持ち、ドラフトトークンを再帰的に生成します。MTP の最初のドラフトがターゲット logits の argmax と食い違えば、即座に first_token だけ出して打ち切ります(無駄打ちを避ける)。
2-3. confidence margin ゲート
ドラフトが2トークンに達したとき、トップ2 logits の差(margin)が閾値(既定 3.0、--mtp-margin)未満なら、検証せず first_token だけ出します。
// 概念: 自信が低ければ検証コストを払わない
if (mtp_last_margin < mtp_margin_threshold) {
return n_accept; // 低確信 → 高速パスで 1 トークンのみ
}
サイクル全体の判定フローはこうです。
2-4. なぜ速くならないのか
- 全ドラフト成功時のみ、ドラフト数に比例して高速化(例: 2トークンで2倍)。
- margin ゲートが発火すると1トークンだけ → 高速化ゼロ(しかもドラフトの計算は無駄)。
- 検証失敗時はドラフト作業がすべて無駄。
- 多くのプロンプトは確信度が低く(margin < 3.0)、高速パスに落ちる。
- ターゲット+MTP のデュアルキャッシュ管理でメモリ帯域への圧力が増す。
README も「現状の MTP/投機的デコードは correctness-gated で、せいぜいわずかな高速化、生成速度の意味ある向上ではない」と明言。--mtp MTP.gguf --mtp-draft 2 で有効化でき、貪欲デコードでのみ有用な実験的パスです。「投機的デコードを真面目に実装したが、このモデル・この環境では効きが薄い」と正直に示している点こそ、回帰検証を重んじるこのプロジェクトらしい部分です。
3. ds4-eval: 壊れていないかを問う評価スイート
ds4-eval(約4,000行)は、リーダーボードランナーではなく実モデル統合の回帰スイートです。92問が埋め込まれています。
- 前半75問: GPQA Diamond 25 + 監査済み SuperGPQA 25 + AIME2025 25 を交互配置
- 後半17問: 公開 CVE から縮約した COMPSEC(C/C++ の脆弱性箇所特定。エクスプロイトではなく「防御コードの欠陥が入る最良の1行」を答える)
./ds4-eval -m ds4flash.gguf --trace /tmp/ds4-eval.txt
実 GGUF をロードし、DS4 チャットプロンプトをレンダリングし、サンプルトークンを分割画面 TUI でストリームし、最終回答を採点します。狙いは「カーネル・量子化・プロンプト整形・KV・ツールストリームに変更を入れた後、DeepSeek V4 Flash が同じ推論パスで、難しい科学・広い知識・厳密な数学・セキュリティコードの代表的ミックスを依然として解けるか」を問うこと。満点 92/92 は想定されておらず、ハードな能力回帰スイートとして使います。
決定的な回帰ゲートも用意されています。
./ds4-eval -m ds4flash.gguf --plain --questions 4 --tokens 2048 --temp 0 --seed 1
q1..q4 の生成トークン数がベースラインと一致するかを見る(例: q1 は PASSED/2048トークン/B・B)。推論変更による生成ドリフトを早期に検出する仕掛けです。--regrade-trace で、モデルを再ロードせず過去トレースに対して採点器だけ再適用し、評価器の変更を監査することもできます。
4. ds4-bench: フロンティアごとの瞬間スループット
ds4-bench(約600行)は、全実行の平均ではなくコンテキストフロンティアごとの瞬間 prefill/生成スループットを測ります。モデルを一度ロードし、固定トークン列を 2048, 4096, 6144, ... と歩き、増分 prefill で「新たに足した区間だけ」を計測。各フロンティアでライブ KV をメモリ保存し、固定の貪欲非EOSプローブを生成し、スナップショットを復元して prefill を続けます。
./ds4-bench -m ds4flash.gguf --prompt-file speed-bench/promessi_sposi.txt \
--ctx-start 2048 --ctx-max 65536 --step-incr 2048 --gen-tokens 128
出力は CSV(フロンティアごとに prefill t/s, 生成 t/s, kvcache_bytes)。「長文脈で速度がどう劣化するか」を1本の曲線として見られるので、第3回で触れた圧縮アテンションの効きを定量化できます。ベンチ用テキストは著作権切れの Project Gutenberg(マンゾーニ『いいなづけ』)です。
5. エンジン以外も自前
DwarfStar は推論エンジン以外も外部依存を避け、自前で抱えています。
-
rax.c(約2,700行): 基数木(radix tree)。第5回の exact replay マップ(tool id → DSML ブロック)の土台。antirez が Redis 向けに書いた rax の流用です。 -
linenoise.c(約2,700行): 軽量な行編集 REPL。CLI の対話入力に使用。これも antirez の作。 -
独自トークナイザ: DS4 のプロトコル特殊トークン(
</,|DSML|など)を認識。./ds4 --dump-tokensでトークナイズ結果だけ見て exit できる。例えば DSML のツール閉じマーカーは</と|DSML|の2トークンから始まる、といった検証ができます。 -
official-vector 回帰テスト:
tests/test-vectorsに公式 DeepSeek V4 Flash API から取った短/長文脈の継続ベクトルを置き、./ds4 --dump-logprobsのローカル結果とトークンバイト単位で比較。トークナイザ/テンプレート/アテンションの退行が、長い生成失敗になる前に検出されます。
make test # ./ds4-eval --self-test-extractors && ./ds4_test --all
./ds4_test --logprob-vectors
デバッグ三種の神器も覚えておくと便利です。
./ds4 --dump-tokens -p "..." # トークナイズだけ
./ds4 --dump-logprobs /tmp/out.json --temp 0 -p "..." # 貪欲継続+上位候補
./ds4-server --trace /tmp/ds4-trace.txt ... # セッション全体のトレース
6. シリーズのまとめ
全8回を通して見えてきた DwarfStar の設計思想を、最後に整理します。
- 1モデル特化という賭け(第1回): 汎用性を捨て、DeepSeek V4 をエンドツーエンドで完成させる。
- アーキテクチャ特化の量子化(第2回): 概算でパラメータの大半を占める routed experts を主対象に 2bit 化し、imatrix で誤差を重要列へ寄せる(q2-q4 mixed など recipe 差分もある)。
- 圧縮 KV の実装(第3回): compressor/indexer/HC/tail-RoPE を Metal グラフに垂直統合。
- KV はディスクの一級市民(第4回): レンダリングバイトをキーに、セッションを跨いで再利用。
- API 互換と DSML 密結合(第5回): exact replay でツール呼び出しと KV を噛み合わせる。
- 分散の非対称性(第6回): prefill は速く、生成は遅い、を正直に設計。
- セッション = KV のエージェント(第7回): 整合性問題を構造ごと消す。
- 正直な実験機構と検証基盤(第8回): steering/MTP/eval/bench で「効くか・壊れていないか」を測り続ける。
通底するのは、「ローカル推論を、1つのモデルで、箱から出してすぐ使える状態まで作り込む」 という一貫した姿勢です。エンジン本体は beta、エージェントは alpha という途上の品質ながら、A) エンジン+API、B) 専用 GGUF、C) エージェント検証の三位一体が、確かに1つの形として組み上がっています。
Redis 作者が C で書いた LLM 推論エンジン ―― その読みどころは、派手な最適化よりも「何を捨て、何に賭けたか」という設計判断の明快さにあります。コードを読みながら、その判断を一緒に追体験していただけたなら幸いです。
参考: 第8回で触れた主なコード
| 項目 | 場所 |
|---|---|
| 方向抽出 | dir-steering/tools/build_direction.py |
| steering 適用 |
ds4.c cpu_directional_steering_project_rows() ほか |
| MTP 投機 |
ds4.c ds4_session_eval_speculative_argmax()
|
| 評価スイート | ds4_eval.c |
| ベンチ | ds4_bench.c |
| 基数木 / REPL |
rax.c / linenoise.c
|
| 回帰ベクトル | tests/test-vectors/ |
本記事は クイックイタレート株式会社 のローカル LLM 研究の一環として、
公開リポジトリ antirez/ds4 のコードを読み解いたものです。行番号・定数・ベンチ値は閲覧コミット ba00a8a(2026-05-30)/README 取得日 2026-06-01 時点のものです。ds4-agent は alpha、エンジン本体は beta 品質で活発に変化するため、引用箇所は各自で最新の README / ソースに当たって再確認してください。
クイックイタレート株式会社
IoT / 電力監視 / AI / 衛星・無線通信 / システムインテグレーション/
ローカル LLM・エージェント基盤に関するお問い合わせはお気軽にどうぞ。