西川和久の不定期コラム
まだ一般向けではありません。でも未来感が凄い2026年春のローカルLLM事情
2026年5月14日 06:12
今年(2026年)に入ってもオープンソース(ウェイト)なLLMは毎月いろいろなものが発表されている。加えて、LLMを高速化する技術も登場し、毎週毎週AI界隈は大騒ぎだ。そこで今回はGemma 4 + MTPで高速化する話と、DeepSeek V4 FlashをM4 Max 128GBで動かす話、この2つをご紹介したい。
Gemma 4がMTP使って高速化!?
この春、LLM界隈では、いろいろな手法を使い、LLMの高速化や低容量化の開発/実験が進んでいる。その中で目を引いたのがこの記事だ。
記事のタイトルには入ってないが、これはMTP(Multi-Token Prediction: マルチトークン予測)を使って推論速度を高速化する技術だ。この技術についてザックリ説明すると、小さなドラフトモデル(ドラフター)が次のトークンを先読みし、大きなメインモデル(ターゲットモデル)が一括検証することで推論の高速化を実現するものである。
実はこのMTP、既に筆者は1カ月以上前から使っており、DGX Spark互換機でvLLM + Qwen 3.6 27B + MTPを起動、OpenCodeなどで実用的に処理ができている。
というのも、それ以前はMTPなしで試したものの、tok/s(トークン出力速度)が遅く、これでバイブコーディングは厳しく、性能が良いだけに残念と思っていた。しかしMTPを導入すると本当に2〜3倍、加えて並列処理にも強く、ピッタリの環境に早変わり。以降ずっと使っている経緯がある。
このような体験もあり、Gemma 4もMTP使えば3倍高速化も嘘じゃないよね……と記事を読んで思った次第だ。
なお、ターゲットとドラフターのペアはどのターゲットモデルとでも組み合わせられるわけではなく、専用の組み合わせがある。たとえばGemma 4の場合、Googleが各モデルサイズに対応するドラフターを用意している。さらに重要な点として、ターゲットモデルは必ずinstruction-tuned版(モデル名に-itがつくもの)を使う必要がある。base版(-itなし)とペアにするとドラフターの予測分布がずれてしまい、逆に遅くなるのだ。
さて、記事を書くにあたって実際に試さないと気が済まないので(笑)、いろいろ調べたのだが、意外とハードルは高い。
| ツール | 状況 |
|---|---|
| vLLM | PR #41745がマージ待ち。プレビューDockerで動作確認済み |
| llama.cpp | Qwen3系MTPはベータ対応済み。Gemma 4 assistantのGGUF変換が未対応で止まっている |
| LM Studio | llama.cppベースのため同様に止まっている |
| Ollama | Gemma 4 MTPは一応対応しているが動作検証中のコメント多数 |
| MLX(mlx-vlm) | 実装はあるがシングルリクエストでは効果なし〜逆効果 |
このように、記事執筆時点でGemma 4 MTPがまともに動くのは、vLLMのプレビューとDockerを使えるLinux環境だけという状況だ。
よって、一般のWindowsユーザーがサクッと試せる手段はどこにもなく、実績のあるDGX Spark互換機で検証することにした。そういえばこの件が影響しているのか?llama.cppやLM Studioも結構長い間更新がない。
DGX Spark互換機での設定は以下のような感じとなる。
- ターゲット: RedHatAI/gemma-4-26B-A4B-it-FP8-Dynamic (FP8、-it版)
- ドラフター: google/gemma-4-26B-A4B-it-assistant (約870MB、BF16)
% hf download RedHatAI/gemma-4-26B-A4B-it-FP8-Dynamic \
--local-dir ~/models/gemma4-26b-a4b-it-fp8
% hf download google/gemma-4-26B-A4B-it-assistant \
--local-dir ~/models/gemma4-26b-a4b-it-assistant
% wget https://raw.githubusercontent.com/vllm-project/vllm/d8b3826648da6b407f8c55457a2103be9aeb5d83/vllm/model_executor/models/gemma4_mtp.py -O /tmp/gemma4_mtp.py
% docker run -d --name gemma4-baseline \
--gpus all --ipc host --shm-size 64gb \
-p 8000:8000 \
-v ~/models:/models \
vllm/vllm-openai:gemma4-0505-arm64-cu130 \
--model /models/gemma4-26b-a4b-it-fp8 \
--kv-cache-dtype fp8 \
--gpu-memory-utilization 0.85 \
--max-model-len 4096 \
--limit-mm-per-prompt '{"image":0,"audio":0,"video":0}'
% docker run -d --name gemma4-mtp \
--gpus all --ipc host --shm-size 64gb \
-p 8000:8000 \
-v ~/models:/models \
-v /tmp/gemma4_mtp.py:/usr/local/lib/python3.12/dist-packages/vllm/model_executor/models/gemma4_mtp.py:ro \
vllm/vllm-openai:gemma4-0505-arm64-cu130 \
--model /models/gemma4-26b-a4b-it-fp8 \
--speculative-config '{"method":"mtp","model":"/models/gemma4-26b-a4b-it-assistant","num_speculative_tokens":4}' \
--kv-cache-dtype fp8 \
--gpu-memory-utilization 0.85 \
--max-model-len 4096 \
--limit-mm-per-prompt '{"image":0,"audio":0,"video":0}'
ベンチマークテスト結果
% time curl http://localhost:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "/models/gemma4-26b-a4b-it-fp8",
"messages": [{"role": "user", "content": "日本の歴史について200文字程度で説明してください。"}],
"max_tokens": 200,
"temperature": 0
}'
※ completion_tokens ÷ real秒数でtok/sを計算
| MTPなし | MTPあり | |
|---|---|---|
| 生成速度 | 42.48 tok/s | 52.7〜73.8 tok/s |
約1.24〜1.74倍だが、シングルリクエストの計測はプロンプト内容やモデルの状態によってブレが出やすく、条件次第といったところか。続いては並列ベンチマークをしてみた。
| 並列数 | MTPなし | MTPあり | 倍率 | ||
|---|---|---|---|---|---|
| 1 | 42.48 | tok/s | 73.83 | tok/s | 1.74× |
| 2 | 73.17 | tok/s | 80.87 | tok/s | 1.11× |
| 3 | 78.13 | tok/s | 141.68 | tok/s | 1.81× |
| 4 | 105.77 | tok/s | 215.37 | tok/s | 2.04× |
並列数が増えるほど効果が大きくなる結果となり、MTP理論通りの挙動を確認。4並列で2倍超えを達成した。
以上のように確かに高速化を確認できた。ただDGX Spark互換機専用ではさすがに……なので、もう少しご家庭用GPUで何とかならないのか……と調べたところ、手元環境では未確認だが、GeForce RTX 5090であれば行けるかも?となった。
DGX SparkではFP8版を使用したが、モデルウェイト単体で約26GBあり、ドラフターと組み合わせるとGeForce RTX 5090(32GB)には乗らない。しかしINT4量子化版(AWQ等)ならモデルウェイトは約15GBに収まる。これならドラフター(BF16、約870MB)を加えても16GB程度だ。
GeForce RTX 5090 (32GB)でINT4 + --max-model-len 4096の場合の推定消費量は、
| 用途 | 推定 |
|---|---|
| モデルウェイト(INT4) | 約15GB |
| ドラフター(BF16) | 約0.9GB |
| KVキャッシュ(fp8、4096トークン) | 約10〜11GB |
| オーバーヘッド | 約2〜3GB |
| 合計 | 約28〜30GB |
というようになり、32GBにはギリギリ乗る計算。ただし--max-model-len 4096という制約付きなので、実用的なコンテキスト長(32K以上)には対応できない。あくまでもお試しという形。いずれにしてもこの状況だとGeForce RTX 4090(24GB)では無理な話となる。
もう1つはBlackwell世代ならNVFP4が使え、モデルサイズは約16.5GBで32GBに余裕で乗り、INT4より精度が高く速い可能性がある、というもの。
とはいえ、仮に動いたとしてもINT4と同じくコンテキスト長が短く、速くても実用レベルにはならない……が、実際のところではないだろうか。
それ以前にやはりllama.cpp、およびそれを使うLM StudioのMTP対応が待ち遠しいところ。これが出れば普通にサクッと使えるようになるだろう。
ds4.c改めDwarfStar 4の仕組み
次は「DeepSeek V4」の話だ。4月24日にV4 ProとV4 Flashが同時リリースされた。特徴は、
- DeepSeek V4 Pro: 1.6T総パラメータ / 49Bアクティブパラメータ、コンテキスト1Mトークン
- DeepSeek V4 Flash: 284B総パラメータ / 13Bアクティブパラメータ、コンテキスト1Mトークン、MITライセンス
ザッと上のような感じで、どう考えてもVRAM 128GB程度の環境では動作しない。ローカルLLM勢にとっては雲の上の存在だ(笑)。
ところがゴールデンウィークも明けた5月10日前後から、にわかに筆者のX界隈が騒がしくなってきた。それは「DwarfStar 4」なら128GB搭載したMac(M3 Ultra/M4 Max/M5 Maxなど)でDeepSeek V4 Flashが動く!というものだ(実際のDwarfStar 4のリリースは4月24日でゴールデンウィーク前)。
調べてみるとここでコードが公開されているようだ。作者はなんとオープンソースデータベース「Redis」の作者antirez氏によるDeepSeek V4 Flash専用のMetal推論エンジンだったりする。当初はds4.cと呼ばれていたが、現在はDwarfStar 4と命名された。特徴は、
- antirez氏(Redisの作者)がGPT-5.5の強力な支援で開発したC言語のネイティブ推論エンジン(つまりバイブコーディング)
- Metal専用、llama.cppに依存しない独自実装
- DeepSeek V4 Flash専用に特化
- ディスクKVキャッシュ
- 2bit量子化で128GB MacBook上での実用運転が可能
- MoEエキスパート部分だけ2bit(IQ2_XXS/Q2_K)、それ以外はそのまま
- サーバー機能もありOpenAI API互換などのendpoint対応(Claude Code、opencode、Piとの連携設定込み)
と、どれもかなり特徴的なのだが、まずは注目なのがサイズだ。サイズを計算すると以下のようになる。
| パラメータ数:284B | 量子化理論サイズ |
|---|---|
| FP16(16bit) | 284B×2byte = 568GB |
| 8bit | 284B×1byte = 284GB |
| 4bit | 284B×0.5byte = 142GB |
| 2bit | 284B×0.25byte = 71GB |
なるほど。確かに2bit量子化ならVRAM 128GBに収まる。ただ、実際のQ2 GGUFは86.7GBなので、理論値の71GBより大きい。これはルーターMoEエキスパートのみ2bitで、共有エキスパート、プロジェクション、アテンション部分はQ8やFP16のまま残しているためだ。
この説明ではよく分からないと思うので、仕組みを大雑把に書くと、全トークンで必ず通るか、選ばれたときだけ通るかの違いで、前者は高い部分精度を保ち、そうでないところはQ2化してサイズを落として、容量を抑えつつ品質を維持する仕組み、といった辺りだ。
次にDeepSeek V4 Flash専用に特化とディスクKVキャッシュだ。この2つはつながりがあり、KVキャッシュの持ち方が独自なのだ。
一般的なLLMは、GQA(Grouped Query Attention)を採用しており、KVキャッシュのサイズは、「トークン数×レイヤー数×ヘッド数×次元数」に比例して膨らむ。たとえばLlama 3.1 70B相当のモデルで1Mトークンのコンテキストを扱うと、数百GB〜TB級のKVキャッシュが必要で、これではどこにKVキャッシュを置いてもたまったものではない。
ところが、DeepSeek V3/V4系列が採用する独自のアテンションアーキテクチャであるMLA(Multi-head Latent Attention)は、キーとバリュー(つまりKV)を低次元の潜在ベクトルに圧縮してからキャッシュする。従って、通常モデルのわずか2〜5%のサイズで済み、1Mトークンで約26GB。ローカルLLMの場合、多くても128Kトークンなのでさらに1桁小さいサイズに収まるのだ。
ただし、汎用のllama.cppなどはGQA前提で作られているため、MLAのKVキャッシュを扱うには一度展開しなければならず非効率的だ。これが、DwarfStar 4がMetal専用で独自エンジンたる理由だ。
さて、ここで疑問なのだが、128Kトークンでも2GB程度なら、86.7GBに加えても128GBのRAM(メモリ)に収まるのでは?という点だろう。しかし、DwarfStar 4は(逆に)意図的にKVキャッシュをSSDへ置いているのだ。
SSDキャッシュの利点は、
1. セッションをまたいで永続化
サーバー再起動後もキャッシュが残る。Claude Codeを再起動しても28Kトークンのprefillが91msで復元。これはRAMキャッシュでは絶対に実現できない
2. 複数セッションのキャッシュを保持
異なるプロジェクト・異なるシステムプロンプトのキャッシュを複数ファイルとして保存しておける。切り替えのたびにゼロから再prefillする必要がない
3. 容量を気にせず積める
SSDは数TBが当たり前。--kv-disk-space-mb 8192(8GB)でも、数十セッション分が貯められる。RAMでこれをやろうとすると貴重な128GBを食い潰す。
4. DeepSeek V4 FlashのMLAとの相性が良い
MLA(Multi-head Latent Attention)でKVキャッシュが極端に小さい(通常モデルの数十分の1)ため、SSDへの書き込み・読み出しが高速で現実的。たとえば26Kトークンで372MBは内蔵SSDなら一瞬
といったところが挙げられる。それに対してSSDキャッシュの欠点は、
1. 初回は必ずコールドスタート
新しいセッション・新しいシステムプロンプトの初回は4分(環境依存)のprefillが避けられない
2. キャッシュキーが厳密
キーはレンダリングされたバイト列のSHA1のため、モデル名やシステムプロンプトが1バイトでも変わると別キーになりキャッシュミスする(例: モデルidをdeepseek-v4-flash → deepseek-chatに変えただけでミス)
3. 外付けSSDだと恩恵が薄れる
KVキャッシュの価値はSSDの帯域に直結。つまり外部SSDで遅いものだと一気にパフォーマンスが落ちる
4. メモリ上のキャッシュは1セッション分のみ
ds4-serverの内部的な仕様になるが、RAM上のライブKVキャッシュを1つしか持てず、別セッションのリクエストが来ると現在のセッションをSSDに退避してから処理する。つまり複数クライアントの並行利用には向かない、つまり、パーソナル用途に限られる
といったように、SSDへKVキャッシュを置く方法は利点、欠点、どっちもどっち的な感じなのだが、antirez氏は欠点より利点を選んだのだろう。
DwarfStar 4を使ってみた
そんなDwarfStar 4だが、MacBook上でのインストールは驚くほど簡単!
% git clone https://github.com/antirez/ds4.git
% cd ds4
% make
% ./download_model.sh q2-imatrix
たったこれだけ。makeも瞬時に終わる。
モデルのダウンロードに関しては、初期は ./download_model.sh q2だったのが、後日q2-imatrix版が公開された。
imatrixは、量子化前にどのウェイトが推論に重要かをサンプルデータで事前計算し、重要なウェイトには精度を割り当て、重要でないウェイトは積極的に削る手法。同じbit数でも、品質が上がると言われている。従ってq2はもう使わない方が良いということになる。なお、q2-imatrixとq2の違いは品質だけで、推論速度的には同じだ。
準備ができたので、まず簡単なベンチマークテストを2つ。1つはコンテキストが短い、もう1つはコンテキストが長い(README.mdをそのままプロンプト)ものだ。
% ./ds4 -p "Scrivi una breve storia su un vecchio pescatore che vive in un piccolo villaggio sul mare." --ctx 32768 --nothink -n 256
ds4: context buffers 1061.71 MiB (ctx=32768, backend=metal, prefill_chunk=2048, raw_kv_rows=2304, compressed_kv_rows=8194)
ds4: Metal device Apple M4 Max, 128.00 GiB RAM.
.
.
ds4: prefill: 54.96 t/s, generation: 31.29 t/s
% ./ds4 -p "$(cat README.md)" --ctx 32768 --nothink -n 256
ds4: context buffers 1061.71 MiB (ctx=32768, backend=metal, prefill_chunk=2048, raw_kv_rows=2304, compressed_kv_rows=8194)
ds4: Metal device Apple M4 Max, 128.00 GiB RAM.
.
.
ds4: prefill: 260.89 t/s, generation: 23.22 t/s
結果はご覧の通り。prefillもgenerationもそこそこ出る。20〜30tok/s程度出ていれば、普通にチャットする程度なら十分な速度といえるだろう。
サーバーとしての起動は以下の通り。OpenAI APIのエンドポイントに加え、コーディングエージェントの「Claude Code」で必要な/v1/messagesにも対応している。
% ./ds4-server --ctx 131072 --kv-disk-dir /tmp/ds4-kv --kv-disk-space-mb 8192 --host 0.0.0.0
ds4: Metal device Apple M4 Max, 128.00 GiB RAM
ds4: requesting Metal residency (may take tens of seconds)... done
ds4: warming Metal model views... done
ds4: Metal model views created in 3.296 ms, residency requested in 575.604 ms, warmup 4.647 ms (mapped 82697.67 MiB from offset 5.08 MiB)
ds4: Metal mapped mmaped model as 2 overlapping shared buffers
ds4: metal backend initialized for graph diagnostics
0512 15:48:22 ds4-server: context buffers 3665.71 MiB (ctx=131072, backend=metal, prefill_chunk=2048, raw_kv_rows=2304, compressed_kv_rows=32770)
0512 15:48:22 ds4-server: KV disk cache /tmp/ds4-kv (budget=8192 MiB, cross-quant=accept, min=512, cold_max=30000, continued=10000, trim=32, align=2048)
0512 15:48:22 ds4-server: listening on http://0.0.0.0:8000
たとえば、Claude Codeで使うときは、環境変数を設定してからClaude Codeを起動する。
# 環境変数を設定してClaude Code起動
ANTHROPIC_BASE_URL="http://127.0.0.1:8000" \
ANTHROPIC_AUTH_TOKEN="dsv4-local" \
ANTHROPIC_MODEL="deepseek-chat" \
claude
また、モデルidにdeepseek-v4-flashを指定した時にはThinking有効、deepseek-chatとした時にはThinking無効となる。
Thinkingを有効にするか無効にするかは用途によるだろうか。ちなみに筆者がバイブコーディングする時は、DeepSeek V4 Flashに限らずすべて無効にして使っている。
最後のベンチマークテストは並列処理。先のKVキャッシュをSSDに置くといった仕組みからダメなのは分かっているが、念のため。
総実行時間: 17.28秒
平均応答時間: 17.28秒
最速応答: 17.28秒
最遅応答: 17.28秒
合計生成トークン: 500
平均トークン/秒: 28.93 t/s
スループット: 0.06 req/s
実効スループット: 28.93 tokens/s
総実行時間: 35.55秒
平均応答時間: 26.23秒 (±13.17)
最速応答: 16.92秒
最遅応答: 35.54秒
合計生成トークン: 1000
平均トークン/秒: 21.81 t/s
スループット: 0.06 req/s
実効スループット: 28.13 tokens/s
並列効率: 48.6% (1並列基準 28.93 t/s×2 = 57.85 t/s)
総実行時間: 61.90秒
平均応答時間: 41.15秒 (±20.74)
最速応答: 20.43秒
最遅応答: 61.90秒
合計生成トークン: 1500
平均トークン/秒: 14.90 t/s
スループット: 0.05 req/s
実効スループット: 24.23 tokens/s
並列効率: 27.9% (1並列基準 28.93 t/s×3 = 86.78 t/s)
総実行時間: 173.88秒
平均応答時間: 99.74秒 (±65.06)
最速応答: 25.50秒
最遅応答: 173.87秒
合計生成トークン: 2000
平均トークン/秒: 8.36 t/s
スループット: 0.02 req/s
実効スループット: 11.50 tokens/s
並列効率: 9.9% (1並列基準 28.93 t/s×4 = 115.71 t/s)
ご覧のように並列の数が増えるとどんどん速度が低下する。
この件、実はClaude CodeやOpenCodeを使うときは結構重要で、2並列程度は普通によく出ている。この点もあって、実際Claude Codeで使うと、我慢できなくもないがちょっと遅い……という、微妙な線に。加えてGPUやメモリをかなり消費する関係で、ほかの処理がもっさりし出し、MacBook Proの筐体も熱くなる。
もしDeepSeek V4 Flashを常用するなら、MacBook Proを専用マシンとし、通常業務はほかのマシンへ移したいところ。ここでMacBook Neo登場か(笑)!?
この辺りの肌感は、用途やユーザーの感覚にもよるだろう。筆者的には一般的なチャットで済ますのが無難かな?というところ。
一般的なチャットで思い出したが、Open WebUIは、エンドポイントから/v1/modelsで得られるモデルidしか通常は選べない。そして困ったことにds4-serverの場合、deepseek-v4-flashしか返さず、Thinkingなしのdeepseek-chatが選べないのだ。
これを何とかするには、Open WebUIの管理者パネル → 設定 → 接続のOpenAI API接続の管理、つまりエンドポイントを設定するところのモデルIDに、deepseek-v4-flashとdeepseek-chat、この2つを登録しておく。こうするとモデル選択画面が2択になり、好みの方を使えるようになる。
執筆中もDeepSeek V4 Flashを使い、いろいろ試しているが概ね感覚は良好。残念なのはVision(視覚)非対応なことだろうか。
今のところDeepSeek V3/V4系列以外、このMLA(Multi-head Latent Attention)でKVキャッシュする手法を採用したモデルはなく、そんなにいいのなら、ほかも真似すれば……と思うのだが、一から学習し直しになり、既存のものはコスト的に問題が出るのだろう。
唯一、2026年3月17日に楽天グループが「国内最大規模」とうたう671BパラメータのMoEモデル「Rakuten AI 3.0」を発表。技術的なベースはDeepSeek V3なのだ。671Bあるので2bit量子化しても128GBには乗らないものの、今回のDwarfStar 4は多分適用可能だ。誰か実験はしないだろうか。
そしてこの原稿を書いている最中にビックニュース!DwarfStar 4がDGX Sparkに対応。これも試すこととなった。DGX Spark互換機でも無事DwarfStar 4が起動。トークン出力速度はM4 Max 128GBの半分程度だが、prefillが速いので結構いい感じに動いている。
以上のように、LLMの春の陣、なかなか面白い技術2つが登場した。ただ、どちらも試せるのがメモリ128GB搭載のDGX SparkとM4 MaxのMacBook Proのみ。“ご家庭用AI PC”と呼ぶのは厳しい価格帯だろう。
とはいえ、今回のような技術を使い、もっと軽量なLLMや環境、もっと手軽な設定でLLMが使えるようになる日も、割とすぐに来るのではないだろうか。この記事でちょっとした先取り感を味わって頂ければ幸いだ。
























