見出し画像

tok/s は 10.5倍違ったのに、遅いほうが勝った:Muse-Glimmer-30B+DFlash を RTX5090 / RTX3090 / AI MAX 395 の4環境で回した

AI MAX 395+ 128GBを買ったのに、RTX3090 24GB → RTX5090 32GBを乗り換えて行った原因がここにあります。現時点での評価です。

こんにちは、くーるぜろです。

前回、Muse-Glimmer-30B に DFlash(投機的デコード)を付けて RTX5090 で叩きました。Q4_K_XL で 60タスク中 58問、tok/s は中央値 182.6。「30B dense がこの速度で回るのは連載になかった位置づけだ」と書きました。

そこで当然、次の疑問が来ます。この速度は 5090 だから出ているのか。手元の別のカードだとどうなるのか。そして速度が落ちたら、賢さも落ちるのか。

今回はモデルも量子化もサンプリングも一切変えず、走らせる場所だけを4つに変えました。

  • RTX5090 32GB(CUDAビルド)

  • RTX3090 24GB(CUDAビルド)

  • AMD Radeon 8060S(AI MAX+ 395 の内蔵GPU / ROCmビルド)

  • 同じ 8060S(Vulkanビルド)

先に結論を書きます。

筆者の実測では、tok/s の中央値は 182.6 → 84.8 → 32.7 → 17.3。上から下まで 10.5倍の開きが出ました。 一方で Resolved は 96.7% / 98.3% / 95.0% / 95.0% で、3.3pt の幅に収まっています。

そして今回いちばん書きたいのはここです。5runs 同士で正面から比べられる 5090 と 3090 では、tok/s が半分以下しかない 3090 のほうが Resolved で 1.6pt 上でした(96.7% → 98.3%)。 ハードを速くしても賢くはならない、という当たり前の話ではありません。同じモデル・同じ量子化・同じ5回で、置き場所を変えるだけでスコアが 1.6pt 動く。これがこのベンチの誤差の目安だ、という話です。


今回の4環境と、条件の違い

先に、揃っていないところを全部開示します。

8060S の2本を1runにしたのは、単純に遅すぎて5runsが現実的でなかったからです。 60タスクを1周するのに ROCm で約60分、Vulkan で約108分かかっています。5runs にすると ROCm で約5時間、Vulkan で約9時間。丸一日ベンチに使うことになります。

この判断の結果として、8060S の2本は「速度の実測」としては信頼できますが、解決力のスコアは 5090 / 3090 と同列に並べられません。 理由は2つ。

  1. 単発は上振れ・下振れがそのまま出ます。 この連載では「±3pt程度の差では優劣を断定しない」を原則にしています。

  2. resolved の判定規則が実質的に変わります。 5runs では5回中3回以上通れば resolved(多数決)ですが、1run では1回の成否がそのまま resolved です。真の成功率が 60% のタスクなら、5runs の多数決なら 68% で resolved になるのに、1run では 60% にしかならない。真の成功率が5割を超えるタスクでは、1run のほうが構造的に不利になります。(今回はほぼ全タスクが高成功率なので、この向きで効きます)

なので以下、速度は4環境を横並びにし、解決力の比較は 5090 vs 3090(5runs 同士)に絞ります。 8060S の2本のスコアは参考値として別に置きます。

コンテキスト長と mmproj も揃っていませんが、今回のタスクは最大でも completion_tokens 7,884 でプロンプトも小さく、65,536 の制約に触れた形跡はありません。mmproj はテキストのみのタスクでは使われません。この2点はスコアに影響していないと見ています(自信度 HIGH)。


