BF16が最下位だった — Qwen3.8-9B を5量子化×60タスク×5回で叩いた
こんにちは、くーるぜろです。
今回は empero-ai の Qwen3.8-9B です。この連載では Qwythos-27B-v1 と Qwythos-9B シリーズを扱ってきましたが、開発元は同じ empero-ai。すっかり常連になりました。
ただしこのモデル、名前から受ける印象と中身がずれています。Qwen3.8 という世代は実在する公式世代ですが、9B は公式ラインナップに存在しません。 公式にあるのは `Qwen/Qwen3.8-2.4T-A95B`(通称 Qwen3.8-Max)と `Qwen/Qwen3.8-27B`(dense + vision)の2つだけ。Qwen3.8-9B は、その公式フラッグシップを教師にして、ひとつ前の世代の器である `Qwen/Qwen3.5-9B` へ蒸留した第三者製モデルです。
叩いてみようと思った理由ははっきりしています。モデルカードにコーディング系の公称値が一切ない。 載っているのは GSM8K と MMLU だけ。SWE-bench も LiveCodeBench も HumanEval もない。つまりこのモデルがコードを書けるかどうかは、誰も数字にしていない。だったら測るしかない。
検証規模は 5量子化 × 60タスク × 5runs = 300タスク実行です。
先に結論を書きます。5量子化で最も強かったのは Q5_K_M で Resolved 70.0%(42/60)。最下位は最高ビットの BF16 で 61.7%(37/60)でした。18.41GB を積んで、5.78GB の Q4_K_M(63.3%)にも届いていません。ただし60問という粒度では、この 8.3pt 差は統計的に有意ではありません(McNemar 検定で全ペア p ≥ 0.267)。この記事は「Q5が勝った」という話ではなく、「BF16に3倍のVRAMを払う理由が見つからなかった」という話です。
このモデルの素性

出自はHFのモデルカードを直接読んで確認しています(確度 HIGH)。"Developed by Empero"、"full-parameter distillation of Qwen3.8 2.4T A95B into the Qwen3.5-9B architecture"。FTPO は Final-Token Preference Optimization の略で、Empero 独自の手法とされています。兄弟サイズの `Qwen3.8-4B` `Qwen3.8-2B` も同じ empero-ai 製。
公開日と、話題になった経緯は確認できませんでした。 Reddit 等で該当スレッドを見つけられていません。ここは「不明」と書いておきます。
公称ベンチ値(モデルカード掲載値)
以下はカード掲載値であって筆者の実測ではありません。この記事の実測表には一切混ぜていません。
本体カード:
GSM8k CoT (flexible): 0.870 / (strict): 0.850
MMLU CoT 57 subjects (flexible-extract): 0.751 / (strict-match): 0.511
GGUFカードにあるベース比較表:

知識系(MMLU)は +0.205 と大幅に伸び、算数(GSM8K)は −0.015 でわずかに落ちている。蒸留で何が移って何が移らなかったかが、この2行に出ています。そしてコーディング系の公称値はカードに存在しません。 今回のベンチが、このモデルのコード能力に対する実質的に初の測定になります。
釘を刺しておくと、教師モデル `Qwen3.8-2.4T-A95B`(公式)のカードには SWE-bench Pro 67.7 / GPQA Diamond 92.6 / HLE 43.6 が載っています。これは教師の数字であって、9B蒸留版の実力ではありません。 総2.4T・活性化95B と 9B dense を同じ棚に置くのは無理があります。
GGUFファイルサイズ

カード掲載値と手元の実測ファイルサイズが完全一致。今回叩いたのは間違いなく empero-ai 配布の公式GGUFそのもので、自前量子化や改変版ではありません。
MTP は、カードに記載がないにもかかわらず筆者は `--spec-type draft-mtp` を付けて起動しています。効いていたかどうかは速度の節で扱いますが、結論だけ先に書くと裏取りできませんでした。
検証環境
実行環境: llama.cpp(CUDAビルド、`b10431-1692f9e50`)
ハードウェア: AMD RYZEN AI MAX+ 395(32コア)/ RAM 31.0GB / GPU0 RTX 3090 24GB(0.2GB・コンテキストのみ)+ GPU1 RTX 5090 31.8GB(llama-server 本体)/ CUDA 13.3 / Linux
実測VRAM使用量(GPU1、llama-server プロセス): Q4_K_M 8.1GB / Q5_K_M 8.8GB / Q6_K 9.6GB / Q8_0 11.4GB / BF16 18.7GB
タスク数: 60問(easy 5 / medium 5 / hard 10 / expert 12 / frontier 8 / architect 20)
実行回数: 各タスク5回(pass@k・成功率を測定)
内容: Pythonのバグ修正・実装タスク(関数レベル、決定論的テスト付き)
サンプリング: temp 1.0 / top_p 0.95 / top_k 20 / min_p 0 / seed 42
投機デコード: `--spec-type draft-mtp` を指定(モデル側の対応可否はカードに記載なし)
起動オプション: `-ngl 99` / ctx 65536 / parallel 1 / batch 2048 / ubatch 512 / `-fa on` / threads 8
評価軸: Resolved率 / 成功率(5回平均) / pass@k / Quality / Combined / usability
使っているのは自作のSWE-Bench風ベンチ(llmbench)です。バグレポートとソースをLLMに渡し、patchを適用してLLMには非公開の隠しpytestでresolvedを判定します。難易度tierは easy / medium / hard / expert / frontier / architect、タスクIDは t001〜t060。
Combined = success_rate ×(0.5 + 0.5 × quality/100)× 100(動かないコードは0点)。Quality は lint 密度と保守性指標の重み付き合成です。GitHub: `zephel01/swe-bench`(MIT)、stdlib-only で再現可能。
ここで先に条件面の弱点を出しておきます。今回のサンプリングは temp 1.0 で、このモデルの公式推奨 temp 0.6 から外れています。 連載の他モデルと横並びで比較するために揃えた設定ですが、モデル公式の推奨から外れているのは事実です。推奨温度で回せばスコアが変わる可能性は否定できません(自信度: MODERATE)。この留保は最後の横断比較でもう一度出てきます。
結果サマリ

