⏱ 読了目安: 約9分
- ナレッジワークのエンジニアがGemma3派生の翻訳LLM「MiLMMT-46」をゲーミングPC向けに最適化する手法を公開。
- Vision削除と語彙半減、imatrix量子化、ubatch縮小、CUDA依存切断でVRAM消費を9GB超から2.7GBへ圧縮。
- 限られたローカルGPU資源でLLMを常駐稼働させるための、モデル・メモリ・ランタイム三位一体の最適化手順が確立。
GPUメモリ奪い合いの壁
深夜、Discordのボイスチャットを繋ぎながらフレンドとオンラインゲームを起動し、ふとタスクマネージャーのパフォーマンスタブを見て絶望した経験はないだろうか。グラフィックボードのVRAM使用率は既に天井近くの90%台に張り付き、ファンは轟音を上げている。そこに「翻訳チャットボットを常駐させたい」とローカルLLMを立ち上げれば、待ち受けているのは凄惨なクラッシュか、画面の凄まじいカクつき、あるいはCUDA Out of Memoryの冷酷なエラーログだ。グラフィックスカードを占有できるサーバーサイドと異なり、クライアントPC環境におけるLLMのデプロイは、常に「他プロセスとの熾烈なリソースの奪い合い」という冷徹な現実から始まる。
株式会社ナレッジワークのAIリサーチャーであるTaein Kim氏が直面したのも、まさにこの現場特有の生々しい課題だった。ターゲットは、海外プレイヤーとリアルタイムでコミュニケーションを取りながら遊ぶオンラインゲームのチャット翻訳である。協力プレイを行う仲間のPC環境は、GeForce RTX 4080 SUPER(16GB)のハイエンドから、RTX 4070 Ti(12GB)、さらには旧世代のGTX 1060(3GB)まで極めてバラつきが大きい。しかも、同じGPUであっても1080p(FHD)で遊ぶか4K(UHD)で遊ぶかによってゲームエンジン自体のVRAMフットプリントは激変する。高解像度環境では、いくら潤沢に見える12GB〜16GBのVRAMであっても、残されたパイはわずか数ギガバイトに過ぎないのだ。
そこで採用されたのが、Xiaomi Researchが公開したGemma3ベースの翻訳特化オープンウェイトモデル「MiLMMT-46」である。1B、4B、12Bの3サイズが用意され、商用LLMに匹敵する翻訳品質を謳う期待のモデルだ。しかし、基準環境(Ryzen 7 7700 / RTX 4070 Ti)でゲームを起動しながら公式GGUFモデルを検証したところ、実用的な翻訳ニュアンスを維持できる「4B Q4_K_M」でさえ動作に引っかかりが生じ、12Bに至っては実行不可に追い込まれた。1Bなら動作は極めて軽快だが、敬語のニュアンスが抜け落ちたり文意が粗雑になったりと、チャット翻訳として常用するには品質に不満が残る。このジレンマを突破するには、モデルサイズ・プロセスメモリ・推論ランタイムのすべてに外科手術を施し、4Bクラスの知能をVRAM 2〜3GBの極小フットプリントへ押し込める以外に道はなかった。
語彙スライスとimatrix
「モデルファイルを小さくしても、VRAMは思ったほど減らない」――この現象に直面し、頭を抱えた開発者は多いはずだ。重みファイルをストレージ上で削るだけでは不十分なのだが、まずは基礎体力としてのモデルファイル自体の贅肉を極限まで削ぎ落とす必要がある。Kim氏が実行した最初のアプローチは、Gemma3が抱える構造的な無駄の徹底排除だった。MiLMMT-46はマルチモーダルを前提としているため、チャット翻訳には一切不要なVisionエンコーダーとProjectorが含まれている。これらを切除してtext-onlyのBF16 GGUFに変換するだけで、ファイルサイズは9.94GBから7.77GBへと一気に2.2GB削減された。
次なるメスが入ったのは語彙(Vocabulary)だ。MiLMMT-46は46言語対応を誇るがゆえに約26万トークン(262,208)という広大な埋め込み(Embedding)層を保持している。だが、個人がオンラインゲームで使う言語ペアは日本語・英語・韓国語の3言語程度に限定される。約1,145万件(約3.77億トークン)の対訳コーパスをトークナイズして実頻度を走査したところ、3言語で1度でも使われたトークンは全体の半分以下の120,699個に過ぎなかった。ここで重要なのは、単に出現頻度だけでバッサリ切り捨てるのではなく、特殊トークンやbyte fallbackトークン(<0xNN>)、チャットテンプレート、記号・固有名詞を含む6,861個のクリティカルなトークンを強制保護した点だ。
語彙サイズを100k、130k、160kと検証した結果、100kではカバー率99.976%でありながら英語トークンの分割膨張(平均+5.6%)を招き、FLORES+ベンチマークで翻訳品質が不合格ラインまで低下した。最終的に、観測トークンを一切落とさない「130k」が選定され、埋め込み層のスライスによってモデルは7.08GBまでスリム化された。なお、調子に乗ってTransformerのレイヤー自体を34層から31層へ間引く実験も行われたが、品質スコア(chrF++)が81%台まで暴落し即座に却下されている。追加の蒸留やLoRAによるファインチューニングを経ない構造的プルーニングは、推論能力の致命的な破壊を招くという貴重なアンチパターンだ。
そして仕上げとして、単なる一律量子化ではなく、日英韓のキャリブレーションデータを流して重みの重要度を算出する「imatrix(importance matrix)」を用いた量子化が施された。過度なビット削減(Q3/IQ3)による破綻を避けつつ、最終的に選ばれた「imatrix Q4_K_S」によって、モデルファイルは当初の9.94GBから2.1GB(約79%減)にまで圧縮されたのである。FLORES+による評価でも元モデル比99.80%のスコアを維持しており、品質劣化を事実上ゼロに抑え込んだ鮮やかな外科手術と言える。
ランタイムの徹底解体
しかし、本番の戦いはここからだった。重みファイルを2.1GBまで削ったにもかかわらず、llama.cppベースのプロセスを起動してVRAMを計測すると、依然として2.9GB、初期状態では9.02GBものリソースを食い散らかしていたのだ。ストレージ上のモデルファイルサイズと、VRAM上に展開されたプロセスの実消費メモリは全く異なる。プロセスメモリには、モデルの重みだけでなく、アテンション機構が保持するKV cache、バッチ処理のためのバッファ、そして推論フレームワーク固有のランタイムオーバーヘッドが重層的に乗っかってくるからだ。
ここでKim氏が打ったクリティカルな一手が「ubatch(マイクロバッチ)」パラメータの調整である。サーバーサイドで複数ユーザーのリクエストを並列処理するならいざ知らず、ローカルでのチャット翻訳は「画面に流れた短い1文を逐次処理する」ストリーミングユースケースに特化している。デフォルトで2048に設定されていたubatchを「128」へと絞り込むことで、無駄に確保されていたバッファ領域が一気に解放され、プロセスの実効VRAM消費は2.7GBまで低下した。当初の9.02GBから約70%の削減を達成し、これでようやく4K解像度でゲームをレンダリング中のGPU上にも、平然と常駐できる計算が成り立った。
| 最適化対象 | 最適化前(Baseline) | 最適化後(Optimized) | 削減率 / 変更内容 |
|---|---|---|---|
| モデルファイル容量 | 9.94 GB | 2.1 GB | -78.9%(Vision除外、語彙130k、imatrix Q4_K_S) |
| プロセス占有VRAM | 9.02 GB | 2.7 GB | -70.1%(ubatch 2048 → 128への絞り込み) |
| ランタイム配布容量 | 843.62 MB | 10.85 MB | -98.7%(cuBLAS/cuBLASLt依存完全排除のカスタムビルド) |
さらにエンジニアとして舌を巻くのが、推論ランタイムそのもののフットプリント削減だ。llama.cppのCUDAビルドをそのまま同梱して配布しようとすると、CUDAランタイムや巨大なcuBLAS、cuBLASLtといった共有ライブラリが引っ張られ、推論バイナリだけで840MB超に肥大化する。クライアント配布型アプリケーションとして、このオーバーヘッドは極めて不格好だ。Kim氏は今回のターゲットモデル(Gemma3ベースのQ4_K_S)が要求する特定のCUDAカーネルのみを厳選してggml-cuda.dllをカスタムリビルドし、cudartやcuBLASへの依存を完全に切断した。その結果、ランタイム全体の容量は843MBからわずか10.85MBへと、98%以上のシュリンクを達成したのである。
ローカルデプロイの処方箋
本検証が我々エンジニアに突きつける教訓は極めて重い。それは「モデル最適化」「プロセス最適化」「ランタイム最適化」の3つを完全に分離して設計しなければ、エッジやクライアントPCにおけるローカルLLMデプロイは決して成功しないという冷徹な事実だ。Hugging Faceからダウンロードした量子化済みGGUFをそのままLM StudioやOllamaに放り込み、「動かない」「重すぎる」と諦めていた開発者は多いだろう。だが、不要なマルチモーダル層の切除、ターゲットドメインに絞った語彙のスライス、ユースケースに特化したバッチバッファの極小化、そして不要なベンダーライブラリのパージという一連のステップを踏めば、商用モデル級の言語処理能力を、GPUの片隅の2GB台のスペースにねじ込むことが可能なのだ。
明日からローカルLLMの実装やクライアント配布に取り組む読者は、まず自らのユースケースにおける「入出力の同時性」と「ドメイン言語」を徹底的に棚卸ししてほしい。もし対話やチャットの翻訳といった短文処理であるならば、即座にランタイムのバッチサイズやKV cache設定を見直すべきだ。また、多言語モデルを特定言語ペアでのみ利用しているなら、埋め込み層に眠る数十万の未使用トークンをスライスするスクリプトを走らせる価値は十分にある。
だが、最後に敢えて問いたい。クラウドAPI全盛の現代において、我々はなぜここまで血を流してローカル推論の軽量化に執着するのか。ネットワーク遅延の完全な排除、外部サービス依存からの脱却、ゼロコストでの連続推論、そして何よりユーザーの手元で完全に完結するプライバシーの担保――その価値を最大化するためには、巨額の計算リソースに物を言わせるアプローチとは対極にある、ハードウェアの限界と泥臭く対峙する組み込みエンジニアリングの精神こそが、今まさにLLM開発現場に再要求されているのではないだろうか。


コメント