検証環境

  • 実行環境: llama.cpp(CUDA / ROCm / Vulkan の3ビルド、いずれも b10354-d2f83055d)

  • ホスト: EVO-X2(AMD RYZEN AI MAX+ 395、32コア / システムRAM 31.0GB)、CUDA 13.3、driver 610.43.02

  • GPU: RTX5090 31.8GB(CC 12.0)/ RTX3090 24.0GB(CC 8.6)/ Radeon 8060S(VRAM 96.0GB 割当)

  • モデル: Muse-Glimmer-30B-UD-Q4_K_XL(約14.8 GiB)+ ドラフタ `dflash-kquant.gguf`(約1.52 GiB)

  • タスク数: 60問(easy 5 / medium 5 / hard 10 / expert 12 / frontier 8 / architect 20)

  • 実行回数: 5090・3090 は各5回、8060S の2本は各1回

  • サンプリング: 公式推奨 temp 1.0 / top_p 0.95 / top_k 64

  • 投機デコード: `--spec-type draft-dflash --spec-draft-n-max 15`、`-ngl 99` / `-ngld 99` / `-fa on`、並列スロット4

  • 評価軸: Resolved率 / 成功率(5回平均) / pass@k / Quality / Combined / usability

起動コマンドはビルドのパスとコンテキスト長だけが違います。ROCm 版はこれです。

~/llm/apps/llama.cpp/build-rocm/bin/llama-server \
  -m ~/llm/models/Muse-Glimmer-30B-GGUF/Muse-Glimmer-30B-UD-Q4_K_XL.gguf \
  -md ~/llm/models/Muse-Glimmer-30B-GGUF/dflash-kquant.gguf \
  --spec-type draft-dflash --spec-draft-n-max 15 \
  -ngl 99 -ngld 99 -c 65536 -fa on \
  --temp 1.0 --top-p 0.95 --top-k 64 \
  --host 0.0.0.0 --port 8085 --jinja --alias "Muse-Glimmer-DFlash-ROCm"

Vulkan 版は `build-vulkan` に差し替え、`GGML_VK_VISIBLE_DEVICES=2` で 8060S を指定しています(Vulkan からは 3090・5090・8060S の3つが見えるため)。

使っているのは自作のSWE-Bench風ベンチ(llmbench)です。バグレポートとソースをLLMに渡し、patchを適用してLLMには非公開の隠しpytestでresolvedを判定します。Combined = success_rate ×(0.5 + 0.5 × quality/100)× 100(動かないコードは0点)。GitHub: `zephel01/swe-bench`(MIT)。


速度:上から下まで 10.5倍

図1: 4環境の速度と待ち時間

結論: 5090 → 3090 で 2.15倍、3090 → 8060S(ROCm)で 2.59倍、ROCm → Vulkan で 1.89倍。積み上げると 5090 は Vulkan-8060S の 10.5倍速い。

「60タスク1周の生成時間」は、各タスクの生成時間を合計した値です(5runs の環境は1周ぶんに換算)。pytest の実行・品質解析・モデルロードは含まないので、実時間はこれより長くなります。 それでも 5090 なら昼休みに1周終わり、Vulkan だと映画1本ぶん待たされる、という差は変わりません。

もうひとつ、tok/s の読み方の注意を前編から再掲します。これは単発実行ではなく、並列スロット4の条件での1ストリーム tok/s です。 モデルカードの 233.4 tok/s は batch size 1・貪欲デコードでの多様プロンプト平均なので、条件が違います。

DFlash が効いていることは4環境すべてで共通です。モデルカードは RTX5090 で「投機なし 74.9 → DFlash あり 233.4 tok/s(3.1倍)」と書いています(モデルカード掲載値。筆者の実測ではありません)。その公称ベースライン 74.9 を、RTX3090 の DFlash あり 84.8 が上回っているのが今回おもしろいところです。世代が2つ違うカードでも、投機的デコードを噛ませれば 5090 の非投機に並ぶ、という読み方ができます(条件が揃っていない比較なので、自信度 MODERATE)。

連載の記録に置くと、3090 + DFlash の 84.8 tok/s は「dense 30B としては速いが、小型 MoE/MTP モデルには遠く及ばない」位置です。過去最速は DeepSeek-V4-Pro-Qwen3.5-4B-MTP の ~424.7 tok/s(2026-08-02 記事、40タスク版・単発実行)。単発と並列4という条件差があるので直接は比べられませんが、桁の感覚として置いておきます。

同じ石で ROCm と Vulkan が 1.9倍違う

見落とされがちなところを強調します。8060S の2本は、GPU もモデルも設定も同じで、llama.cpp のビルドだけが違います。 それで 32.7 と 17.3、1.89倍の開きが出ました。