Combined は Q4 58.5 / Q5 63.5 / Q6 59.4 / Q8 62.7 / BF16 57.1。usability(🟢自律 / 🟡補助 / 🔴不可)は Q4 30/8/22 / Q5 32/10/18 / Q6 29/10/21 / Q8 33/8/19 / BF16 31/6/23。報告 avg_latency は Q4 1671ms / Q5 2124ms / Q6 2582ms / Q8 4380ms / BF16 4658ms です。
そして今回、5runs を回したのに指標が全部同じ値になりました。全量子化で pass@k = 平均成功率 = ≥1成功 = Resolved の4指標が完全一致しています。これは異常事態なので、専用の節を立てて後で解剖します。
結論: 総合チャンピオンは Q5_K_M(Resolved 70.0% / Combined 63.5)。最高ビットの BF16 が 61.7% / 57.1 で最下位となり、8.3pt(5問分)の逆転が出ました。ただし McNemar 検定では全10ペアが p ≥ 0.267、Wilson 95%CI も全量子化が 57.5〜72.9% の帯で重なります。言えるのは「Q5が優れている」ではなく、「ビットを上げても解決力は上がらず、VRAMと速度だけが3倍と半分になる」までです。

最高ビットが最下位 — BF16 61.7%、Q5_K_M 70.0%
序列だけ抜き出すとこうなります。
Q5_K_M 70.0% > Q8_0 68.3% > Q6_K 65.0% > Q4_K_M 63.3% > BF16 61.7%
ビット幅の順番とまったく噛み合っていない。特に効くのは費用対効果の話で、18.41GB を消費する BF16 が、5.78GB の Q4_K_M より1問少ないという結果です。VRAM 3.18倍、速度は約半分。それで解けた問題は減っている。
中位量子化がピークになること自体は、この連載では見慣れた形です。Qwythos-27B の標準版は Q5_K_M(90.0%)がピークで Q6_K(83.3%)で落ちた。KAT-Coder-V2.5-Dev は Q6_K が単独首位。DeepSeek-V4-Pro-Qwen3.5-9B は Q4_K_M が最高で、ビットを上げるほど下がって Q6_K で底を打つ形でした。
ただし今回は一段新しい。BF16 まで測ったのは Qwythos-9B-v1(Q4_K_M と BF16 が最良)だけで、BF16 が最下位に沈んだ実測は連載初です。 「フル精度を積めば少なくとも損はしない」という直感が、このモデルでは成立しませんでした。
向きの非一貫性も相変わらず。Qwythos ファミリーでは同じ Q5_K_M が 9B では谷、27B では山でした。DeepSeek 9B は Q4 が最高で単調に減る。今回は Q5 が山で BF16 が底。「このシリーズは Q5 が鉄板」のようなファミリー単位の一般化は、やはり成立しません。 最適点はモデルごとに実測するしかない。
とはいえ「Q5_K_M が優れている」と言い切るつもりはありません。理由は2つ先の節で書きます。
「BF16はコードが綺麗」はselection biasだった
結果サマリの表をもう一度見ると、妙なことが起きています。Resolved 最下位の BF16 が Quality では最高(85.2)で、Resolved 首位の Q5_K_M が Quality 最低(81.5)。報告値ベースで相関を取ると r = −0.843 の逆相関です。素直に読めば「解けない量子化ほど綺麗なコードを書く」。そんなわけがない。
そこで、5量子化すべてが解けた共通28問だけに絞って Quality を計算し直しました。


