こんな環境で悩んでいませんか
- RTX 5070や5060クラスのGPUが1〜2枚
- VRAMは12GB前後、大きいモデルは入らない
- でもローカルLLMは長い文脈もサクサク動いてほしい
この条件、実はNemotron-3-Nano-30B-A3Bがかなり刺さります。理由は「賢さの割にKVキャッシュがめちゃくちゃ軽い」という一点に尽きます。
まず数字で見てください
ローカルのサーバー(RTX 5070 12GB×2)での実測値です。
速度(同条件・同GPUで比較)
| 前に使っていた9B | Nemotron-3-Nano-30B | |
|---|---|---|
| 単発 | 69.8 tok/s | 134.4 tok/s |
| 4並列 | 252 tok/s | 411.0 tok/s |
| 60並列(8081直接・LAN IP・5試行平均) | 1066〜1113 tok/s | 723.9〜773.1 tok/s |
パラメータ数だけ見ると30Bで9Bより大きいのに、単発〜4並列ではNemotronの方が速いです。理由は後述しますが、1トークンあたり実際に動くのはたった3.2B分だけだからです(MoE構成)。
ただし正直に書くと、60人同時アクセスのような極端な高並列では9Bの方が上回ります。MoEのエキスパートルーティングとMamba状態更新が、9Bの単純なDense Transformerほど効率よくバッチ化できていないためだと考えています(未検証の推測です)。個人ホームラボで60人同時利用は現実的にまず起きないので実運用上は気にしなくて良いですが、数字は盛らずそのまま載せておきます。
KVキャッシュ(文脈の持ちやすさ)
| 目安 | |
|---|---|
| VRAM 500MBのKV予約分で持てるトークン数 | 約25万トークン(≒同時ユーザー約2人分@128K文脈) |
| 12GB×2構成での実運用コンテキスト長 | 128K |
500MBという、他のモデルなら一瞬で溶けるような容量で、これだけの文脈が持てます。理由は、全52層のうちAttentionを使う層がたった6層しかないためです。残りはMamba(状態空間モデル)という別の仕組みで、こちらはKVキャッシュをほぼ必要としません。
「30Bだから重い」は誤解で、実際にVRAMを圧迫するのはAttention層の数であって、パラメータ数そのものではありません。ここがNemotronの一番の強みです。
とりあえず動かしてみる(最短ルート)
vLLM/Aphrodite系のエンジンなら、以下のフラグだけ意識すれば動きます。
# WSL2環境なら必須(V2ランナーはUVAでクラッシュする)
export APHRODITE_USE_V2_MODEL_RUNNER=0
aphrodite run nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B-AWQ \
--enable-expert-parallel \
--reasoning-parser nemotron_v3 \
--enable-auto-tool-choice \
--tool-call-parser qwen3_coder
これで会話・ツール呼び出し・思考モードまで一通り動きます。躓きやすいポイントだけ先にまとめておきます。
-
--enable-expert-parallelは忘れずに: GPU2枚以上でMoEの中間サイズが割り切れずエラーになることがある -
reasoning parserは内蔵の
nemotron_v3を使う: 自作/移植版の別パーサーだと<think>タグが文字化けして漏れることがある(Nemotron特有のトークナイザの都合) -
thinking_token_budgetが効かない場合: これは実際にバグでした。詳細は後半に書きますが、Aphrodite 0.22.0の時点では2行のパッチで直ります
実際にうちの本番で使っているフルの起動コマンド
最短ルートに、VRAM節約とチューニングのフラグを足すとこうなります(RTX 5070 12GB×2、TP=2構成)。
aphrodite run stelterlab/NVIDIA-Nemotron-3-Nano-30B-A3B-AWQ \
--tensor-parallel-size 2 \
--enable-expert-parallel \
--kv-cache-dtype fp8 \
--gpu-memory-utilization 0.85 \
--kv-cache-memory-bytes 500000000 \
--max-model-len 131072 \
--max-num-seqs 64 \
--max-num-batched-tokens 4224 \
--enable-prefix-caching \
--mamba-cache-mode align \
--reasoning-parser nemotron_v3 \
--enable-auto-tool-choice \
--tool-call-parser qwen3_coder
-
--kv-cache-memory-bytes: KVキャッシュに使うVRAM量をバイト単位で明示指定。500MBで約25万トークン分持てます(冒頭の表の通り) -
--kv-cache-dtype fp8: KVキャッシュをfp8に落として容量をさらに節約 -
--max-num-seqs: 同時に処理できるリクエスト数の上限。64にすると60並列でも待ち行列が詰まらず、単発〜60並列のどのレンジでも16設定より速くなりました(具体的な数字は次のセクションの表を参照) -
--mamba-cache-mode align: Mamba状態キャッシュのメモリ確保方式。alignにするとブロック単位で確保され安定します
他のモデルと比べてどうか
同じくらいのサイズ感で候補に挙がるモデルとの比較です。
| Nemotron-3-Nano 30B | Qwen3.6-27B | Gemma 4 26B MoE | |
|---|---|---|---|
| Attentionを使う層の割合 | 52層中6層 | 64層中16層 | 全層(sliding window+global) |
| KVキャッシュの重さ | かなり軽い | 中間 | 重い |
| 賢さの傾向 | 実行・ツール呼び出しに強い | 総合力が高い | サイズの割に賢い |
Gemma 4は賢いのですが、Mambaのような軽量機構を使っておらず全層アテンションに近いため、うちのVRAM(12GB×2)だと文脈を伸ばした瞬間にKVキャッシュがきつくなります。Qwen3.6-27Bは一部Mamba的な機構(Gated DeltaNet)を持っていて中間的。VRAMが限られたコンシューマGPU環境では、Nemotronの「Attention層を極限まで削る」設計が一番相性が良いという結論に落ち着きました。
ここまでで「試してみようかな」と思っていただけたら十分です。以下は実際に本番投入した際に踏んだバグの話で、興味があれば読んでください。
おまけ: thinking_token_budgetのバグを追いかけた話
本番投入した日の夕方、「こんにちわ」と送っただけなのに1分以上「思考」し続けた。
thinking_token_budgetは本来これを防ぐパラメータです。16から4000まで、どんな値を設定しても常に5,900〜6,300文字前後「思考」し続け、指定値を完全に無視していました。
デバッグ用のprint文を状態管理クラスに仕込んで確認したところ、予算超過を検知するはずの状態更新関数が、デコードループのどこからも一度も呼ばれていないことが判明しました。バッチへのリクエスト追加・削除・移動のタイミングでしか呼ばれておらず、1本のリクエストが継続して生成し続けている間は状態が一切更新されない、という配線漏れでした。
さらにもう1箇所、実際に</think>をlogitsへ強制注入する関数も、投機的デコード専用のパスにしか配線されておらず、通常経路からは一度も呼ばれていませんでした。
| 修正前(budget=16) | 修正後(budget=16) | |
|---|---|---|
| 思考の文字数 | 5,927〜6,324文字(budgetを完全無視) | 73文字(指定通り打ち切り) |
修正自体は、既存の投機的デコード用パスで動いていたのと同じ呼び出しを、本来呼ばれるべき2箇所に足しただけです。Aphrodite Engineのupstreamへfix: thinking_token_budget has no effect when async scheduling is enabledとしてPRを提出し、CI通過・マージされました。
Aphroditeで思考予算モデルを動かしていて、指定した値が無視されている場合は、async schedulingが有効になっていないか確認してみてください。デフォルトで有効になっています。
次に欲しいもの
Nemotron-3-Nanoはこのhomelabの本番モデルとして定着しました。もしNemotron 3.5 Lightningの、特定の推論スタックに縛られない量子化版(AWQやGPTQのように普通に読み込める形式)が出たら、次に試したいと思っています。
コンシューマGPU2枚のhomelabから。DGXではありません。