AI MAX+ 395 のような APU を買った人にとって、これは「どのビルドを使うか」だけで待ち時間が半分になるという話です。8060S を使うなら ROCm ビルド一択、というのが今回の実測から言える実用的な結論です。

ただし注意点があります。Vulkan ビルドは3枚のGPU(3090・5090・8060S)がすべて見えていた環境で、`GGML_VK_VISIBLE_DEVICES=2` による指定で 8060S に固定しています。マルチGPU環境の Vulkan は初期化の挙動が読みにくいので、この 17.3 tok/s が「Vulkan バックエンド一般の性能」だと一般化はできません(自信度 MODERATE)。


解決力:5runs 同士で比べると、遅い 3090 のほうが上だった

ここからは 5090 と 3090、同じ5runs 同士の比較です。

図2: tok/s は 10.5倍の滑り台、Resolved はほぼ横ばい

結論: tok/s が半分以下の 3090 のほうが、Resolved で 1.6pt、Combined で 1.0pt 上。ただしこれは 3090 が賢いのではなく、同一条件を2回引き直しても 1〜2問ぶん動くという意味です。

差の中身を見ると、動いたのは60問中3問だけでした。

Resolved の 1問差は、t021 が 2/5 → 4/5 に上がって過半数を跨いだ、それだけです。t048 は逆に 5/5 → 4/5 に落ちています。

そして前編で「連載の鬼門」と書いた t020 が、3090 では 5/5 の完全通過でした。5090 では 3/5 だったタスクです。前編で「このタスクの通過/失敗は再帰下降パーサを引くか操車場アルゴリズムを引くかのくじ引きになっている」と書きましたが、その読みがそのまま裏付けられた格好です。ハードを変えたら、たまたま5回とも当たりを引いた。

教訓を先に書きます。この連載のスコアは、モデルも量子化も変えなくても ±2pt 程度は動きます。(厳密には今回動かしたのはカードなので、「まったく同じ条件での引き直し幅」ではなく、その上限の目安です) モデル比較の記事で 1〜2pt の差を見たら、それは実力差ではなく引き直しの範囲だと思ってください。筆者自身、過去記事でこの幅の差に意味を持たせて書いたことがあります。今回の実測はその自戒でもあります。


参考:8060S の2本のスコア(1run・留保つき)

こちらは単発なので、上の表とは分けて置きます。

4環境の Resolved は 95.0〜98.3%、幅は 3.3pt。 しかも 1run の2本は多数決が使えないぶん構造的に不利な条件です。この幅の中で環境の優劣を語ることはできません(自信度 HIGH)。

Vulkan の Quality 83.9 と 🟢自律 42/60 が4環境で最高になっていますが、これも単発の上振れの範囲です。「Vulkan のほうが質の高いコードが出る」とは書きません。


難易度別:どの帯でも速度差だけが素直に効く

図3: 難易度別の tok/s と Resolved — 曲線の形が4環境で同じ

easy・medium が突出して速く、hard 以降はゆるやかに下がって frontier で底を打ち、architect でわずかに戻る。この形が4環境でまったく同じです。 難しいタスクほど長い推論を書き、長い推論ほど DFlash の受理率が下がって遅くなる。frontier → architect の反転まで4環境そろって起きているのは、曲線の形が環境に依存しないことの分かりやすい証拠です。この形が環境で変わらないというのは「速度差はハードの素の性能差であって、DFlash の効き方が環境で変わっているわけではない」ことを示します(自信度 MODERATE。今回は受理率そのものを記録していません)。

Resolved が落ちるのは expert 帯(t021)と architect 帯(t046 / t058 / t059)の2つだけで、architect は 19 / 19 / 18 / 17 と、1run の2本がわずかに低いだけです。

逆に言うと easy から frontier までは4環境とも天井に張り付いています。 前編では同じ問題に当たったので L7(grandmaster 16問)を新設しましたが、今回は所要時間の都合で L7 を回していません。 Vulkan で L7 を5runs 回すと丸一日仕事になります。環境比較を上位帯まで伸ばすのは次回の宿題です。