共通28問での Quality レンジは 84.94〜85.36、わずか 0.42pt。 報告値の 3.7pt 差はほぼ消えました。しかも28問中17問は5量子化で Quality が完全一致しています。
差の正体は extra 列にあります。Q5_K_M が追加で解いた14問には Quality 23.7(t057)/ 32.4(t054)/ 37.6(t056)という低品質の正解が混ざっている。すべて architect 帯。この3問を除くと Q5 の Quality は 81.52 → 85.39 に跳ね上がり、BF16 の報告値 85.18 を上回ります。 ただし共通28問という土俵では BF16 が 85.36 なので、そちらとは事実上並ぶ、という書き方が正確です。どちらにせよ「BF16だけが群を抜いて綺麗」ではなくなる。
結論: BF16 はコードが綺麗なのではなく、汚いコードが出るような難しい問題に到達しなかっただけです。Quality の高さは能力の証明ではなく、挑戦しなかったことの副作用でした。
そもそも Quality という指標が脆い
ついでに指標の中身も割っておきます。300件で検算して不一致ゼロだった式がこれ。
Quality = (4 × ruff_score + 3 × complexity_score) / 7
`llm_review` と `sonarqube` は全実行で `enabled: false`。今回の Quality は「ruff の lint 清潔さ」と「radon の保守性指数」だけでできています。設計の良し悪しも、動くかどうかも見ていない。
減点の主因を数えると W293(空行の行末空白)23件 / E501(行長超過)20件。長いコードを書くと ruff が0点近くまで落ちて Quality が半減する構造です。
t057(Q5): Quality 23.7 / ruff 0.0(83 LOC に 12 issue: C420, F401, W293)/ complexity 55.2
t054(Q5): Quality 32.4 / ruff 5.1(59 LOC に 7 issue: E501, W293)/ complexity 68.8
t056(Q5): Quality 37.6 / ruff 0.0(18 LOC に 3 issue: E501, W293)/ complexity 87.8
t056 は保守性指数 87.8 の正解コードなのに、E501 と W293 のせいで Quality 37.6 まで落ちている。難しい問題に挑んで長いコードを書いた量子化ほど、この指標では損をする。 Quality を量子化間の優劣に使うときは、比較対象が全員解けた問題だけに揃えないと意味がありません。
ただし、この差は統計的に有意ではない
ここまで逆転の話をさんざん書いてきましたが、統計的にはこの序列は確定していません。
McNemar 検定(n=60、対応あり)で全10ペアを検定した結果:

全ペアが p ≥ 0.267。 最小の p 値が記事の看板である Q5 vs BF16 の 0.267 で、それでも有意水準には遠く及びません。Wilson 95%CI も全量子化が 57.5〜72.9% の帯で重なっています。
理由は単純で、60問だと1問が 1.67pt だからです。Q5 と BF16 の 8.3pt 差は問題数にすると 5問差。60問中5問の入れ替わりは揺らぎの範囲に十分収まります。
これは「差がない」ことの証明ではありません。差を検出できていない、というだけです。 本当に Q5 が強いのかもしれないし、本当は横並びなのかもしれない。60問という解像度では判定できない。
この連載の第一原則は「1回の結果で語らない」。今回は単発ではなく5runs 回して、それでも序列は出せませんでした。原則を守った上で、なお足りなかった。 しかも、その5runs 自体にもっと厄介な問題がありました。
pass@k で見る「再現性」の差 — 5runsが実質1runだった
結果サマリで先送りにした話をします。4指標が全量子化で一致したのは、5回の試行がほぼ完全に同じ結果を返していたからです。
数えました。全300タスクで `attempts` は5件ずつ存在します。そして `(resolved, quality, combined, fail_reason, truncated, finish_reason)` の6項目が5回とも完全一致したのは 298/300。
例外の2件はどちらも **t033(frontier)**の Q6_K と BF16。「試行1が `llmbench:reasoning_budget` で打ち切られ、残り4試行が fail-fast でスキップされた」というもので、サンプリングのゆらぎではなくハーネス側の中断です。
「全部 fail-fast で省略されていたから一致したのでは」と疑うのが筋なので、そこも確認しました。fail-fast が記録されたのはこの2タスク(計8 attempt)だけ。残り1492 attempt は実際に実行されています。
ウォールクロックからも裏を取りました。Σlatency × 5 が実行間隔に占める割合は 80.6%(Q5)/ 83.1%(BF16)。×1 で計算すると84%が説明のつかない空白時間になる。5回の推論は実際に走っていたと考えていい(自信度: MODERATE-HIGH)。Quality は ruff と radon から 0.1 刻みで出る値なので、5回とも一致したなら5回とも実質同じコードが出ていたと読むのが自然です。
言い切ってはいけないこと
「5runs がバイト単位で同一だった」とは書けません。 artifacts は各タスク1本しか保存されていない(`t001/llm_output.txt` の単一ファイルで、run 別ディレクトリが存在しない)。attempts[] には生テキストもトークン数もレイテンシも入っていない。書けるのは「判定・Quality(0.1刻み)・失敗理由が5回とも一致した」までです。
原因が seed 42 固定だとも断定しません。 `--seed 42 --parallel 1` という設定からの推論であって、計測データに seed 再設定の記録はありません(自信度: MODERATE)。pass@k = pass@1 は事実として正しいものの、その原因が完全な決定論であるとまでは今回のログでは示せない。
量子化をまたいだ一致も観測しています。llm_output.txt がバイト単位で一致したタスクが 9/59、生成コードでは 10/58。easy 帯(t001, t002, t003, t005)と t013、さらに architect の t043(628バイト)・t047(675バイト)まで、5量子化で完全に同じものが出ていました。
締めます。pass@k = pass@1 になったのは事実。これでは5runs を回した意味がありません。次回は seed を試行ごとに変える設計に直します。これは宿題にします。
量子化を上げてもモデルは同じ間違いをする

