前回・前々回の記事でQwen3.5-35B-A3Bのチューニングまで終えたところで、Qwen3.6とGemma 4が立て続けにリリースされた。どちらもHX370のUMA環境に向いていそうな構成(Qwen3.6はMoE、Gemma 4はQATモデル)だったので、単純に乗り換えて試してみた記録。llama.cppの更新でハマったポイントも含めて残しておく。
結論から言うと、速度はGemma 4 26B-A4B(QAT)がpp・tgともに1.5倍前後優位だが、ワンショットのコーディングではQwen3.6に軍配が上がるという結果になった。
環境
- マシン: MINISFORUM HX370
- GPU: AMD Radeon 890M(RDNA 3.5 / gfx1150、UMA 64GB)
- OS: CachyOS Linux
- バックエンド: Vulkan
- 対象モデル:
Qwen3.6-35B-A3B-UD-Q4_K_M.gguf、gemma-4-26B-A4B-it-qat-UD-Q4_K_XL.gguf(いずれもUnsloth製GGUF)
llama.cppの更新(8183 → 9941)
手元のllama.cppは3月時点のビルド(version 8183)のままだった。Gemma 4のアーキテクチャ自体が新しいため、まずソースを更新する必要があった。
cd ~/src/llama.cpp
git pull origin master
ビルドエラー:SPIRV-Headersが見つからない
再ビルドしたところ、Vulkanバックエンドのconfigureで詰まった。
CMake Error at ggml/src/ggml-vulkan/CMakeLists.txt:14 (find_package):
Could not find a package configuration file provided by "SPIRV-Headers"
以前のビルドでは問題にならなかった箇所だが、ggml-vulkan/CMakeLists.txtを見るとfind_package(SPIRV-Headers CONFIG REQUIRED)が新たに要求されるようになっていた。CachyOSはArch系なので、単純にパッケージを追加すれば解決した。
sudo pacman -S spirv-headers
これでconfigureが通り、ビルドも完了した。
更新後の確認
./build-vulkan/bin/llama-server --version
version: 9941 (683f0c72e)
built with GNU 16.1.1 for Linux x86_64
コミットログでGemma 4関連の対応が入っていることも確認できた。
git log --oneline --all | grep -i "gemma.4\|gemma4"
dbe9c0c8c convert : support Gemma4ForCausalLM architecture (#23682)
04eb4c446 llama : add Gemma4 MTP (#23398)
c8d6a0063 mtmd: enable non-causal vision for gemma 4 unified (#24082)
...
convertのアーキテクチャ対応、MTP対応、マルチモーダル(mtmd)対応まで一通り取り込まれていることが確認できたので、これで両モデルを動かす準備が整った。
新モデルのダウンロード
Qwen3.6-35B-A3B
Qwen3.5-35B-A3Bの直接の後継。総パラメータ35B・アクティブ3BというMoE構成は変わらないので、既存のsystemdサービス(llama-server.service)のモデルパスを差し替えるだけで済む。
cd ~/src/llama.cpp/models
hf download unsloth/Qwen3.6-35B-A3B-GGUF \
--include "Qwen3.6-35B-A3B-UD-Q4_K_M.gguf" \
--local-dir .
Gemma 4 26B-A4B(QAT版・マルチモーダル)
Gemma 4はGoogleの新しいオープンモデルファミリーで、26B-A4Bは総パラメータ26Bのうち実働4B相当というMoE構成。QAT(Quantization-Aware Training)版は素の量子化より精度を維持しつつファイルサイズが小さいので、そちらを選んだ。マルチモーダル対応のためmmprojも一緒に取得する。
hf download unsloth/gemma-4-26B-A4B-it-qat-GGUF \
--include "gemma-4-26B-A4B-it-qat-UD-Q4_K_XL.gguf" \
--include "mmproj-BF16.gguf" \
--local-dir .
ベンチマーク実測
テスト条件
--n-prompt 1024 --n-gen 0(プロンプト処理速度のみ計測)と--n-prompt 0 --n-gen 256(生成速度のみ計測)の2種類--n-gpu-layers 99 --flash-attn on- batch-size / ubatch-sizeは128・256・512の組み合わせで計測(pp計測時のみ)
ベンチマークコマンド
プロンプト処理速度(pp)とbatch/ubatchの組み合わせを一度に見るためのコマンド。Qwen3.6・Gemma 4ともにモデルパスを差し替えるだけで同条件で計測している。
cd ~/src/llama.cpp
# Qwen3.6-35B-A3B
./build-vulkan/bin/llama-bench \
-m ./models/Qwen3.6-35B-A3B-UD-Q4_K_M.gguf \
--n-prompt 1024 \
--n-gen 0 \
--batch-size 128,256,512 \
--ubatch-size 128,256,512 \
--n-gpu-layers 99 \
--flash-attn on
# Gemma 4 26B-A4B(QAT)
./build-vulkan/bin/llama-bench \
-m ./models/gemma-4-26B-A4B-it-qat-UD-Q4_K_XL.gguf \
--n-prompt 1024 \
--n-gen 0 \
--batch-size 128,256,512 \
--ubatch-size 128,256,512 \
--n-gpu-layers 99 \
--flash-attn on
生成速度(tg)は、pp側で最も速かった設定(batch=512 / ubatch=512)に固定して別途計測した。
./build-vulkan/bin/llama-bench \
-m ./models/Qwen3.6-35B-A3B-UD-Q4_K_M.gguf \
--n-prompt 0 --n-gen 256 \
--batch-size 512 --ubatch-size 512 \
--n-gpu-layers 99 --flash-attn on
./build-vulkan/bin/llama-bench \
-m ./models/gemma-4-26B-A4B-it-qat-UD-Q4_K_XL.gguf \
--n-prompt 0 --n-gen 256 \
--batch-size 512 --ubatch-size 512 \
--n-gpu-layers 99 --flash-attn on
注意: 今のバージョン(9941)では
--flash-attnの指定値が0/1ではなくon/off/auto形式に変わっている。旧バージョンの記事のコマンドをそのまま使い回す場合は要注意。
結果:プロンプト処理速度(pp1024)
Qwen3.6-35B-A3B
| batch-size | ubatch-size | pp t/s |
|---|---|---|
| 128 | 128 | 239.59 |
| 128 | 256 | 237.93 |
| 128 | 512 | 237.14 |
| 256 | 128 | 225.44 |
| 256 | 256 | 302.25 |
| 256 | 512 | 303.89 |
| 512 | 128 | 225.49 |
| 512 | 256 | 291.21 |
| 512 | 512 | 344.11 |
Gemma 4 26B-A4B(QAT)
| batch-size | ubatch-size | pp t/s |
|---|---|---|
| 128 | 128 | 280.16 |
| 128 | 256 | 284.75 |
| 128 | 512 | 270.72 |
| 256 | 128 | 270.26 |
| 256 | 256 | 390.24 |
| 256 | 512 | 375.77 |
| 512 | 128 | 276.46 |
| 512 | 256 | 401.84 |
| 512 | 512 | 518.94 |
前回のQwen3.5検証と同様、batch-sizeとubatch-sizeを揃えたときに性能が跳ね上がる傾向が両モデルで再現された。ubatch=128に固定すると、batchをいくら上げても頭打ちになるのも共通している。Vulkanバックエンド特有の癖として定着しつつある。
結果:生成速度(tg256)
最速設定(batch=512 / ubatch=512)で比較。
| モデル | サイズ | 実働パラメータ | pp1024 | tg256 |
|---|---|---|---|---|
| Qwen3.6-35B-A3B | 20.60 GiB | 3B | 344.11 t/s | 23.02 t/s |
| Gemma 4 26B-A4B(QAT) | 13.26 GiB | 4B | 518.94 t/s | 30.01 t/s |
考察
ファイルサイズが約35%小さい(13.26 GiB vs 20.60 GiB)Gemma 4の方が、pp・tgともに1.5倍前後速いという結果になった。実働パラメータはGemma 4の方がわずかに大きい(4B vs 3B)にもかかわらずこの差なので、QAT量子化の効率の良さか、Gemma 4のhybrid attention設計がRadeon 890MのUMA帯域と相性が良いか、のどちらかだと思われる。ここは実装の詳細まで踏み込まないと確定的なことは言えないが、体感速度としてはかなり印象的な差だった。
ただしこれは純粋な速度比較であって、コーディングタスクでの精度や日本語の自然さは別軸の話。用途に応じて使い分けるのが妥当だろう。
生成物で試す:テトリスを作らせてみた
速度だけでなく実際の生成物も見ておきたかったので、両モデルに同じお題(「動くテトリスを作って」)を投げてみた。まずはQwen3.6-35B-A3Bの成果物から。
スコア・レベル・ライン数の表示、NEXTピース表示、操作キー一覧まで一式そろっており、動作も問題なさそうだった。
続いてGemma 4 26B-A4Bの結果がこちら。
タイトルやスコア・ライン数表示、操作キー案内といった外枠のUIはQwen3.6と遜色ない見た目に仕上がっている。ただし肝心のプレイフィールドが真っ黒で、ブロックがそのまま下に落ちて闇に消えていくだけになっており、ゲームとして成立していなかった。ベンチマークの数値ではGemma 4が優勢だったが、少なくとも今回のワンショット生成に関してはQwen3.6に軍配が上がる結果になった。プロンプトの与え方やシステムプロンプト次第で変わる可能性はあるので、この結果だけで優劣を決めつけるのは早計だが、「速いモデル=コーディングも得意」とは限らないという当たり前の教訓ではある。
おまけ:Claude Codeからつなぐ
どちらのモデルもClaude Codeのバックエンドとして使いたかったのだが、ここで一つ勘違いをしていた。「llama-serverはOpenAI互換APIしか喋らないので、Claude Code(Anthropic Messages API前提)につなぐには変換プロキシが要る」と思い込んでいたのだが、実際にはllama.cpp本体にPR #17570(2026年1月マージ)で/v1/messagesエンドポイントがネイティブ実装済みだった。プロキシなしで直接つながる。
export ANTHROPIC_BASE_URL="http://127.0.0.1:11434"
export ANTHROPIC_AUTH_TOKEN="dummy"
export ANTHROPIC_API_KEY=""
export ANTHROPIC_MODEL="qwen3.6-local"
export ANTHROPIC_SMALL_FAST_MODEL="qwen3.6-local"
claude
動作確認はcurlで十分。
curl http://127.0.0.1:11434/v1/messages \
-H "Content-Type: application/json" \
-d '{"model": "qwen3.6-local", "max_tokens": 1024, "messages": [{"role": "user", "content": "Hello!"}]}'
一点だけ既知の制約がある。GitHub Issue #20090で報告されている通り、/v1/messagesの変換処理(convert_anthropic_to_oai())は現状thinkingブロックを無言で握りつぶす。Extended Thinkingを使うモデルをマルチターンで使う場合、会話履歴中の推論内容が欠落する可能性があるので、複雑なタスクで違和感がないか一度確認しておいた方がいい。
まとめ
Qwen3.5からQwen3.6への乗り換えは既存構成のマイナーアップデート程度で済んだが、Gemma 4は速度面でかなり優位という予想外の結果になった。しばらくはGemma 4を主力に、精度が気になる場面ではQwen3.6に切り替える運用で様子を見てみたい。
なお今回1Mコンテキストにも挑戦してみたのだが、GPUメモリの壁に思いのほか早くぶつかることになった。こちらは別記事にまとめる。