t059:4環境すべてで全滅。しかも生成コードがバイト単位で一致した

今回いちばん強い証拠が出たのがこれです。

前編で「連載最強の壁」と書いた t059(浮動小数点の総和が真値からドリフトする)は、4環境すべてで一度も通りませんでした。 5090 5/5 失敗、3090 5/5 失敗、ROCm 1/1、Vulkan 1/1 — 合計 12試行すべて失敗です。

そして生成された `fsum.py` は、4環境で md5 が完全一致しました。

c2a4b499caaaa21175f19a51bdd0e1c4  5090 CUDA   /t059/generated/fsum.py
c2a4b499caaaa21175f19a51bdd0e1c4  3090 CUDA   /t059/generated/fsum.py
c2a4b499caaaa21175f19a51bdd0e1c4  8060S ROCm  /t059/generated/fsum.py
c2a4b499caaaa21175f19a51bdd0e1c4  8060S Vulkan /t059/generated/fsum.py

`llm_output.txt` も `test_output.txt` も4環境で同一ハッシュです(`llm_output.txt` に残るのは思考部分を除いた最終回答だけで、t059 の場合は186バイト・11行しかありません)。

図4: t059 と、環境で判定が割れた3問

中身はこれ。

def total(values):
    s = 0.0
    c = 0.0
    for v in values:
        y = v - c
        t = s + y
        c = (t - s) - y
        s = t
    return s

教科書的な Kahan 加算。前編で書いたとおり、`[1.0, 1e16, 1.0, -1e16]` のような「大きい項が後から来る」入力では補正項自体が失われ、素朴な `sum()` と同じ 0.0 を返します。必要なのは Kahan-Babuška-Neumaier か `math.fsum` です。

なぜこれが「ハードの問題ではない」ことの決定的な証拠になるか。 3つあります。

  1. 落ちる計算はGPUで走っていません。 生成された `total()` は CPython の float(IEEE754 binary64)を CPU で回すだけです。GPU と計算バックエンドが関与するのは「トークンを生成するところ」だけで、「テストを実行するところ」には一切関わりません。

  2. 推論の長さは環境ごとにバラバラです。 completion_tokens は 5090 が 1,237、3090 が 887、ROCm が 822、Vulkan が 1,323。最大60%違います。同じ答えに、違う長さの思考で辿り着いている。そこに至る道は環境ごとに別なのに、出てきた答えは1バイトも違わない。

  3. temp 1.0 で12回引いて、別解が出た形跡がありません。 artifacts に残るのは1タスク1試行分なので、md5 まで照合できるのは4環境ぶんの4件です。ただし12試行すべて Quality 86.3・9行で完全に同値なので、残る8試行も同じ Kahan だったと見ています(自信度 HIGH)。

つまり t059 は、モデルの分布に「Kahan」という強力なアトラクタがあって、そこから抜け出せない。ハードを変えても量子化を変えても抜けられない、モデル側の知識の穴です(自信度 HIGH)。 割るならプロンプトで手法を指定するしかありません。


バックエンドの数値差より、サンプリングの揺れのほうが支配的だった

ここが今回いちばん技術的に面白かったところです。

「ROCm と CUDA では行列演算の丸めが違うから、出てくるコードも系統的に変わるのでは」と考えるのが自然です。実際に測りました。各タスクで保存された生成コードのハッシュを、環境のペアごとに突き合わせます。

図5: 生成コードの一致率 — 同じバックエンド同士も、違うバックエンド同士も、変わらない

4環境すべてで一致したのは 18/60

結論: 一致率にバックエンドのシグナルはまったく乗っていない。同じ CUDA 同士(43.3%)と、NVIDIA↔AMD(38.3〜46.7%)が完全に同じ帯に収まっている。

  • 同じバックエンド同士(CUDA vs CUDA): 26/60 = 43.3%

  • 違うバックエンド同士(5ペアの合計): 127/300 = 42.3%

  • Fisher の正確検定で p = 0.887、オッズ比 1.04

差はありません。 それどころか、最も一致率が高かったのは 5090(NVIDIA / CUDA)と 8060S(AMD / ROCm)という、ベンダも計算バックエンドもコンテキスト長も違う組み合わせでした。