5量子化 × 5回 = 25試行すべてが落ちた問題が8つあります。t020・t043・t044・t046・t047・t055・t059・t060。 t020 だけ hard 帯で、残り7問はすべて architect 帯です。
面白いのは、落ち方がビット幅とほとんど関係ないこと。順番に見ていきます。
t059(浮動小数点の総和ドリフト)— Kahan というアトラクタ
5量子化すべてが、docstring の文言以外は完全に同一のアルゴリズムを出力しました。 全部が「Kahan の補償付き加算」を選んでいます。
s = 0.0; c = 0.0
for v in values:
y = v - c; t = s + y; c = (t - s) - y; s = t
return sKahan 和としては正しい実装です。ただしテストの `total([1.0, 1e16, 1.0, -1e16]) == 2.0` は Kahan では通りません(補償項自体が桁落ちで消える)。必要なのは Neumaier(Kahan-Babuška)補償か `math.fsum()`。全量子化とも `assert 0.0 == 2.0` で落ちました。
一番こたえるのがここ。Q5 の docstring には「correctly returns 2.0 instead of 0.0」と、自分で正解が明記してあります。その上で、その正解を出さないコードを書いている。
系譜も一貫しています。SmartCode-Fable5-27B は7量子化すべて全滅、Qwythos-27B は6パターン全滅。KAT-Coder-V2.5-Dev は Q5_K_M だけ 4/5 で解決、Q4 は 0/5、Q6 は 2/5(ビット幅と解決力が単調に並ばない実例)。Muse-Glimmer-30B は Q4 0/5・Q5 2/5 で両方未解決。環境比較記事では4環境12試行すべて全滅した上に生成コードの md5 が4環境で完全一致。「モデルの分布に『Kahan』という強力なアトラクタがあって、そこから抜け出せない」という見立ては、今回の5量子化一致でさらに補強されました。
t043 / t047 — 5量子化がバイト単位で同一
この2問は、5量子化すべてがバイト単位で同一の出力を返しました(t043 = 628バイトの replay.py、t047 = 675バイトの runner.py、いずれもSHA一致)。
t043 は `snapshot is None` の分岐で `state` を正しく初期化しているのに、2行後の `for event in store.since(snapshot.offset):` を無条件で実行して `AttributeError: 'NoneType' object has no attribute 'offset'`。自分で書いた None ガードを、2行後に自分で踏み抜いています。
t047 は元のバグ(実行前に applied へ入れる)を正しく直しているのに、再実行時に applied 済みをスキップする処理がない。`log == ['a','a','b','c']` で期待値 `['a','b','c']` と合わない。「失敗しても再開できる」という要件の"再開"側だけが丸ごと抜けている。 t043 は Qwythos-27B で 4/6 失敗、KAT-Coder v2 では15試行すべて全滅。t047 は Qwythos-27B で 4/6 失敗、KAT-Coder v2 では Q6_K だけ 4/5 で通った flaky 問題でした。
t044(プラグインのロード順序・循環検出)
ここは落ちたテストが2種類に割れました。
Q4 / Q6 / Q8 は `test_order_independent_of_registration` で落ちています。 症状は3量子化とも同じで、`['a','b','c','d'] != ['a','c','b','d']` ——登録順に依存した順序が出ている。ただし選んだアルゴリズムは違って、Q4 と Q8 は Kahn 法(入次数を数えて `queue.pop(0)`)、Q6 は `visit()` を再帰する DFS 版のトポロジカルソートです。別のアルゴリズムを選んでも、同じ「登録順に引きずられる」という穴を開けている。 とくに Q4 は `# Use a deterministic order (sorted) so result is independent of registration order` とコメントを書いた上で、実装では一度もソートしていません。要件をコメントで正しく述べてから、その通りに実装しない。
Q5 と BF16 は `test_transitive_order` で、存在しない循環を検出して `CycleError` を投げています。 Q5 のほうは原因がはっきりしていて、`loader.py` と `registry.py` の2ファイルを同時に書き換えて整合を壊しました。registry 側を `{"deps": list(deps)}` に変えたのに loader 側は `len(deps)` のまま。全ノードの入次数が1になり、初期キューが空になる。複数ファイル編集の整合性が取れない典型例です。
BF16 は `loader.py` 1ファイルしか書き換えておらず、中身も素直な Kahn 法。それでも同じ `test_transitive_order` で偽の `CycleError` を出しました。元の `registry.py` が artifacts に残っていないため、入次数の数え方のどこがずれたのかまでは特定できません(自信度: LOW)。 分かるのは、2ファイル書き換えという分かりやすい失点をしていないのに同じ落ち方をした、という事実だけです。
t046(DIのsingleton/requestライフタイム)
5量子化すべてが同じ設計ミス。singleton スコープは正しく作れているのに、request スコープのキャッシュキーを `(key, request)` にした。テストが渡す `request` は素の dict なので `TypeError: unhashable type: 'dict'`。
この問題は Qwythos-27B が6パターン全滅、KAT-Coder v2 では Q6_K が新たに落とした一方、Muse-Glimmer-30B は Q4 3/5・Q5 4/5 で両方通過しています。 解けるモデルは解ける問題を、Qwen3.8-9B は5量子化とも落としました。
t020(電卓の演算子優先順位とカッコ)— 連載最古参の鬼門
今回、5量子化 × 5回 = 25試行すべて全滅。 ただし負け方が新しい。
Q5 / Q8 / BF16 の3量子化は、shunting-yard 法と RPN 評価器を完全に正しく書いています。その上で `_tokenize()` が `+-*/` と数字しか受理せず、`(` が来ると `raise ValueError(f"bad character: {ch!r}")`。`test_parentheses` の `evaluate("(1+2)*3")` がそこで死ぬ。アルゴリズムを知っていて実装もできるのに、入口のトークナイザに括弧を通す1行を足し忘れている。
Q6_K は `_is_operator(token)` が `return token in "+-*/"` で、整数トークンが来ると `TypeError: 'in <string>' requires string as left operand, not int`。Q4_K_M に至っては `result[i] = (result[i-1][0], result[i-1][1] op val)` という Python として構文不正な式を出力して `patch parse failed: no file blocks found in output`。このタスクだけ test_output.txt が生成されていません。
Muse-Glimmer-30B が t020 を Q4/Q5 とも 3/5 で割ったとき、原因は「再帰下降パーサを引くか操車場アルゴリズムを引くかのくじ引き」でした。今回はくじ引きの当たり札を引けているのに、入口で落ちている。 新しい負け方です。
t055(相対日付のパース)— 連載初の深掘り
仕様は「next 月曜 = base より後の最初の月曜(base が同じ曜日なら +7)」。5量子化とも別々の箇所で落ちました。
Q4: `"in 3 days"` を `len(parts)==2` でしか見ておらず `ValueError`
Q5/Q6: base=2026-06-26(金) から `"next monday"` が 2026-07-06(正解は 2026-06-29)。無条件 +7
Q8: 曜日計算も in N days も通した上で `.lower()` を忘れ、`"Next Monday"` で `ValueError`。5量子化で一番惜しい
BF16: base=金曜での `"next friday"` が 2026-06-26(当日、正解は 2026-07-03)。`delta==0 → 7` のガードがない
t055 は Qwythos-27B の Q4_K_M(標準) 失敗内訳に名前だけ出ていた問題で、中身を書くのは今回が初です。
t060(見た目が同じ文字列が別物と判定される)— 初登場の鬼門
過去5記事のどこにも登場していない、今回が初登場の鬼門。テスト3件中2件は通り、`test_unicode_casefold`(`equal("straße","STRASSE",fold=True) is True`)だけが落ちます。必要な答えは `str.casefold()` の一語。ß → ss を行うのは casefold だけです。

