TL;DR(先に結論)
-
24GBのコンシューマGPU(RTX 3090 / Ampere)× gemma4 では、
gemma4-26B-A4B(MoE)+ Ollamaが最速かつ最良だった。 - vLLMは「多ユーザ処理が速い」で有名だが、それは"同じモデルなら"の話。今回は MoEの軽さ(アクティブ4B)が vLLM の継続バッチ処理に勝った。
- vLLMでgemma4を動かすのは、80GB級 / Blackwell GPUが事実上の前提(公式レシピにもそう書いてある)。
- 「もっともらしいAIの助言」や断片的なブログ情報は、実機で試すと次々に落とし穴があった。この記事はその実録。
背景
ローカルLLMの推論ノードとして、中古のRTX 3090(24GB)搭載機を1台組んだ。手元の本命モデルは gemma4 と Qwen3.8。
「本番の多人数処理なら vLLM だろう」という一般論を信じて、gemma4 を vLLM で立てようとした??ところが、ここからが長かった。
セットアップで先にハマった所(GPU以前)
本題の前に、地味だが刺さるポイント3つ。
-
NVIDIAドライバのカーネル不一致
dkmsでドライバを入れて再起動したらnvidia-smiが死んだ。原因は、パッケージ導入時にカーネルが更新され、GRUBが新カーネルで起動したのに、dkmsは旧カーネル向けにしかビルドしていなかった、という罠。
→dnf install kernel-devel-$(uname -r)で現行カーネルの devel を入れ、dkms autoinstall -k $(uname -r)で再ビルドして解決。 -
650W電源 × RTX 3090 は電力制限が事実上必須
3090はスパイクが大きく、650Wだとトランジェントで落ちるリスク。nvidia-smi -pl 280で電力制限(性能ロス数%)+ systemd で起動時に自動適用して安定化。 -
Rockyのデフォルトパーティションは
/が70GBで頭打ち
自動パーティションだと/が70GBに制限され、残り(数百GB)が使わない/homeに割り当たる。LLMはモデルで容量を食うので、空の/homeLVを削除して/に統合(XFSはオンライン拡張・無停止)。
本編:vLLM × gemma4 の落とし穴フルコース
gemma4をvLLMで動かそうとして、壁を1枚ずつ越えては次の壁にぶつかった。順番に:
-
configパースで即死
AmbiguousGlobalPerLayerAttributeError: 'head_dim' is a per-layer attribute。
gemma4は層ごとにattentionの形(head_dim)が違う特殊構造で、新しいtransformersがそれを厳格化。pip版のvLLM(安定版)はこれに未対応。
→ 修正は未リリースのソースにしか無く、公式Dockerイメージvllm/vllm-openai:gemma4-cu130を使うのが正解。uv pip ... --index-strategy unsafe-best-matchでないとnightlyも掴めない、というオマケ付き。 -
MoEの4bitカーネルがAmpereに無い
修正版でconfigは通ったが、gemma4-26B-A4B(MoE)をAWQ/GPTQ 4bitで動かすと、
Failed to find a kernel: Marlin requires ... 割り切れない次元 / Cutlass・Machete は capability 90(Hopper) 必要。
→ MoEの4bit × Ampere(cap 8.6) は、vLLMのカーネルが対応していない。 -
NVFP4はBlackwell専用
「NVFP4なら4bitで小さい」という情報があるが、NVFP4はB200/B300(Blackwell)専用。3090では動かない。 -
dense 31B は載るが KV枯渇
MoEを諦めてdense 31B AWQにすると、configもカーネルも重みロードも全部通過!…したが、
weightsで約20GB使い、KVキャッシュが1.5GBしか残らず、実用context 1856トークンが限界。24GBには31Bは大きすぎ。 -
「27B dense」は存在しない(それはGemma 3)
じゃあ27B denseで、と思ったら??Gemma 4のdenseは 12B と 31B のみ。26Bは A4B(MoE)。27BはGemma 3だった。 -
公式レシピが全てを語っていた
vLLMの gemma-4-26B-A4B 公式レシピには「単一GPUで約80GB VRAM必要/対応GPUは A100・H100・B200等」と明記。
→ そもそも gemma4 の vLLM 対応は"80GB級データセンターGPU"前提。24GBの3090は対象外。
教訓:Ollamaが3090でgemma4を動かせるのは、llama.cppが独自カーネルで4bit MoEをAmpereでも捌けるから。vLLMとは得意分野が違う。
クライマックス:A/Bベンチ(gemma4-MoE+Ollama vs Qwen3.8-27B-dense+vLLM)
「じゃあ dense の Qwen3.8-27B なら vLLM で動く(Qwenは素直)」??これは動いた。
gemma4の全ブロッカーが無く、素直にREADYまで到達(KVを詰めるチューニングは必要)。
そこで同じ質問で A/B比較した。
単発レイテンシ(両方とも思考オフで公平化)
| 質問 | gemma4-26B-A4B (Ollama) | Qwen3.8-27B (vLLM) |
|---|---|---|
| 消費税率 | ? 0.48s | ? 0.82s |
| 要約 | ? 0.53s | ? 1.54s |
| 数列(等比) | ? 1536(正解) / 0.84s | ? 768(計算ミス) / 4.7s |
| 箇条書き | ? 0.91s | ? 1.96s |
8並列スループット
| 総時間 | 実効スループット | |
|---|---|---|
| gemma4-MoE (Ollama) | 6.8s | 133.6 tok/s |
| Qwen3.8-27B (vLLM) | 15.6s | 69.7 tok/s |
単発で2?5倍、8並列でも約2倍、gemma4-MoE+Ollamaが速い。 品質も互角?やや上(Qwenは等比数列で 3×512=768 と計算ミス)。
なぜ「vLLMなのに負ける」のか
- gemma4-26B-A4B は MoE:1トークンでアクティブ4Bしか動かない(激軽)
- Qwen3.8-27B は dense:27B全部動く(1トークンあたり約7倍重い)
- vLLMの継続バッチ処理をもってしても、"1トークンの計算量が7倍重い"のは覆せない。しかも重い量子化でKVが小さく、最大4並列が頭打ち。
→ 「vLLM = 速い」は一般論。実際のボトルネックは"モデルの1トークンあたりの計算量"。MoEの軽さが効く場面では、Ollama+MoEが勝つ。
結論
-
24GBコンシューマGPU × gemma4 なら、
gemma4-26B-A4B(MoE)+ Ollamaが最適解(実測で確定)。 - スケールは「エンジンを変える」より「ノードを足してLBで束ねる」方が正しい(同じ機を2台→容量2倍)。
- vLLMの本領は、80GB級/Blackwell GPUで、MoEを継続バッチ処理する時。上位機を積んだら解禁。
- AIの助言も断片ブログも、"もっともらしいが実機で詰む"ことがある。最後は自分の環境で試すのが一番早い。
付録:ハマりどころチェックリスト
- dkmsドライバは現行カーネルのkernel-develを入れてから(インストール中のカーネル更新に注意)
- 650W電源+3090は電力制限(280W前後)を永続化
-
Rockyデフォルトの
/70GB頭打ちに注意(空/homeを/へ統合) - gemma4のvLLMは公式Dockerイメージ必須(pip安定版はconfigバグ)
- MoEの4bit × Ampere はvLLMカーネル非対応、NVFP4はBlackwell専用
- gemma4-26Bは公式に80GB VRAM前提(24GBは対象外)
- 「27B dense gemma4」は無い(それはGemma 3)
-
denseは動くが、大きいモデルはKVキャッシュ枯渇に注意(
--max-model-lenと--gpu-memory-utilization、--enforce-eagerで調整) -
**思考モデルは
reasoning_effort:noneやenable_thinking:false**で公平比較を(でないとトークンを食って答えが切れる)