Ryzen AI Max+ 395でローカルLLMが快適になった
前回記事:「Ryzen AI Max+ 395でローカルLLMの地獄を見たの巻」を書いた数日後、最新のスタック(ROCm 7.2.4 / llama.cpp b9672 / vLLM 0.23.0)で、もう一度全部やり直してみました。そうしたら世界がだいぶ変わっていたんです。
- 念願だった GPT-OSS-120B が、GPU で動いた。
- 一度も推論に届かなかった vLLM が、gfx1151 で初めて立ち上がった。
- 最近出たばかりの Qwen3.6-35B-A3B が、すんなり動いて、しかも 120B より賢い。
- 動かなかった HIP も、安定して動くようになった。
- そして、前回いちばん叩いた壊れたファーム(MES 0x83)も、なぜか今は普通に動く。理由は分かりません。
「普通に動く」レベルになっていました!
前回「ファームを手で差し替える儀式」をさんざん書きましたが、今回はそれも要りませんでした。ROCm/カーネルをアップデートしているうちに、いつのまにか hang しなくなっていた。なぜ直ったのかは正直よく分からないのですが、ともかく動く。というわけで、ここからは前回動かなかったものが、動くようになった話です。
GPT-OSS-120B が動いた!
前回、初期に引いて「使えなかった」大物のひとつが GPT-OSS-120B(OpenAI 製、128エキスパート MoE・top-4、116.8B total / 5.1B active、ネイティブ MXFP4)でした。今回ちゃんと向き合ったら、GPU で普通に動きました。
私は最初、「MXFP4 は gfx1151 では動かない、Q4_K_M に変換しないとダメだ」と結論づけていました。 でもこの記事を書くにあたって実機で測り直したら、それが誤りだったんです。最新の llama.cpp(b9672)+ Vulkan で、MXFP4 GGUF も Q4_K_M GGUF も、両方 GPU で動きました。
| フォーマット | フレームワーク | 結果(b9672, Vulkan, 実測) |
|---|---|---|
| MXFP4 GGUF(59GB) | llama.cpp Vulkan | GPU 動作 ✅ pp512 458.6 / tg128 54.5 t/s |
| Q4_K_M GGUF(58GB) | llama.cpp Vulkan | GPU 動作 ✅ pp512 486.9 / tg128 59.8 t/s |
| MXFP4 safetensors(61GB) | vLLM 0.23.0 | VRAM に 88% 載るのに GPU 計算されず(CPU 寄り)、5.6 t/s |
MXFP4 が CPU 落ちするのは、llama.cpp ではなく vLLM/ROCm 経路の話でした。ggml(llama.cpp)は gpt-oss をネイティブ MXFP4 のまま CUDA/Vulkan/Metal/CPU で実行できる実装を持っていて、gfx1151 でも Vulkan 経由でちゃんと GPU に乗る。私が以前「CPU 落ち」と見たのは、おそらく古いビルドか別経路のものでした。
一方、MXFP4 が本当に GPU で動かないのは vLLM/ROCm 側です。理由は、MXFP4 のネイティブ MoE カーネルがデータセンター/Instinct 系に偏っているから(あくまで vLLM の文脈での話):
| GPU | vLLM での MXFP4 カーネル |
|---|---|
| NVIDIA Blackwell(B200 等) | FlashInfer(ネイティブ MXFP4 テンソルコア) |
| NVIDIA Hopper(H100/H200) | Triton matmul_ogs |
| AMD MI300x / MI355x(CDNA) | Triton(Instinct 専用) |
gfx1151(RDNA 3.5)には vLLM 用の MXFP4 カーネルが無く、Triton のコンパイルがこける/--enforce-eager 強制で実質 CPU 寄りになる。VRAM には 68.7GB 載っているのに GPU 計算されない、という「載るのに動かない」構造です。(なお MXFP4 は OCP のオープン標準フォーマットで、「データセンター専用」なのはフォーマットではなくネイティブ実装のほう。コンシューマ Blackwell ですらネイティブ FP4 非対応で Marlin に落ちる、というくらいカーネル事情はバラバラです。)
実用上の結論は、GPT-OSS-120B を gfx1151 で GPU 推論するなら llama.cpp Vulkan。フォーマットは MXFP4 GGUF(ネイティブ品質を保てる)でも Q4_K_M GGUF(やや速い)でも、どちらも GPU で回る。私の実測では Q4_K_M が tg 59.8、MXFP4 が 54.5 で、速度はわずかに Q4 が上、品質はネイティブの MXFP4 が上、というトレードオフでした。
116B クラスの MoE が、この箱で 55〜60 t/s で生成できる。前回「72B は秒3トークンで会話にならない」と書いたことを思えば、MoE(active 5.1B)の威力と相まって、隔世の感があります。
gfx1151でvLLM も動いた!
前回、いちばん悔しかったのが vLLM でした。「あらゆる手段を試して全滅。一度も推論に到達せず」。amdsmi のシンボル不一致で、import すら通らなかった。
それが今回vLLM 0.23.0(PyTorch 2.10.0)で、gfx1151 で初めて動きました。 import から推論まで、ちゃんと通った。「no longer working」の残骸ではなく、本当に動く vLLM が手元に立った。
ただし正確に書くと、gfx1151 は upstream vLLM の公式サポート GPU には入っていません。動かすにはコミュニティのパッチ(amdsmi のモック注入、CMakeLists で gfx1151 指定など)が前提で、素の wheel が自動で動くわけではない(公式 wheel タグも +rocm722、依存は ROCm 7.2.3)。前回 amdsmi で門前払いだったのが、パッチ込みなら推論に到達するところまで来た、というのが正確なところです。
踏んだバグと対処:
-
prometheus_fastapi_instrumentatorが_IncludedRouterのpath属性を読めずAttributeError(FastAPI 0.137 のinclude_router仕様変更が原因。vLLM 0.23.0 で再現、Issue #45596/#45597)→pathアクセス前にhasattrガードを足して回避。 -
ゾンビプロセスが VRAM を解放しない。vLLM の EngineCore 等が落ちても VRAM を掴んだまま(VRAM 非解放は Issue #23793 等で既知)。
sudo fuser /dev/dri/renderD128で掴んでいるプロセスを特定してkill -9で回収。これは地味にハマるので注意。
そして正直に書くと:MXFP4 モデルは vLLM では GPU 計算されません(上で書いたとおり、RDNA に MXFP4 カーネルが無いため)。vLLM が本来の GPU 推論を出すのは BF16 / AWQ モデルのとき。参考までに、有志の hec-ovi/vllm-awq4-qwen では Qwen3.6-27B AWQ-INT4 が 24.8 t/s と報告されていますが、これは single-stream + DFlash 投機的デコード込み・vLLM 0.20.0 / ROCm 7.13 nightly という別構成での値なので、素の AWQ 性能そのものではない点に注意(私の 0.23.0 環境とも条件が違います)。いずれにせよ「vLLM が動く」と「全モデルが速く動く」は別、というのは前回同様。それでも、門前払いだった vLLM が推論に到達したのは、私にとって大きな一歩でした。
Qwen3.6-35B-A3B がGPT-OSS-120B より賢い!
そして今回の主役。Qwen3.6-35B-A3B(MoE、35B total / 3B active、Q4_K_M で 21GB、コンテキスト 262K ネイティブ・YaRN で最大 1M、テキスト/画像/動画マルチモーダル、Apache 2.0)。2026年4月15日に出た新しいモデルです。これが、すんなり動いて、提示されたベンチでは GPT-OSS-120B を上回る。
公開ベンチの比較がこれです。ただし重要な留保を先に:この比較表は Qwen 公式が出したものではありません。Qwen 公式 README には GPT-OSS-120B の列は無く、私が Qwen 公式値(Qwen の土俵)と OpenAI 公式値(OpenAI の土俵)を別々のソースから並べた合成です。Qwen 側は自己申告・自前 scaffold、GPT-OSS 側は high reasoning 設定で、条件が非対称な点は割り引いて読んでください。
| ベンチマーク | Qwen3.6-35B-A3B | GPT-OSS-120B (high) | 優位 |
|---|---|---|---|
| GPQA Diamond(PhD級科学) | 86.0 | 80.1 / 80.9(tools) | Qwen |
| SWE-bench Verified(実コード) | 73.4 | 62.4 | Qwen |
| HLE(難問推論) | 21.4 | 14.9 / 19.0(tools) | Qwen |
| AIME(競技数学) | 92.7(AIME 2026) | 92.5 / 97.9(tools)(AIME 2025) | 年度が別/tools込みでGPT-OSS |
それから、AIME は出題年度が違います(Qwen は 2026、GPT-OSS は 2025 で、同じ試験ではない)。SWE-bench も Qwen は自前 agent scaffold(200K ctx, temp=1.0)での自己申告で、scaffold が変われば数字は大きく動く。ツール込みの数学では GPT-OSS-120B(97.9)が Qwen(92.7)を上回るので、「全項目で勝ち」ではありません。
それでも、総パラメータ約 1/3(35B vs 117B)、アクティブ 3B の小さいモデルが、提示したベンチの多く(GPQA・HLE・SWE-bench)で 9 ヶ月前の 120B を上回るのは事実。世代差(GPT-OSS-120B は 2025年8月、Qwen3.6 は 2026年4月)が効いています。条件差に留意した上で、ここで挙げたベンチでは Qwen3.6 が優勢、というのが誠実な言い方でしょう。しかもテキスト・画像・動画のマルチモーダル対応。
ローカル運用の観点でも、アクティブ 3B という極端なスパース比のおかげで、メモリにもスループットにも余裕が出る。**「大きいほど賢い」が崩れて、「新しくて小さい方が賢くて軽い」**という、モデル進化の恩恵をまるごと受けられる。前回 72B で絶望したこの箱に、いちばん刺さる進化でした。
Vulkan vs HIP
前回「llama.cpp は HIP では動かず Vulkan 一択」と書きました。今回、HIP(ROCm ネイティブ)が gfx1151 で実用速度で回りました(同条件・サーバ停止で実測)。
| バックエンド(b9672) | pp512 | tg128 |
|---|---|---|
| HIP(ROCm 7.2.4) | 1083.8 t/s | 52.7 t/s |
| Vulkan | 1018.4 t/s | 63.1 t/s |
プロンプト処理は HIP がわずかに速く(+6%)、生成速度は Vulkan が 17% 上回る。体感に効くのは tg なので、総合では Vulkan が最適解。ただ、HIP がこの速度でちゃんと回ること自体が前回からの前進です(前回は HIP バックエンドが gfx1151 でまともに動かず Vulkan しか選べなかった)。
Thinking モードの動的切り替え
Qwen3.6 はデフォルトで Thinking(思考)モード。私の環境(b9672)では、API レベルで動的に切り替えられました。
| 方法 | 効果(私の環境での挙動) |
|---|---|
chat_template_kwargs: {enable_thinking: false / true} |
OFF/ON 切り替え(動作確認済み) |
thinking_budget_tokens: 0 |
効かなかった(※下記注) |
/no_think(プロンプト内) |
モデルは認識する |
--reasoning-budget 0(サーバ起動時) |
API パラメータを上書きしてしまう |
重要な罠:サーバ起動時に --reasoning-budget や --reasoning off を指定すると、API レベルのパラメータが上書きされて動的切り替えができなくなります。起動時はこれらを指定せず、--reasoning-format deepseek のみ指定するのが正解。ストリーミングは SSE 対応で、reasoning_content(思考)が先に流れ、完了後に content(回答)が流れます。
補足(裏取りで分かったこと):この reasoning 制御まわりは、llama.cpp 側で仕様変更が続いている過渡期です。
thinking_budget_tokensは「起動時に--reasoning-budgetを指定していなければ per-request で効く」のが本来の挙動(Discussion #21445)で、私が「効かない」と見たのは起動時に budget を固定していたせい。またchat_template_kwargs経由のenable_thinkingは新しめのビルドでは deprecated 化して--reasoning on/offへの誘導警告が出る報告もあります。要するにどの llama.cpp ビルドかで挙動が変わるので、上表は「b9672 時点の私の環境」と読んでください。
20K コンテキストを実用にする ― プレフィックスキャッシュ
実アプリから 20K トークンのコンテキストを毎回投げると、毎回 ~27秒のプリフィルが走る、という問題に当たりました。原因と対処が綺麗に分かれたので記録しておきます。
原因:
| 問題 | 詳細 |
|---|---|
--cache-ram デフォルト 8GB |
20K トークンの KV checkpoint を保存するには不足 |
--parallel 2 |
リクエストが slot 0/1 に分散し、前回の KV が別スロットに行く |
| LCP similarity 23% | 共通プレフィックスが少なく、ほぼ全再計算 |
対処:
| 設定 | 変更前 | 変更後 |
|---|---|---|
--parallel |
2 | 1(同一スロットに毎回当たり KV 再利用) |
--cache-ram |
8192 (8GB) | 32768 (32GB)(大きな KV checkpoint を保存可能) |
結果:
| リクエスト | プロンプト処理 | キャッシュヒット |
|---|---|---|
| 1回目(cold) | 578ms / 69tok | 0 tokens |
| 2回目(warm) | 100ms / 17tok | 53 tokens(5.8倍速) |
単一ユーザーなら --parallel 1 に倒すのが正解、というのが結論。20K コンテキストでも、2回目以降は共通プレフィックス分がキャッシュされて差分のみ再計算になります。(注:--cache-reuse 自体は別の n_cache_reuse による部分再利用機能で、Qwen3.6 のような MoE モデルでは効かず「cache reuse is not supported」と出ます。当初これを「Vulkan 非対応」と書いていましたが、裏取りしたらバックエンドではなくモデルアーキ(MoE/SWA 等)が理由でした。上の host-memory prompt cache(--cache-ram)とは別の機能です。)
現在の常用構成
最終的に、こう落ち着きました。
llama-server \
-m ~/models/Qwen3.6-35B-A3B-UD-Q4_K_M.gguf \
--host 0.0.0.0 --port 8081 \
-ngl 99 -c 262144 --parallel 1 \
--cache-ram 32768 \
--reasoning-format deepseek
| 項目 | 値 |
|---|---|
| バックエンド | Vulkan(b9672, UMA最適化済み) |
| コンテキスト | 262144(256K) |
| VRAM 使用量 | ~28GB / 96GB |
| 生成速度 | 60-61 t/s |
| プロンプト処理 | 1037 t/s(ベンチ) |
| キャッシュ | 32GB host-memory prompt cache |
| 思考モード | API 動的切り替え対応 |
前回「Gemma 4 26B + 128K が一本道」と書いたところから、Qwen3.6-35B-A3B + 256K + プレフィックスキャッシュまで来ました。256K がちゃんと常用できているのも、前回「256K は箱ごと死ぬ」と書いたことを思うと、大きな変化です(モデルが MoE で active 3B、KV が軽いのも効いています)。
ベンチマーク一覧
(pp512/tg128。GPT-OSS と Qwen3.6 Vulkan(b9672) は今回あらためて実機で測り直した値です。)
| モデル | フレームワーク | 量子化 | バックエンド | GPU | pp512 | tg128 |
|---|---|---|---|---|---|---|
| GPT-OSS-120B | llama.cpp b9672 | MXFP4 | Vulkan | ✅ GPU | 458.6 | 54.5 |
| GPT-OSS-120B | llama.cpp b9672 | Q4_K_M | Vulkan | ✅ GPU | 486.9 | 59.8 |
| GPT-OSS-120B | vLLM 0.23.0 | MXFP4 | ROCm | ❌ CPU | - | 5.6 |
| Qwen3.6-35B-A3B | llama.cpp b9672 | Q4_K_M | Vulkan | ✅ GPU | 1018 | 63.1 |
| Qwen3.6-35B-A3B | llama.cpp b8797 | Q4_K_M | Vulkan(旧版・同スタック対照) | ✅ GPU | 1009.7 | 60.7 |
| Qwen3.6-35B-A3B | llama.cpp b9672 | Q4_K_M | HIP | ✅ GPU | 1083.8 | 52.7 |
素晴らしいハードにソフトとモデルが追いついてきた
アップデートで確実に良くなりました。
- モデルの進化:72B で絶望した箱に、35B/3B の Qwen3.6 が「120B より賢く、軽く」収まる。「大きいほど賢い」が崩れて、この箱の帯域の天井に、モデルのほうが歩み寄ってきた。
- ソフトの成熟:最新版に更新することで、HIP が安定動作、vLLM が初めて推論に到達、MXFP4 も Vulkan で GPU に乗る、ファームもなぜか正常動作。前回「Vulkan 頼み」と嘆いた状況が、選択肢のある世界に変わりつつある。
自分は新しいものが出たらすぐに試したくなるんで、人柱になりましたが、今から買う人はかなりすんなり動かせるのではないかと思います。ただ、メモリ帯域はハードウェア固定なので、NVIDIAよりは遅いと思いますけど、大容量VRAMがあるのは楽しいです。
参考リンク
- vLLM Now Supports gpt-oss(FlashInfer / Triton matmul_ogs / AMD MI300x の MXFP4 カーネル対応)
- ggml の gpt-oss ネイティブ MXFP4 対応(llama.cpp Discussion #15095)
- llama.cpp — host-memory prompt caching(PR #16391 / Discussion #20574)
- llama.cpp — per-request reasoning toggle(Discussion #21445)
- llama.cpp Vulkan UMA host-visible buffers(PR #22930)
- kyuz0/amd-strix-halo-vllm-toolboxes(Strix Halo で vLLM を動かすツールボックス)
- hec-ovi/vllm-awq4-qwen(Qwen3.6-27B AWQ-INT4 + DFlash の 24.8 t/s 報告元)
- vLLM 0.23.0 リリースノート
- ROCm Issue #5724 — MES 0x83 GPU Hang(gfx1151 のファーム問題)
- Qwen3.6-35B-A3B(HuggingFace) / unsloth GGUF
- GPT-OSS モデルカード(arXiv:2508.10925)
- Strix Halo ローカル LLM ガイド
- 前回記事:「Ryzen AI Max+ 395でローカルLLMの地獄を見たの巻」
Discussion