結論: temp 1.0 でのサンプリングの揺れが、バックエンドの数値差を完全に覆い隠しています(自信度 MODERATE)。

自信度を MODERATE にしているのは、方法に2つ弱点があるからです。比較しているのは各タスク1試行分だけで、しかも5runs の側は「1回でも通ったら通った試行が保存される」仕様なので、抽出条件が1run 側と揃っていません。 また「違うバックエンド同士 127/300」は60タスクを5ペアに重複計上した延べ数で独立ではないので、検定の p 値は目安として読んでください。 「AMD だと出力が変わる」と心配する必要はありません。そもそも同じ CUDA ビルドでも、カードを変えて1回ずつ引けば半分以上は違うコードが出てきます。

一致したタスクの性質も調べました。「易しいタスク」ではなく「短いタスク」です。

一致した18問のほうが、むしろ成功率が低い。 全滅している t059 が一致群に入っているからです。トークンごとの一致確率を q とすれば全体の一致確率はおよそ q のべき乗になるので、出力が長いほど指数的に一致しなくなる。これは純粋なサンプリングノイズの形であって、バックエンド差の形ではありません(自信度 HIGH)。


環境を変えても、出力は壊れなかった

ROCm や Vulkan に切り替えると文字化けや途中打ち切りが起きるのでは、という不安があります。60タスク×4環境=240件すべてを機械的に検査しました。

結論: ROCm でも Vulkan でも、モデルの出力そのものが壊れることはなかった。

失敗理由はすべて `tests failed` か `flaky N/5 passed` で、タイムアウトも接続エラーもゼロ。日本語を含む出力の非ASCII文字の内訳(CJK 734字 / ひらがな 462字 / カタカナ 482字)も 3090・ROCm・Vulkan で完全一致しており、マルチバイト境界の破損もありません(5090 だけ数が違うのは、t021 などで生成物そのものが違うからです)。

