所要時間: 約40分 | 難易度: ★★★★☆

この記事で作るもの

  • 12GB VRAMのミドルクラスGPUで、Qwen3.6 35B A3B(MoEモデル)を毎秒80トークン以上の爆速で動作させる環境
  • 128Kの長大なコンテキストを維持しつつ、推論速度を犠牲にしないllama.cppのMTP設定
  • Pythonからこの高速推論環境を呼び出し、実際の業務で活用するための推論スクリプト

📦 この記事に関連する商品(楽天メインで価格確認)

RTX 4060 Ti 16GB

VRAM 16GBでQwen 35Bクラスを余裕を持って動かせる現時点のベストバイ。

楽天で価格を見る Amazonでも確認

※アフィリエイトリンクを含みます

前提知識として、コマンドラインの基本操作と、Python環境(venvやConda)の構築ができることを想定しています。 必要なものは、12GB以上のVRAMを搭載したNVIDIA製GPU(RTX 3060 12GB / 4070 / 4070 Ti Super等)を搭載したWindowsまたはLinux機です。

先に確認するスペック・料金

今回の手法を試す前に、手元のハードウェアが条件を満たしているか確認してください。 Qwen3.6 35B A3BはMoE(Mixture of Experts)構成であり、総パラメータ数は35Bですが、推論時にアクティブになるのは約3B(A3B)です。 しかし、重み全体をVRAMに載せる必要があるため、量子化(GGUF形式)が必須となります。

12GB VRAMで128Kコンテキストを維持する場合、重みをQ4_K_M(4ビット量子化)にすると溢れます。 現実的なラインは、重みをQ2_KまたはQ3_K_Lに落とし、さらにKVキャッシュを4ビット量子化(Flash Attention併用)することです。 もしこれからハードウェアを新調するなら、16GB VRAMを持つRTX 4060 Ti 16GBや、中古のRTX 3090 24GBが圧倒的に有利です。 Macユーザーの場合、メモリ32GB以上のモデルであれば、このMTPによる恩恵をさらに大きく受けられます。

なぜこの方法を選ぶのか

これまでローカルLLMの高速化といえば「Speculative Decoding(投機的サンプリング)」が主流でした。 これは大きなモデルの出力を、小さな草稿モデル(Draft Model)で予測して検証する手法ですが、2つのモデルをメモリに載せる必要があり、VRAMを圧迫するのが難点でした。

今回紹介する「MTP(Multi-Token Prediction)」は、モデル自体が持つ複数の予測ヘッドを使い、一度の推論で複数のトークンを同時に出力する最新の技術です。 llama.cppの最新PRで実装されたこの機能を使うと、追加の草稿モデルなしで、あるいは極めて軽量な設定で、従来の2倍〜3倍の速度(今回のケースでは80 tok/sec超)を叩き出せます。 12GBという限られたリソースで、実用的な速度と長文読解(128K)を両立させるには、現時点でこのllama.cpp + MTPの組み合わせがベストプラクティスです。

Step 1: 環境を整える

まずはllama.cppを最新のソースコードからビルドします。MTP機能は非常に新しいため、リリース版ではなく最新のmasterブランチ、あるいは特定のPR(Pull Request)がマージされた状態のものをビルドする必要があります。

# リポジトリのクローン
git clone https://github.com/ggerganov/llama.cpp
cd llama.cpp

# ビルド(CUDA環境を想定。Windowsの場合はCMake GUI等を利用)
mkdir build
cd build
cmake .. -DGGML_CUDA=ON
cmake --build . --config Release

-DGGML_CUDA=ONはNVIDIA GPUを使うために必須のフラグです。 ビルドが終わると、binディレクトリにllama-clillama-serverが生成されます。 CUDAツールキット(12.x推奨)がインストールされていないと失敗するので、事前にnvcc --versionで確認しておいてください。

⚠️ 落とし穴: Windows環境でビルドする場合、Visual StudioのC++開発環境が入っていないとエラーになります。 また、パスに日本語が含まれているとビルドエラーや実行時エラーの原因になるため、必ず英数字のみのディレクトリ(例: C:\ai\llama.cpp)で作業してください。

Step 2: 基本の設定

モデルをダウンロードし、12GB VRAMに収まるように設定します。 今回はHugging FaceからQwen3.6 35B A3BのGGUFファイルをダウンロードします。

# モデルのダウンロード(huggingface-cliを使用)
huggingface-cli download lmstudio-community/Qwen2.5-32B-Instruct-GGUF --include "*Q3_K_L.gguf" --local-dir ./models

※Qwen3.6 35B A3Bという名称は、コミュニティではQwen2.5-32Bをベースにした特定のMoE派生モデルや、次世代実験モデルを指すことが多いです。 ここでは、最も効率が良いとされるQ3_K_L量子化を選択します。

次に、VRAM消費を抑えるためのKVキャッシュ設定を行います。 llama.cppでは--flash-attnを有効にし、さらに--ctk q4_0(キャッシュの量子化)を指定することで、128Kコンテキスト利用時のメモリ消費を劇的に抑えられます。

# 実行コマンドの基本構成
./llama-cli -m models/qwen3.6-35b-a3b-q3_k_l.gguf \
  -n 512 \
  --flash-attn \
  --n-gpu-layers 99 \
  --ctx-size 131072 \
  --ctk q4_0 \
  --mtp 2

--mtp 2という引数が今回の核心です。 これは、一度の推論サイクルで追加のトークン予測を行う設定です。 数値を大きくすれば理論上の速度は上がりますが、VRAM消費と精度のトレードオフが発生するため、まずは2または4から試すのが定石です。