NFC / NFKC / NFKD の正規化は5量子化とも正しく書けています。「Unicode 正規化」は知っているのに「casefold と lower の違い」を知らない。 知識の境界が気持ち悪いほど綺麗に出ました。しかも BF16 の実装が一番凝っていて、一番間違っている。ASCII に落とす発想は独創的ですが、その独創が ß を消し飛ばしている。
8問を通して見えるのはひとつ。量子化ビットは知識の穴を埋めない。 Q4 で知らないことは BF16 でも知らない。
量子化ごとの失敗タスクと、難易度別の分解
難易度帯で分解すると、差がついた場所がはっきりします。


easy は全量子化満点。medium・hard・expert は1〜2問のばらつきに収まっています。実質的に差がついたのは **frontier(4〜6問)と architect(5〜9問)**だけです。
architect 20問の構造
architect 帯を「何量子化が解けたか」で分類すると、この帯の性格が見えます。

全員が解ける3問(t050 並行カウンタ / t051 async プールのデッドロック / t052 スレッドセーフLRU)は、いずれも「ロックやセマフォを足す」定型パターンです。 一方で全滅7問は、要件を読み替えたり複数ファイルの整合を取ったりする必要がある。architect 帯の壁は難易度そのものではなく、**「定型パターンに落ちるかどうか」**でした。
各量子化の architect 内訳を並べるとこうなります。
Q4_K_M(6問): 確実3 + t042, t049, t041
Q5_K_M(7問): 確実3 + t042 + t054, t056, t057
Q6_K(7問): 確実3 + t042, t049, t045, t048
Q8_0(9問): 確実3 + t042, t049, t041, t053, t056, t058
BF16(5問): 確実3 + t049, t045
確実3問と 4/5 の2問を引くと、残りは「運次第の10問」です。量子化間の architect の差(5〜9問)は、この10問をいくつ拾えたかで決まっています。 実力差というより、くじ引きの引き当て数。前節の「統計的に有意ではない」に素直につながる話です。
ユニーク失敗・ユニーク成功