唯一の SyntaxError も、モデルのせいではありませんでした。 Vulkan の t058 で `vrange.py` の37行目が壊れていたのですが、

    m = re.match(r'(>=||=':
        return v >= target

同じタスクの `llm_output.txt`(モデルが実際に吐いた生テキスト)を開くと、完全に正常な Python が入っていました。

    m = re.match(r'(>=|<=|>|<|==|=)?(.+)', token)
    if not m:
        return False
    op = m.group(1) or '=='

欠落した2区間はどちらも `<` で始まり `>` で終わる区間です。つまり壊れたのはモデルの出力ではなく、llmbench 側の「出力からコードを取り出してファイルに書く」経路です。 240件でこれ1件、しかも壊れた当のファイルの5行目にある `while len(parts) < 3:` は無傷で残っているので、単純なサニタイザではありません(機序の特定はできていません。自信度 MODERATE)。

自作ベンチのバグを自分で踏んだ格好で、これは筆者の宿題です。 ただし記事としては、「Vulkan で SyntaxError が1件出た」と数字だけ書くとバックエンドの問題に見えてしまうので、ここは分けて書いておきます。


環境で判定が割れた3問も、全部サンプリングの揺れだった

60問中、4環境で判定が割れたのは t021・t046・t058 の3問だけです。全部追いました。

t046(singleton と request のライフタイム) — 8060S の2本で 0/1、CUDA の2本で 3/5。8060S 側はどちらも同じ `TypeError: unhashable type: 'dict'` で落ちています。テストが `req = {}` という dict をリクエストとして渡すので、それを辞書のキーにできない。

# 8060S(ROCm)     : request をそのままキーにした
req_cache = self._request_instances.get(request)
# CUDA(5090/3090) : id() でラップしていた
req_id = id(request)

落ちる原因になった差は `id()` の有無、それだけです。 コード全体は4環境でかなり違います(行数は 41 / 39 / 38 / 29、例外メッセージも変数名もバラバラ)。それでも機能上の分かれ目は「リクエストを辞書のキーにできる形に変換したかどうか」の1点に集約されます。 しかも CUDA 側も 3/5 で、5回中2回は落ちています。Fisher 検定で p = 0.45。バックエンド由来と考える根拠はありません(自信度 HIGH)。

t021(バンカーズ丸め) — ROCm で 0/1、Vulkan で 1/1。ROCm 版の `money.py` は他3環境と1行を除いて完全一致していました。

-from decimal import ROUND_DOWN, ROUND_HALF_EVEN, Decimal                    # ROCm
+from decimal import ROUND_DOWN, ROUND_HALF_UP, ROUND_HALF_EVEN, Decimal     # 他3環境

import から識別子が1個だけ抜けて、`NameError: name 'ROUND_HALF_UP' is not defined`。 典型的な単一トークンのスリップです。しかも判定の割れ方が 5090 NG / 3090 OK / ROCm NG / Vulkan OK と、バックエンドの境界を横断しています。

t058 — 上に書いたハーネス側の書き出し事故です。

3問とも、バックエンド由来ではありませんでした。 2問は引き直しの揺れ、1問は自作ベンチ側の事故です。


まとめ

  • 同じモデル・同じ Q4_K_XL・同じサンプリングで、走らせる場所だけを4つ変えた。tok/s は 182.6 / 84.8 / 32.7 / 17.3 で、上から下まで 10.5倍。

  • 5runs 同士で比べられる 5090 と 3090 では、遅い 3090 のほうが Resolved で 1.6pt 上(96.7% → 98.3%)。差の中身は 60問中4問、実質は t021 が過半数を跨いだ1問。

  • これがこのベンチの誤差の目安。同じ条件で引き直すと ±2pt は動く。 1〜2pt の差に実力差を読んではいけない。

  • 同じ 8060S で、ROCm ビルドは Vulkan ビルドの 1.89倍速い。 AI MAX+ 395 を使うなら ROCm 一択。

  • RTX3090 + DFlash の 84.8 tok/s は、モデルカードが載せる「5090・投機なし」の 74.9 を上回る(条件は揃っていない。自信度 MODERATE)。

  • t059 は4環境12試行すべてで全滅し、生成コードの md5 まで一致した。 ハードでも量子化でもなく、モデルの知識の穴。

  • 生成コードの一致率は、同じバックエンド同士 43.3%、違うバックエンド同士 42.3%(Fisher p = 0.887)。 バックエンドの数値差はサンプリングの揺れに完全に埋もれている。

  • ROCm・Vulkan で出力が壊れることはなかった。 240組で文字化け・打ち切り・パース失敗はゼロ。唯一の SyntaxError は自作ベンチの書き出しバグ。

今回の教訓:「環境を変えたら結果が変わった」と言う前に、同じ環境で引き直したときどれだけ動くかを測っておく。 それをやらずに環境差を語ると、引き直しのノイズを性能差だと言ってしまいます。今回 3090 が 5090 に勝ったのは、まさにそのノイズです。

用途別に1行ずつ書いて締めます。

  • 速度が要るなら RTX5090。 60タスク1周が約11分。ほかは何を選んでも倍以上待つ。

  • RTX3090 は現役。 半分の速度だが解決力は落ちない。VRAM 24GB に Q4_K_XL(22.7GB)がぎりぎり載る。

  • AI MAX+ 395(8060S)を使うなら ROCm ビルド。 Vulkan の1.89倍。ただし 5090 の 0.18倍で、実用は「待てる作業」に限られる。

  • Vulkan は逃げ道として持っておく。 出力が壊れることはなかったので、ROCm が動かない環境での保険にはなる。


検証で生成したコード・テスト結果はアーカイブ済みです。「特定タスクの詳細が見たい」「自分の環境でも試したい」はコメントへどうぞ。


モデル情報

関連記事

  • 前編:連載の鬼門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)

  • くーるぜろの記事一覧: https://note.com/zephel01

#ローカルLLM #llamacpp #ベンチマーク #量子化 #GGUF #MuseGlimmer #DFlash #ROCm #Vulkan #RTX3090 #AIMAX395

いいなと思ったら応援しよう!

zephel01 サーバー代とコーヒー代になります☕ 役に立ったら応援よろしくお願いします!