第1回「EVO-X2(Ryzen AI Max+ 395 / 128GB)でQwen3.8-Flash-Nextを動かした話」
第2回「EVO-X2(Ryzen AI Max+ 395 / 128GB)でQwen3.8-Flash-Nextを高速化した話」
の続き。
第2回の最後では、llama.cpp b10679 と dzannotti/Qwen3.8-Flash-Next-MTP-GGUF の Qwen3.8-Flash-Next-MTP-Q4_K_M.gguf を組み合わせてMTPを試したものの、draft modelのロード時点で失敗した。それから1日もたたないうちにX(旧Twitter)でUnsloth版の新しい情報を見つけたので、早速試してみた。
結論
今回の Unsloth版llama.cpp(b10715-mix-86bd2d3) + ROCm + Qwen3.8-Flash-Next UD-IQ3_XXS ではMTPが正常に動作した。
今回の結果は、llama.cppのb10679 → b10715-mix-86bd2d3のbuild間差と、同じb10715-mix-86bd2d3上でのMTPあり / なしの差の2段階に分けて見る必要がある。
MTPを使わない llama-bench でも、deep-context側の d=126000 は前回のb10679で6.41 tok/s、今回のb10715-mix-86bd2d3で8.12 tok/sと約1.25倍になった。
同じb10715-mix-86bd2d3上で実長文をMTPあり / なしにして比較すると、コンテキスト128KでのTGは8.22 → 13.77 tok/sと1.68倍になった。
以降、Prompt Processing(入力処理 / prefill)を PP、Token Generation(生成 / decode)を TG と表記する。どちらも単位は tok/s で、高いほど速い。
新しくダウンロードしたもの
UnslothのQwen3.8-Flash-Next-GGUF向けMTPモデルが公開されていたので、以下のREADMEに従って試した。
llama.cppも、Unslothが公開している専用のプレビルド版を使用した。
ダウンロードしたのは以下の2種類。
app-b10715-mix-86bd2d3-windows-x64-rocm-gfx1151.zip
app-b10715-mix-86bd2d3-windows-x64-vulkan.zip
新しく展開した b10715-mix-86bd2d3 のROCm版とVulkan版について、第1回の最初と同じように llama-server の起動から簡単な推論までを試した。
今回のEVO-X2環境ではROCm版は正常動作した。一方、Vulkan版はモデルロード後の推論でクラッシュしたため、この後の検証はROCm版だけを使用している。
追記(2026-09-06) クラッシュについては後日解決してVulkan版でも動作するようになっている
自分でビルドしなくても、zipをダウンロードして展開するだけで使えるのはありがたい。
MTP用のドラフトモデルは
から、
mtp-Qwen3.8-Flash-Next-Q8_0.gguf
をダウンロードした。さらに比較用として、
mtp-Qwen3.8-Flash-Next-shared-Q8_0.gguf
もダウンロードした。
MTPを入れる前にllama.cppの違いによる差を測っておく
前回、速度面で一番気になったのが、コンテキストが埋まったときのdecode速度低下だった。
そこでMTPを有効にする前に、まず llama-bench の -d を変えて、前回使った llama.cpp b10679 と、今回のUnsloth b10715-mix-86bd2d3 のbuild間差を確認した。
主な条件は前回と合わせている。
target model : Qwen3.8-Flash-Next UD-IQ3_XXS
ngl : 999
ncmoe : 0
threads : 4
batch : 2048
ubatch : 1024
KV cache : F16
Flash Attn : enabled
generation : 128 tokens
repeat : 3
実行イメージはこんな感じ。
foreach ($d in 0, 32768, 65536, 126000) {
.\llama-bench.exe `
-m "(モデルのパス)\Qwen3.8-Flash-Next-UD-IQ3_XXS-00001-of-00003.gguf" `
-ngl 999 `
-ncmoe 0 `
-t 4 `
-b 2048 `
-ub 1024 `
-fa 1 `
-ctk f16 `
-ctv f16 `
-n 128 `
-d $d `
-r 3
}
b10715-mix-86bd2d3 の結果は以下。
| decode depth | TG |
|---|---|
| 0 | 26.50 tok/s |
| 32,768 | 16.64 tok/s |
| 65,536 | 11.75 tok/s |
| 126,000 | 8.12 tok/s |
前回の b10679 と同条件で比較できる両端を見るとこうなった。
| decode depth | b10679 | b10715-mix-86bd2d3 | 差 |
|---|---|---|---|
| 0 | 27.39 tok/s | 26.50 tok/s | -3.3% |
| 126,000 | 6.41 tok/s | 8.12 tok/s | +26.7% |
d=0では少し遅くなっているが、126K付近ではかなり速くなっている。
MTPのパラメータを最適化
前回と同じ日本語論文抜粋データ、9,406字(5,337 prompt tokens)を使って、spec-draft-n-max と spec-draft-p-min を変えつつ、出力の日本語が崩れないことも確認した。
共通条件は、
context : 8192
ncmoe : 0
threads : 4 / batch threads 4
batch : 2048
ubatch : 1024
Flash Attn : enabled
temperature : 0.2
top-k : 20
top-p : 0.8
min-p : 0.05
reasoning : off
MTP draft : mtp-Qwen3.8-Flash-Next-Q8_0.gguf
MTPありの実行例。
.\llama-cli.exe `
-m "(モデルのパス)\Qwen3.8-Flash-Next-UD-IQ3_XXS-00001-of-00003.gguf" `
-md "(モデルのパス)\mtp-Qwen3.8-Flash-Next-Q8_0.gguf" `
--spec-type draft-mtp `
-c 8192 `
-ngl 999 `
-ncmoe 0 `
-t 4 `
-tb 4 `
-b 2048 `
-ub 1024 `
-fa 1 `
--spec-draft-n-max 2 `
--spec-draft-p-min 0 `
--temp 0.2 `
--top-k 20 `
--top-p 0.8 `
--min-p 0.05 `
--jinja `
--single-turn `
--reasoning off `
-f (入力文書のパス) `
-n 1024 `
-lv 4
測定結果はこうなった。
| MTP | n-max | p-min | PP [tok/s] | TG [tok/s] | draft acceptance | mean len |
|---|---|---|---|---|---|---|
| なし | - | - | 283.75 | 21.43 | - | - |
| あり | 1 | 0.00 | 287.26 | 29.28 | 83.9% | 1.84 |
| あり | 1 | 0.75 | 273.94 | 26.93 | 92.0% | 1.92 |
| あり | 2 | 0.00 | 292.36 | 31.28 | 69.2% | 2.38 |
| あり | 2 | 0.50 | 287.88 | 29.67 | 72.8% | 2.39 |
| あり | 2 | 0.75 | 288.69 | 29.34 | 84.0% | 2.52 |
| あり | 2 | 0.90 | 273.29 | 27.54 | 91.0% | 2.53 |
| あり | 3 | 0.75 | 286.27 | 28.94 | 76.7% | 2.75 |
このテストでは n-max=2 / p-min=0 が最速で、MTPなしの21.43 tok/sに対して31.28 tok/s、約1.46倍になった。
面白かったのは、draft acceptanceが一番高い設定が一番速いわけではなかったこと。
たとえば n-max=2 / p-min=0.9 はacceptanceが91.0%あるが、TGは27.54 tok/s。一方、p-min=0 はacceptanceが69.2%まで下がるのに、TGは31.28 tok/sまで伸びた。
そこで、この後の長文試験は
n-max=2
p-min=0
で固定した。
参考までに、前回の b10679 で同じ5,337-token文書をMTP処理したなしで処理したときは、PP 304.60 tok/s / TG 21.14 tok/sだった。
llama.cppのbuildが違い、実行パラメータが厳密に同じではないが、TGは今回測定したMTPなしの値と近い。
PPが前回の方が速いのはbuildの差か他のパラメータの差かは今回は検証していない。
長文要約テスト
前回使った長さ調整済みの日本語論文データを使って、先頭に
以下は日本語の技術文書の連続入力です。
本文を最後まで読み込んでください。
末尾に
以上が入力文書です。
複数回繰り返されている部分は無視して、入力文書のユニークな部分について要約してください。
次の項目を含め、800字程度の日本語でまとめてください。
1. 文書が扱う問題
2. 主な手法の分類
3. 評価表現辞書の構築方法
4. 共起情報・PMI・文脈情報の役割
5. 文書分類との関係
6. 注意点または限界
文書に書かれていない内容は推測しないでください。
数式・専門用語は、意味を変えずに必要に応じて残してください。
を追加したファイルを入力ファイルとした。
TGをある程度安定して測るため、前回より長めの出力を要求するプロンプトに変更している。
MTP側のパラメータは先ほど決めた n-max=2 / p-min=0。それ以外はMTPあり / なしでそろえた。
ncmoe : 0
threads : 4 / batch threads 4
batch : 2048
ubatch : 1024
Flash Attn : enabled
KV cache : F16
temperature : 0.2
top-k : 20
top-p : 0.8
min-p : 0.05
reasoning : off
32Kを例にすると、MTPありは前節のコマンドの -c を32768にし、長文ファイルを -f で渡す形。
.\llama-cli.exe `
-m "(モデルのパス)\Qwen3.8-Flash-Next-UD-IQ3_XXS-00001-of-00003.gguf" `
-md "(モデルのパス)\mtp-Qwen3.8-Flash-Next-Q8_0.gguf" `
--spec-type draft-mtp `
-c 32768 `
-ngl 999 `
-ncmoe 0 `
-t 4 `
-tb 4 `
-b 2048 `
-ub 1024 `
-fa 1 `
-ctk f16 `
-ctv f16 `
--spec-draft-n-max 2 `
--spec-draft-p-min 0 `
--temp 0.2 `
--top-k 20 `
--top-p 0.8 `
--min-p 0.05 `
--jinja `
--single-turn `
--reasoning off `
-f 入力ファイルのパス) `
-n 1024 `
-lv 4
結果はこちら。
| Context | MTP | Prompt tokens | PP | TG | TG倍率 | Completion tokens | draft acceptance | 出力結果 |
|---|---|---|---|---|---|---|---|---|
| 32K | なし | 29,557 | 224.11 | 17.34 | 1.00x | 578 | - | 正常 |
| 32K | Q8_0 | 29,557 | 214.15 | 26.87 | 1.55x | 677 | 74.3% | 正常 |
| 64K | なし | 61,789 | 170.98 | 12.25 | 1.00x | 638 | - | 正常 |
| 64K | Q8_0 | 61,789 | 164.20 | 19.15 | 1.56x | 590 | 64.8% | 正常 |
| 128K | なし | 126,253 | 118.12 | 8.22 | 1.00x | 532 | - | 正常 |
| 128K | Q8_0 | 126,253 | 112.65 | 13.77 | 1.68x | 546 | 66.5% | 正常 |
MTPを有効にするとPPは少し遅くなり、TGは1.55~1.68倍速くなった。
128Kでは8.22 → 13.77 tok/sで、同じb10715上のMTPあり / なし比較では 1.68倍 になったが、「TGが1.68倍 = 1回のリクエスト全体が1.68倍速い」ということではない。
今回の128Kは126,253 prompt tokensに対して生成が500 tokens台なので、時間の大半はPPが占める。実測のtotal timeも、出力token数が完全には一致しないので参考値ではあるが、
128K MTPなし : 約18分53秒
128K MTPあり : 約19分20秒
だった。
128Kのような「超長文を読ませて比較的短い回答を出す」用途では、MTPによるTG高速化より約4%のPP差の方が全体時間に効く場合がある。一方、会話を続けてprompt cacheが効いている状態や、もっと長い回答を生成する用途ではTGの差が体感に直結しやすいはずなので、ここは用途次第だと思う。
出力については、32K / 64K / 128KのMTPあり・なしのすべてで正常な日本語の要約文章が出力された。前回の ncmoe=8 のような / 反復は再現しなかった。今回は品質評価を目的にしていないので、要約内容の正確性を細かく採点まではしていない。
前回のb10679との参考比較
前回測定した、 llama.cpp b10679 / c=131072 / ncmoe=0 / t4 / tb4 / b2048 / ub1024 / fa1 では、126,149 tokens入力でPP 117.72 tok/s / TG 6.41 tok/sだった。
この時は元の文書は同じだが、末尾の確認番号だけを出力していて、今回の要約出力とはプロンプトと生成長が違う。
そのため、厳密な同条件での比較ではないが、今回の最初に測った -d 126000のllama-bench結果の、
b10679で6.41 tok/s → b10715-mix-86bd2d3で8.12 tok/s
と、128K近い長文実データ入力の
b10679(前回測定)でTG 6.41 tok/s → b10715-mix(MTPなし)(今回測定) TG 8.22 tok/s
の傾向は一致する。
条件が違うので参考値にはなるが、b10715-mix(MTP Q8) TG 13.77 tok/s はTG 6.41 tok/sから比べると約2.15倍になっている。
128K時のリソース比較
128KのMTPあり / なしでは、別途PowerShellでWindowsのリソースカウンタも約2秒間隔で記録した。
処理中に値がほぼ横ばいになっていた区間の代表値を比較すると、以下のようになった。
| 指標 | MTPなし(代表値・約) | MTPあり Q8_0(代表値・約) | 差(約) |
|---|---|---|---|
| Used RAM | 10.01 GiB | 11.33 GiB | +1.32 GiB |
| Free RAM | 53.64 GiB | 52.32 GiB | -1.32 GiB |
| Commit | 63.9% | 69.8% | +5.9pt |
| llama Private | 51.91 GiB | 57.28 GiB | +5.37 GiB |
| llama GPU Total Committed | 57.37 GiB | 62.63 GiB | +5.26 GiB |
| Adapter Dedicated | 56.26 GiB | 60.51 GiB | +4.25 GiB |
| Adapter Shared | 1.66 GiB | 2.67 GiB | +1.01 GiB |
| Adapter Total Committed | 58.09 GiB | 63.35 GiB | +5.26 GiB |
※ 安定区間の代表値を小数第2位まで表示している。瞬間値や厳密な平均値ではないため、リソース表全体を概数として扱う。
ここまで使っている通常の mtp-Qwen3.8-Flash-Next-Q8_0.gguf を有効にすると、128K実長文処理中のGPU committed系はおよそ5.3 GiB増えた。
EVO-X2はUMAなので、Windowsが表示する Dedicated / Shared は物理的に完全に別のVRAMとRAMが載っている、という意味ではない。ここではWindowsのメモリ会計上の値として比較している。
別のMTPモデルと比較
ここまで検証してきたのは、Unslothの
mtp-Qwen3.8-Flash-Next-Q8_0.gguf
だが、同じリポジトリで公開されている
mtp-Qwen3.8-Flash-Next-shared-Q8_0.gguf
も使ってみた。
ログを見るとshared版には
qwen4exp.nextn_shared_target_tensors = true
が設定されており、ロード時には
tensor token_embd.weight taken from the target model
tensor output.weight taken from the target model
と出ていた。
つまりshared版は、draft model側に同じtensorを全部持つのではなく、一部をtarget modelから借りて使う形式になっている。
実際、draft modelロード時のbufferを見ると、
通常Q8_0:
ROCm0 model buffer 3291.18 MiB
ROCm_Host model buffer 644.14 MiB
shared-Q8_0:
ROCm0 model buffer 2647.04 MiB
となっており、ログ上のdraft model buffer合計では約1.26 GiB小さい。
測定結果はこうなった。
| 順番 | MTP | PP | TG | MTPなし比 | draft acceptance |
|---|---|---|---|---|---|
| 1 | Q8_0 | 214.15 | 26.87 | 1.55x | 74.3% |
| 2 | なし | 224.11 | 17.34 | 1.00x | - |
| 3 | shared-Q8_0 | 215.69 | 26.12 | 1.51x | 69.5% |
| 4 | Q8_0 再測定 | 214.90 | 25.67 | 1.48x | 68.5% |
熱の影響が気になったので、Q8_0を初回と最後に2回測ったが、TGが26.87 → 25.67 tok/sと約4.5%変動した。
shared-Q8_0の26.12 tok/sはその2回の間に入っているので、今回1回ずつの測定から「shared版の方が速い / 遅い」と判断するほどの差はなさそう。
少なくとも今回の32K試験では、self-contained Q8_0とshared-Q8_0はほぼ同じ速度帯で、shared版はdraft model bufferを小さくできたという結果になった。
まとめ
今回の測定で一番大きかったのは、前回は起動すらできなかったQwen3.8-Flash-NextのMTPが、Unslothの b10715-mix-86bd2d3 とMTP GGUFを使うことで、EVO-X2のROCm環境でもllama.cppの自前ビルドなしで普通に動いたこと。
そしてllama.cppのbuild変更とMTPの相乗効果でTGは2倍以上速くなったが、PPは約4%遅くなり、128K処理時のGPU committed系も約5.3 GiB増えた。今回の環境では、追加メモリと少しのPP低下との引き換えにdecodeを速くするトレードオフになった。
さらに shared-Q8_0 も32Kで試したところ、通常Q8_0とほぼ同じ速度帯で、llama.cppログ上のdraft model bufferは小さかった。メモリ使用量を抑えたい場合の候補になりそう。
そして今回あらためて感じたのは、ローカルLLMの「速さ」をTGだけで見るのは危ない、ということ。
128Kで13.77 tok/sまで生成が速くなっても、126K tokensを最初に読む時間の方が圧倒的に長い。実際のチャット体験では、PP、TTFT、prompt cacheがどの程度効くか、そして1回に何tokens生成するかの方が重要になる場面も多そう。
次回の予定
128KでTGが約13~14 tok/sというのは、コーディングやエージェント用途だと遅く感じる場面もあると思う。
ただ、チャットで会話したり長文要約を読んだりする用途なら、私が文字を読んで理解する速度と大差ないので、それほど遅くは感じない。
むしろチャットでは、PP(入力読み込み速度)、TTFT(最初の1tokenが出るまでの時間)、prompt cacheのヒット率の方が体感に影響する気がする。
次回はOpen WebUIにQwen3.8-Flash-Nextを登録して、チャットでの会話や長文要約の使い勝手を他のモデルと比較してみたい。
検証環境
Hardware
- Device: NucBox_EVO-X2
- CPU / APU: AMD Ryzen AI MAX+ 395 with Radeon 8060S
- CPU clock displayed by Windows: 3.00 GHz
- Installed memory: 128 GB
- Windows usable memory: 63.6 GB
- UMA Frame Buffer: 64 GB
- GPU: AMD Radeon 8060S Graphics
OS
- OS: Windows 11 Pro
- Version: 25H2
- OS Build: 26200.9168
- Installed: 2025-10-24
- Windows Feature Experience Pack: 1000.26100.344.0
llama.cpp
b10715-mix-86bd2d3- build: 10715
- commit:
92cedc867 - Windows x64 ROCm gfx1151
- Unsloth team build
- build log上のcompiler: Clang 23.0.0
EVO-X2にインストール済みのHIP SDK
第1回・第2回から同じローカル環境。上の Clang 23.0.0 は今回使ったUnslothプレビルド版のbuild logに出るコンパイラで、以下はEVO-X2側にインストールしてあるHIP SDKの情報。
- HIP SDK: 7.2.60201-38d754472
- HIP compiler: clang 21.0.0git
- HIP target: gfx1151
使用したモデル
Target model
- Repository:
unsloth/Qwen3.8-Flash-Next-GGUF - URL: https://huggingface.co/unsloth/Qwen3.8-Flash-Next-GGUF
- Quantization: UD-IQ3_XXS
- Logger metadata:
IQ3_XXS - 3.0625 bpw - Model file size reported by llama.cpp: 76.32 GiB
- Model params: 176.94B
MTP draft model
mtp-Qwen3.8-Flash-Next-Q8_0.ggufmtp-Qwen3.8-Flash-Next-shared-Q8_0.gguf- URL: https://huggingface.co/unsloth/Qwen3.8-Flash-Next-GGUF/tree/main/MTP