特定量子化への偏りは見えません。むしろ注目したいのは BF16 の行で、medium 帯の binary_search(t008)を落として、hard 帯の slugify(t017)を解いています。 難易度の順序が逆。これを「BF16 は文字列処理に強い」と読むのは無理があります。素直に揺らぎです。
各量子化の失敗タスク全リスト

左右に割ったのは、次の節で40問に揃えた比較をするためです。t001〜t040 の失敗数は Q5 だけが5問で、他4量子化はすべて8問。 60問全体で見えた序列のうち、architect 抜きで残るのはこの1点だけでした。
t017(hard の slugify)は BF16 以外の4量子化が落としています。t007 は Q5 だけが解いた medium。この2問も「運次第」側の代表です。
usability(実際どれくらい任せられるか)と、動かないコードもlintでは78点

3分類の定義を再掲。🟢 自律はレビューほぼ不要でそのまま使える、🟡 補助はレビュー前提なら任せられる、🔴 不可は任せられない。
ただし中身を確認したら思ったより単純でした。境界を全件チェックした結果がこれです。
unresolved → 🔴(103件)
resolved かつ Quality ≥ 80 → 🟢(155件、最小 80.2)
resolved かつ Quality < 80 → 🟡(42件、最大 79.9)
usability_tier は、Quality の80点しきい値の言い換えにすぎません。 独立した評価軸ではない。
そう分かると BF16 の🟡が6件しかないことの意味も変わります。「補助が必要なコードが少ない=出力が安定している」ではなく、Quality が80を割るような難しい問題にそもそも到達していないだけ。selection bias の節と同じ構造がここでも出ています。
落としたコードにも同じ式を当てる
ここからがこの記事で一番実務に効く話。unresolved(テストが通らなかった)タスクの生成コードに、同じ Quality 式を当ててみました。

(Q5 の中央値 81.2 は、resolved の🟢しきい値である80を超えています)
動かないコードの中央値が 75〜81。lint も保守性指標も「合格圏」です。このモデルは「ちゃんとした見た目で、動かないコード」を安定して出します。
これが何を意味するか。静的品質指標や自動レビューでは、この失敗モードを弾けません。 ruff は通る。radon の保守性も高い。型ヒントも docstring も付いている。t059 に至っては docstring で正しい仕様を宣言してから間違った実装を書いてくる。人間のコードレビューでも、Kahan 和と Neumaier 補償の違いを知らなければ普通に通ってしまうでしょう。
ローカルLLMにコードを任せるなら、防波堤はテストしかありません。 見た目の品質は何も保証していない。
速度 —「Q8は2.6倍遅い」の正体は1問の暴走
数字を並べる前に3点。
MTP(投機的デコード)を指定した実行は構造的に速い数字が出ます。 先読みが当たるぶん速いだけで、賢さの証明ではありません。今回は `--spec-type draft-mtp` を付けていますが、モデルカードに MTP の記載がないので、そもそも効いていたかどうかも怪しい。
今回は dense 9B のみで、MoE との比較はありません。 MoE は活性化パラメータが小さいぶん速い数字が出ます。ここに並ぶ数字を他記事の MoE モデルと直接比べないでください。
今回の値はすべて単発実行時のものです(parallel 1)。並列実行時の1ストリーム tok/s は桁が変わります。

報告値だけ見ると「Q8_0 は Q4 の 2.6倍遅い」ように読めます。実際は違う。
犯人は Q8_0 / t048 の1問です。 completion_tokens が 49,152(max_tokens の上限に到達)、latency 154.72秒、5試行すべて truncated。Q8_0 が生成した全トークン 79,759 のうち、62% がこの1問です。除外すると avg_latency は 4380ms → 1778ms に落ちて、Q6_K(1819ms)とほとんど変わらなくなります。
t033 も別の形で壊しています。Q6_K が 47.38秒、BF16 が 76.20秒で `finish_reason = llmbench:reasoning_budget`。思考だけして本文をゼロトークンしか出さずに打ち切られた実行です。ほかに Q5_K_M / t041 が 25.25秒・9,434トークン、BF16 / t041 が 39.45秒・8,227トークン。
平均 latency は外れ値1問で簡単に壊れます。速度は中央値 tok/s で読むべきです。 幸い tok/s の分布は非常にタイトで、全量子化とも p10〜p90 が平均の ±10% 以内。中央値が代表値として素直に使えます。
帯域律速との乖離


