Qwen3.8 の MTP で遅くなる原因と正しい付け方 — llama.cpp・Ollama・16GB(RTX 5060 Ti)で実測
CONTENTS目次(9)
この記事の結論
- Qwen3.8-27B に MTP を付けたら、生成が 3〜5 倍遅くなった。原因は MTP ではなく付け方で、MTP の層が最初から入っている GGUF(モデルのファイル)に、別ファイルの MTP を重ねていた。
- 別ファイルの MTP は、MTP を外した小さい版のためのもの。重ねると VRAM(GPU のメモリ)が約 1.3GB 多く要り、16GB からあふれて本体の一部が CPU に回る。
- 本体の MTP だけを使い、全部を GPU に固定すると、日本語の文章で 1.36 倍(1 秒あたりのトークン数 tok/s が 27.3 → 37.2)、コードで 1.96 倍(27.3 → 53.4 tok/s)になった。Ollama は置き場所を自動で決めるので、文脈 32K では本体を押し出して逆に遅くなった(
num_gpu 99で固定すれば 38.4 tok/s)。
MTP(Multi-Token Prediction)は、モデルに付いた小さな「先読みの頭」が次の数トークンを下書きし、本体がそれをまとめて確かめる仕組みです。下書きが当たった分だけ、1 回の計算で進むトークンが増えるので速くなります。確かめる工程があるので、出てくる文章の傾向は MTP を使わないときと変わりません。
Qwen3.8-27B は MTP に対応していて、同じ RTX 5060 Ti 16GB で「26 → 54 tok/s と約 2 倍になった」という報告も出ています。ところが手元で試すと、逆に 3〜5 倍遅くなりました。原因を突き止めて付け方を直すまでの記録です。数字は 2026年9月29日時点のものです。
測った環境
| 項目 | 内容 |
|---|---|
| GPU | GeForce RTX 5060 Ti 16GB(電力の上限 180W) |
| CPU・メモリ | Core i5-12400F・DDR4-3200 32GB |
| OS・ドライバ | Windows 11・NVIDIA ドライバ 610.47 |
| モデル | unsloth/Qwen3.8-27B-GGUF の UD-Q3_K_XL(13.15GB・3bit の量子化) |
| 実行環境 | llama.cpp b11193(公式の Windows 向け CUDA 13.4 版)・Ollama 0.34.3 と 0.34.4 |
| 共通の設定 | flash attention あり・KV キャッシュ(読んだ文脈を覚えておくメモリ)は q8_0・-b 512 -ub 512・同時処理 1。思考は切る。サンプリングは Qwen の推奨値(温度 0.7・top_p 0.8・top_k 20・presence_penalty 1.5) |
| 問い | 日本語の文章の続きを書かせる問い(入力の長さは 3 通り。表では目安の 2,000・8,000・16,000 トークンと書くが、実際は 1,540〜1,763・6,949〜7,256・14,539〜14,741)と、日本語の参考資料のあとに仕様を書いて Python のモジュールを書かせる問い(入力 1,896〜2,159 トークン)。どれも 512 トークンを出力させ、各 2 回 |
つまずき: MTP を付けたら 3〜5 倍遅くなった
最初は、unsloth の同じリポジトリにある別ファイルの MTP(MTP/mtp-Qwen3.8-27B-Q4_0.gguf・1.37GB)を、本体とは別に渡しました。Ollama では /api/create の draft_files で、llama.cpp では --spec-draft-model(下書きのモデル)で渡す形です。llama.cpp のほうは、頭を GPU に載せる --spec-draft-ngl 99 も付けました。1 回に下書きさせる数(手数)は、Ollama の既定と同じ 4 です。
| 生成 tok/s | MTP なし | Ollama+別ファイル | llama.cpp+別ファイル |
|---|---|---|---|
| 文脈 8K・入力 2,000 | 27.6 | 9.4〜9.8 | 10.4〜10.8 |
| 文脈 32K・入力 2,000 | 27.6 | 5.2〜5.5 | 5.3〜6.6 |
| 文脈 32K・入力 16,000 | 25.7 | 4.5〜5.3 | 4.5〜4.8 |
| 文脈 32K・コード | 27.6 | 8.8〜9.1 | 8.5〜9.9 |
MTP なしは Ollama 0.34.3 の値(llama.cpp でもほぼ同じ 26.1〜28.1)。2026年9月29日に測定。
MTP なしと比べて、文脈 8K とコードでは約 3 分の 1、文脈 32K の文章では約 5 分の 1 の速さです。生成している間の GPU の消費電力は、測った 5 回とも 60W 未満で、上限の 180W に遠く届きません。代わりに、推論を受け持つ llama-server(Ollama の中で動くものも同じ)が、CPU を 5.3〜6.2 コア分使っていました。GPU が待たされ、CPU で何かを計算している状態です。
先読みの当たりが悪いせいかとも考えましたが、下書きが 421 個中 405 個(96%)当たった回でも 11.1 tok/s でした。当たりの問題ではありません。
原因: 本体の GGUF に MTP の層が最初から入っていた
GGUF の設定の部分を読むと、原因が分かりました。使っていた UD-Q3_K_XL には、MTP の層がすでに入っていたのです。
qwen35.nextn_predict_layers = 1 ← MTP の層が 1 つある
blk.64.* ← MTP の層の重み(15 本)
設定と重みの一覧から抜き出して整形。
unsloth の説明にも「UD-Q2_K_XL より小さい版(8.37GB 以下)からは MTP を外した。必要なら別ファイルの Q4_0 の MTP を使える」とあります。別ファイルの MTP は、MTP を外した 1〜2bit の小さい版(UD-IQ2_S 以下)のためのもので、UD-Q2_K_XL 以上には要りません。先に挙げた報告の議論でも、別の人が「GGUF に MTP の層(blk.64.nextn.*)が入っているので、別の下書きモデルは要らない」と書いています。
それを重ねたことで、何が起きたか。別ファイルの MTP は、自前の出力層などを含めて、読み込むと 1,306MiB あります。置き場所を自動で決める llama.cpp の仕組み(--fit。VRAM に 1GiB の余白を残す)は、全部が入りきらないと、本体の層の一部を CPU に回します。起動の記録で層の数までは確かめていませんが、次の VRAM の増え方と、上の電力・CPU の様子から、本体の一部が CPU に回されていたとみられます。
| VRAM の使用量(起動直後) | MTP なし | 別ファイルの MTP あり | 増えた分 |
|---|---|---|---|
| 文脈 8K | 12,952 MiB | 13,956 MiB | +1,004 MiB |
| 文脈 32K | 13,878 MiB | 14,046 MiB | +168 MiB |
llama.cpp b11193 で測定。Windows の画面表示などが使う分を含む。
別ファイルの MTP(1,306MiB)と、その作業領域を足したのに、文脈 32K では VRAM が 168MiB しか増えていません。足した分を空けるために、本体の層が GPU から追い出された形です。本体が一部でも CPU にあると、下書きを確かめるたびに CPU の計算を待つことになり、当たりが良くても速くなりません。
自分の GGUF に MTP の層があるかを確かめる
llama.cpp の開発元が出している Python の道具(gguf)で、設定の部分だけを表示できます。
pip install gguf
gguf-dump --no-tensors Qwen3.8-27B-UD-Q3_K_XL.gguf
表示の中に nextn_predict_layers があり、値が 1 以上なら、本体に MTP の層があります。そのときは別ファイルの MTP を渡しません。
正しい付け方: 本体の MTP だけを使い、全部を GPU に固定する
llama.cpp では、本体の MTP を使うのに別ファイルの指定は要りません。--spec-type draft-mtp を付けるだけです。あわせて、置き場所の自動決定を切って、全部を GPU に載せるように固定します。こうすると、入りきらないときに本体が黙って CPU に回されることはなくなります。ただし Windows では、ドライバの設定によって、VRAM からあふれた分が共有メモリ(メインメモリ)に置かれることがあり、そのときもやはり遅くなります。起動したら nvidia-smi で、VRAM の使用量が上限の手前に収まっているかを確かめます。
llama-server -m Qwen3.8-27B-UD-Q3_K_XL.gguf -c 32768 -np 1 \
-ngl 99 --fit off -fa on -ctk q8_0 -ctv q8_0 \
--spec-type draft-mtp --spec-draft-n-max 2
--spec-draft-n-max は、1 回に下書きさせるトークンの数(手数)です。2 と 3 を測りました。
| 生成 tok/s | MTP なし | 手数 2 | 手数 3 |
|---|---|---|---|
| 文脈 8K・入力 2,000 | 27.3 | 37.7(×1.38) | 34.3 |
| 文脈 32K・入力 2,000 | 27.3 | 37.2(×1.36) | 35.2 |
| 文脈 32K・入力 8,000 | 26.6 | 36.4(×1.37) | 38.1 |
| 文脈 32K・入力 16,000 | 25.6 | 35.2(×1.37) | 33.6 |
| 文脈 32K・コード | 27.3 | 46.4(×1.70) | 53.4(×1.96) |
各 2 回の中央値。llama.cpp b11193。VRAM は手数 2 で 14,771MiB、手数 3 で 14,919MiB(文脈 32K、全部 GPU)。2026年9月29日に測定。
- 日本語の文章は 1.36〜1.38 倍でした。下書きの当たりは、手数 2 で 45〜53% です。手数を 3 にすると当たりは 33〜49% に下がり、速さは入力によって 33.6〜38.1 tok/s と上下しました(手数 2 は 35.2〜37.7 tok/s)
- コードは手数 3 で 1.96 倍でした。当たりは 72〜79% と高く、手数を 2 から 3 に増やすと 46.4 → 53.4 tok/s に伸びました
- VRAM は MTP なしより 890〜1,038MiB 増えました(unsloth の案内は「約 2GB 多く見込む」)。全体 16,311MiB のうち空きは 1,400〜1,500MiB ほどしかないので、ほかのアプリが GPU を使っていると入りきらないことがあります
報告の約 2 倍は、どれもコードを書かせる使い方での数字でした。最初の投稿は、ゲームを 1 つの HTML ファイルで書かせる問いで 35 → 50〜55 tok/s。26 → 54 tok/s の人は、コーディングのエージェントで使う長さの文脈で測っています。手元でもコードは 1.96 倍と、ほぼ同じでした。日本語の文章では 1.3〜1.4 倍が目安です。
Ollama で使う場合の落とし穴
Ollama 0.34 系では、本体に MTP の層がある GGUF を読み込み、モデルの設定で draft_num_predict(手数)を指定すると、MTP が有効になります。Modelfile なら次の 1 行です。
PARAMETER draft_num_predict 3
ただし Ollama は、中で動かしている llama.cpp に -ngl を渡さず、置き場所を自動の決定(--fit)に任せています。MTP の分だけ VRAM が増えると、その自動の決定が本体の一部を CPU に回します。
| Ollama 0.34.4・手数 3 | 生成 tok/s | GPU に載った割合 |
|---|---|---|
| 文脈 8K・入力 2,000 | 25.3・37.2 | 100% |
| 文脈 32K・入力 2,000 | 12.9〜14.0 | 90% |
| 文脈 32K・コード | 20.9〜21.3 | 90% |
2 回の値。文脈 8K は 1 回目と 2 回目の差が大きく、理由は確かめていない。2026年9月29日に測定。
文脈 8K なら全部が GPU に収まり、2 回目は 37.2 tok/s 出ました。文脈 32K では 1 割が CPU に回り、文章では MTP なし(Ollama 0.34.3 で 27.6 tok/s)の半分に落ちています。Ollama で MTP を使うなら、文脈を小さくするか、モデルの設定で置き場所を固定します。num_gpu 99(全部の層を GPU に置く)を足すと、文脈 32K でも全部が GPU に載り、38.4 tok/s 出ました(入力 約 1,500 トークン・1 回だけの測定)。
PARAMETER draft_num_predict 3
PARAMETER num_gpu 99
ただし num_gpu で固定すると、VRAM に入りきらないときに自動で逃がしてくれなくなります。文脈を長くしたり、ほかのアプリが GPU を使っていたりすると、読み込みに失敗したり、遅くなったりすることがあります。
参考: Gemma 4 31B は別ファイルの MTP で速くなった
同じ日に Gemma 4 31B(unsloth の UD-IQ3_XXS・11.84GB)でも試しました。Gemma 4 の MTP は、本体とは別の小さな下書き用のモデルとして配られていて(本体と KV キャッシュを共有して動く)、別ファイル(Q8_0・0.51GB)を渡すのが正しい付け方です。頭が小さいので 16GB に収まり(文脈 32K で 15,218MiB)、Ollama でも llama.cpp でも速くなりました。
| 生成 tok/s(文脈 32K) | MTP なし(Ollama/llama.cpp) | Ollama+MTP | llama.cpp+MTP |
|---|---|---|---|
| 入力 2,000 | 26.4/26.5 | 36.5(×1.38) | 35.0(×1.32) |
| 入力 16,000 | 22.4/22.4 | 31.0(×1.38) | 30.4(×1.35) |
| コード | 26.3/26.3 | 57.9(×2.20) | 55.2(×2.10) |
各 2 回の中央値。手数 4(Gemma の MTP の案内と同じ)。Ollama 0.34.3・llama.cpp b11193。倍率はそれぞれの MTP なしとの比。2026年9月29日に測定。
Gemma でも、日本語の文章は 1.3〜1.4 倍、コードは 2 倍強でした。別ファイルの MTP が要るかどうかはモデルごとに違うので、先に本体の GGUF に MTP の層があるかを見る、というのがこの日の教訓です。
測っていないこと
- ほかの量子化(UD-IQ4_XS など)や、ほかの GPU では測っていません。VRAM の余白が変わると、同じ設定でも入りきらないことがあります
- Ollama で
num_gpuを固定したときの速さは、文脈 32K・入力 約 1,500 トークンの 1 回だけ - 長い出力(数千トークン)や、思考ありの設定での速さ
- MTP は出力の傾向を変えない仕組みなので、文章の質は測り直していません
まとめ
- Qwen3.8-27B の unsloth の GGUF(UD-Q3_K_XL など)には MTP の層が入っている。別ファイルの MTP は、MTP を外した小さい版のためのもの
- 別ファイルを重ねると 16GB からあふれ、本体の一部が CPU に回って 3〜5 倍遅くなる。VRAM が増えるべき分だけ増えていなければ、押し出しを疑う
- 正しくは
--spec-type draft-mtpだけを付け、-ngl 99 --fit offで全部を GPU に固定する。RTX 5060 Ti で日本語の文章 1.36 倍・コード 1.96 倍(2026年9月29日時点) - Ollama は置き場所が自動なので、文脈 32K では本体を押し出して遅くなる。文脈を小さくするか、
num_gpu 99で置き場所を固定する(固定すると 38.4 tok/s)
出典
- unsloth/Qwen3.8-27B-GGUF(Hugging Face): https://huggingface.co/unsloth/Qwen3.8-27B-GGUF
- Unsloth Dynamic 3.0 GGUFs(小さい版から MTP を外した旨): https://unsloth.ai/docs/basics/dynamic-3.0-ggufs
- Unsloth「Run MTP Models」(MTP は約 2GB 多くメモリを使う・手数は 2 から試す): https://unsloth.ai/docs/models/mtp
- RTX 5060 Ti 16GB で MTP を使った報告(unsloth/Qwen3.8-27B-GGUF の議論 #26・2026年8月): https://huggingface.co/unsloth/Qwen3.8-27B-GGUF/discussions/26
- llama.cpp の投機的デコードの説明: https://github.com/ggml-org/llama.cpp/blob/master/docs/speculative.md
- Ollama の Modelfile(draft_num_predict): https://github.com/ollama/ollama/blob/main/docs/modelfile.mdx
- gguf(Python の道具・gguf-dump): https://pypi.org/project/gguf/
- unsloth/gemma-4-31B-it-GGUF(Hugging Face): https://huggingface.co/unsloth/gemma-4-31B-it-GGUF
- Gemma 4 31B の MTP の説明(本体と KV キャッシュを共有する下書き用のモデル): https://huggingface.co/unsloth/gemma-4-31B-it-GGUF/blob/main/MTP/README.md
この記事は、手元の機材で行った測定をもとにした一般的な技術情報の提供を目的としており、特定の製品・ソフトウェアの購入や利用を推奨・勧誘するものではありません。数値は 2026年9月29日時点の測定で、モデルの版・量子化・ソフトの版・機材によって変わることがあります。