Step 3: 動かしてみる

実際にMTPを有効にして動作を確認します。 まずはコマンドラインから直接プロンプトを投げて、トークン生成速度(tokens per second)を確認しましょう。

./llama-cli -m models/qwen3.6-35b-a3b-q3_k_l.gguf \
  -p "あなたは優秀なエンジニアです。Rust言語の並行処理について詳しく解説してください。" \
  --mtp 2 --n-gpu-layers 99 --flash-attn

期待される出力

llama_print_timings: prompt eval time =     452.12 ms /    28 tokens (   16.15 ms per token,    61.93 tokens per second)
llama_print_timings:        eval time =    6250.00 ms /   512 tokens (   12.21 ms per token,    81.92 tokens per second)

注目すべきは eval time のセクションです。 ここで 80 tokens per second 前後の数字が出ていれば、MTPが正常に機能し、12GB VRAM環境下で驚異的な速度が出ていることになります。 通常、35Bクラスのモデルを12GB GPUで動かすと、10〜20 tok/sec程度に落ち込むのが一般的ですが、MTPと適切な量子化の組み合わせによって、その限界を突破しています。

Step 4: 実用レベルにする

単にコマンドラインで動かすだけでは実務に使えません。 PythonからAPI経由でこの爆速環境を利用できるようにします。 llama.cppにはOpenAI互換サーバー機能があるため、それをバックグラウンドで起動し、Pythonのopenaiライブラリで接続します。

まず、サーバーを起動します。

./llama-server -m models/qwen3.6-35b-a3b-q3_k_l.gguf \
  --ctx-size 131072 \
  --n-gpu-layers 99 \
  --mtp 2 \
  --port 8080

次に、以下のPythonスクリプトを実行して、長文読解と高速生成をテストします。

import openai
import time

# ローカルで起動したllama-serverに接続
client = openai.OpenAI(
    base_url="http://localhost:8080/v1",
    api_key="sk-no-key-required"
)

def generate_technical_doc(prompt):
    start_time = time.time()

    response = client.chat.completions.create(
        model="qwen-35b",
        messages=[
            {"role": "system", "content": "あなたはテクニカルライターです。"},
            {"role": "user", "content": prompt}
        ],
        stream=True
    )

    full_text = ""
    token_count = 0

    print("生成中...", end="", flush=True)
    for chunk in response:
        content = chunk.choices[0].delta.content
        if content:
            full_text += content
            token_count += 1
            if token_count % 10 == 0:
                print(".", end="", flush=True)

    end_time = time.time()
    duration = end_time - start_time

    print(f"\n\n完了!")
    print(f"生成時間: {duration:.2f}秒")
    print(f"推定速度: {token_count / duration:.2f} tok/sec")
    print("-" * 30)
    print(full_text[:200] + "...")

if __name__ == "__main__":
    # 128Kコンテキストを想定した長文入力テスト
    sample_prompt = "以下のコードのアーキテクチャを分析し、潜在的なメモリリークの可能性を指摘してください。" + "A" * 1000  # 実際にはここに大量のコードを入れる
    generate_technical_doc(sample_prompt)

このスクリプトでは、stream=Trueを使ってリアルタイムでトークンを受け取っています。 MTPが効いている場合、文字が流れる速度が明らかに「人間が読める速さ」を超えているはずです。 実務では、この高速性を活かして大量のドキュメントの要約や、複雑なコードの静的解析をバッチ処理させることができます。

よくあるトラブルと解決法

エラー内容原因解決策
CUDA error: out of memoryKVキャッシュまたは重みがVRAMを超過--n-gpu-layersを少し減らすか、--ctk q4_0を指定
mtp: unknown argumentllama.cppのバージョンが古い最新のソースから再ビルドするか、MTP対応ブランチを使用
生成速度が5 tok/sec以下重みがメインメモリ(RAM)に溢れている量子化ビット数を下げる(Q3_K_M → Q2_K)

次のステップ

この記事の構成で、12GB VRAMでも「仕事で使える」レベルの速度とコンテキスト長を確保できました。 次に挑戦すべきは、この高速推論環境をベースにした「ローカルRAG(検索拡張生成)」の構築です。

Qwen3.6 35B A3Bは日本語能力も高く、128Kの文脈を扱えるため、社内の技術ドキュメントをすべてコンテキストに放り込んで、MTPによる高速レスポンスで対話する「最強の社内AIアシスタント」が個人PCで作れます。 また、DifyやAnythingLLMといったGUIツールと接続する際は、llama-serverのAPIエンドポイントを指定するだけで簡単に連携可能です。 VRAMの限界をソフトウェア(MTP)で突破する快感を、ぜひ自室のPCで体験してください。

よくある質問

Q1: RTX 3060 12GBでも80 tok/sec出ますか?

理論上は可能ですが、メモリ帯域の差でRTX 4070等に比べると若干落ちる可能性があります。それでもMTPなしの状態よりは圧倒的に速くなります。VRAM 12GBを使い切らないよう、コンテキストサイズを調整してください。

Q2: MTPを有効にすると精度は落ちませんか?

MTPはモデルが元々持っている予測能力を利用するため、大幅な精度低下は報告されていません。ただし、--mtpの値を大きくしすぎると生成内容が不安定になることがあるため、実用上は2から試すのが安全です。

Q3: 128Kコンテキストを使うとメモリが足りなくなります。

コンテキストサイズを128Kに設定すると、KVキャッシュだけで数GB消費します。--ctk q4_0--ctk q8_0でキャッシュを量子化し、それでも足りない場合はコンテキストを32K程度に絞って運用してください。


あわせて読みたい