サイズが 3.18倍になっても、速度低下は 1.83倍で止まっています。純粋な帯域律速なら 103.7 tok/s まで落ちるはずのところ、実測は 180.9。予測の 1.74倍出ている。
投機デコードが効いている可能性はあります。ただし受理率の記録がないので直接の裏取りはできません(自信度: MODERATE)。 カードに MTP の記載もない以上、「BF16 は帯域律速の予測より速かった」という事実の記述以上は書けません。キャッシュ効率やカーネルの違いという説明も同じくらい成り立ちます。
レイテンシ差の中身
共通28問に絞ってレイテンシを分解しました。Q4 → BF16 は 1.26s → 2.41s で 1.91倍。内訳は生成速度の差が 337.0/184.0 = 1.83倍、生成トークン数の差が 449.7/414.1 = 1.09倍。
レイテンシ差のほぼ全部が素の生成速度で、トークン数の寄与は9%しかありません。 BF16 が遅いのは「長く考えるから」ではなく「単純に1トークンあたりが遅いから」です。
トークン消費

Q8_0 は t048 を除くと Σ30,607 / 平均 518.8 で、他の量子化と横並びになります。
resolved と unresolved で分けると傾向がはっきり出ます。Q4 は 493.3 / 601.0、Q5 は 517.0 / 1,109.6、Q6 は 514.6 / 640.8、Q8 は 497.1 / 3,125.1(t048 を除くと 568.1)、BF16 は 466.7 / 944.0。分からない問題ほど長く書き、長く考える。 出力トークン数は難易度のセンサーとして使えます。
なお、思考トークンは artifacts に残っていません。llm_output.txt のバイト数と completion_tokens が合わない(t001 は 243バイトに対して 223トークン)ので、保存されているのはパッチ本文だけです。短いタスクでは生成トークンの過半が思考に消えていると見ています(自信度: MODERATE、バイト数からの概算)。
9B帯の中での位置づけ — 40問に揃えて過去記事と比べる
比較の前に土俵を揃えます。今回の60問の Resolved% を、40問で回した過去記事とそのまま比べてはいけません。 architect 20問が入っているぶん、全体が引き下げられているからです。
ただし救いがあって、タスクIDと難易度の対応は t001〜t040 = easy〜frontier、t041〜t060 = architect。今回のデータから t001〜t040 を抜き出せば、40問記事と同条件で比べられます。
40問に揃えた今回の Qwen3.8-9B:


比較対象は DeepSeek-V4-Pro-Qwen3.5-9B(2026-08-02記事、40タスク×5runs、同じ RTX 5090)です。

(同記事の 4B は Q8_0 の 80.0% が最良で、Combined は Q5_K_M の 68.4 が最高でした)
Qwen3.8-9B は4量子化が 80.0% で DeepSeek 9B の最良(Q4_K_M 80.0%)に並び、Q5_K_M は 87.5% でそれを上回りました。 同じ 9B、同じ40問、同じ5runs、同じ RTX 5090。9B 帯としては素直に強い部類です。
ただし完全な同条件ではありません。DeepSeek 記事は sample_temp 0.8、今回は temp 1.0 で回しています。 温度が違えば出力の分散が変わるので、この 7.5pt 差を「Qwen3.8-9B のほうが強い」と読み切るのは行き過ぎです(自信度: MODERATE)。しかも今回の Q5 と他4量子化の差自体が統計的に有意でない以上、87.5% という数字にも同じ幅の不確かさが乗ります。
それでも、この比較には価値があります。コーディング系の公称値が存在しないモデルなので、これが現時点でこのモデルのコード能力を測る唯一の外部基準です。
結局どれを選ぶか
Q4_K_M(5.78GB / 63.3% / ~325 tok/s): 一番速く、一番軽い。VRAM が厳しいならこれで実用上ほとんど困りません。今回の5量子化はどれを選んでも有意差がないので、迷ったら最小を取っていい。
Q5_K_M(6.64GB / 70.0% / ~319 tok/s): 今回の総合首位。Q4 から 0.86GB 増えるだけで速度低下は4%。デフォルトの推奨はこれ。
Q6_K(7.56GB / 65.0% / ~306 tok/s): Q5 より重く、遅く、解けた問題も少ない。Q5 が置ける環境で Q6 を選ぶ理由は、今回のデータからは見つかりません。
Q8_0(9.79GB / 68.3% / ~282 tok/s): 解決力は Q5 に次ぎますが、t048 で 49,152トークンまで暴走して154秒溶かす事故を起こしました。長考の暴走を許容できる用途でだけ。
BF16(18.41GB / 61.7% / ~181 tok/s): 3倍の VRAM と半分の速度を払って最下位。今回の用途(コーディング)で選ぶ理由はありません。
VRAM 別の話をすると、8GB 級なら Q4_K_M、12GB 級以上なら Q5_K_M。そして 24GB 以上を積んでいる人へ——このモデルに関しては、余った VRAM を BF16 に使う理由が今回のデータからは見つかりませんでした。 Q5_K_M を置いて、残りをコンテキスト長か並列数に回したほうが得です。
まとめ
BF16 が最下位。 Q5_K_M 70.0% > Q8_0 68.3% > Q6_K 65.0% > Q4_K_M 63.3% > BF16 61.7%。18.41GB が 5.78GB に負けた。
「BF16 はコードが綺麗」は selection bias。 共通28問で比べると Quality レンジは 0.42pt しかない。報告値の差は「難しい問題に到達したかどうか」の副作用だった。
この序列は統計的に有意ではない。 McNemar 全10ペアが p ≥ 0.267、Wilson 95%CI は 57.5〜72.9% で完全に重なる。60問では1問が 1.67pt。
5runs が実質1run だった。 298/300 のタスクで6項目が5回とも一致。pass@k = pass@1 になり、再現性の測定にならなかった。
鬼門8問はビットを上げても1問も解けなかった。 t059 は5量子化とも Kahan 和、t043/t047 は5量子化がバイト単位で同一出力、t060 は5量子化とも casefold を知らない。
速度の「Q8 は2.6倍遅い」は t048 1問の暴走。 除外すると 4380ms → 1778ms。平均 latency は外れ値で壊れる。
40問に揃えると DeepSeek-V4-Pro-Qwen3.5-9B と同格以上。 4量子化が 80.0% で並び、Q5_K_M は 87.5%(※温度条件は異なる)。
もう一度結論を書きます。Qwen3.8-9B は Q5_K_M(6.64GB / 70.0% / ~319 tok/s)が最良で、BF16(18.41GB / 61.7% / ~181 tok/s)は最下位でした。ただし60問では1問が 1.67pt なので、この序列自体は統計的に確定していません。確定して言えるのは3つ。ビットを上げても鬼門8問は1問も解けるようにならなかったこと、BF16 の Quality の高さは「難しい問題を解かなかった」ことの副作用でしかなかったこと、そして5runs 回したのに5回とも同じ答えが返ってきて、再現性の測定になっていなかったことです。
今回の教訓
「このモデルは綺麗なコードを書く」は、たいてい「難しい問題を解かなかった」の言い換えである。 品質を比べるなら、比較対象が全員解けた共通問題だけで比べる。土俵を揃えないと、挑戦しなかったモデルが勝つ。
静的品質指標は「動くかどうか」を一切見ていない。 落としたコードの隠れ Quality 中央値は 75〜81 で、🟢の80しきい値の前後に散らばっている。ローカルLLMにコードを任せるなら、防波堤はテストしかない。
量子化ビットを上げても、モデルの知識の穴は埋まらない。 ビット幅が変えるのは「運次第の問題をいくつ拾えるか」であって、「知らないことを知る」ではない。casefold を知らないモデルは、BF16 でも casefold を知らない。
宿題
seed 設計の見直し。 試行ごとに seed を変えないと pass@k が pass@1 に潰れて、5runs を回す意味がなくなる。次回から直す。
architect 帯の run 数を増やす。 「運次第の10問」を10runs 以上で叩かないと、量子化間の差が実力なのか揺らぎなのか分離できない。
推奨 temp 0.6 での再測。 連載横並びのために temp 1.0 で回しているが、公式推奨での挙動は別途見ておきたい。
検証で生成したコード・テスト結果はアーカイブ済みです。「特定タスクの詳細が見たい」「自分の環境でも試したい」はコメントへどうぞ。
モデル情報
HuggingFace: https://huggingface.co/empero-ai/Qwen3.8-9B
ベース: dense 9B(器は Qwen/Qwen3.5-9B、教師は Qwen/Qwen3.8-2.4T-A95B からの全パラメータ蒸留)
開発元: empero-ai(Empero)
コンテキスト長: 262,144 tok
ライセンス: Apache-2.0
推奨サンプリング: temperature 0.6 / top_p 0.95 / top_k 20(今回の検証は temp 1.0 で実行)
使用ベンチ: https://github.com/zephel01/swe-bench (MIT)
関連記事
連載の鬼門t020をついに割った — Muse-Glimmer-30B + DFlash を76タスク×5回×2量子化で叩いた(2026-08-10)
パラメータ2倍の差は、Combined 3.1pt しかなかった — DeepSeek-V4-Pro-Qwen3.5 の 9B と 4B(2026-08-02)
速くなったMTPが賢いとは限らない — Qwythos-27B-v1 の MTP版と標準版を6量子化で比較(2026-07-30)
1runのチャンピオンは5runsのチャンピオンではなかった — Kwaipilot KAT-Coder-V2.5-Dev 60タスク5runs(2026-07-29)
SmartCode-Fable5-27B 7量子化ベンチ検証(2026-07-28)
くーるぜろの記事一覧: https://note.com/zephel01
#ローカルLLM #llamacpp #ベンチマーク #量子化 #GGUF #Qwen38 #EmperoAI #9B #BF16 #passk #コーディングモデル
※納品時の注記: note投稿時はテーブルが崩れるため、①主要な比較表(表1・難易度別表・速度表)はスクリーンショット画像化する、②または要点を箇条書きに変換する、のどちらかで対応してください。
いいなと思ったら応援しよう!
サーバー代とコーヒー代になります☕ 役に立ったら応援よろしくお願いします!