この記事では、検証した2つのスタックでLLMの性能を比較します。1つはExLlamaV3とTabbyAPIを通じて提供するEXL3量子化モデル、もう1つはllama.cppを通じて提供するGGUFモデルです。これはファイルコンテナだけを切り離して比較するテストではありません。このベンチマークのEXL3テンソルはsafetensorsファイルに格納されており、一方のGGUFは複数の量子化方式に対応するコンテナです。
要点
今回のEXL3とGGUFのベンチマークでは、EXL3は量子化したモデル重みのデータ量が同じ場合に品質が高く、RTX 5090でのプロンプト処理も大幅に高速でした。一方、GGUFは読み込みとデコードが速く、対応ハードウェアの範囲も広いという結果でした。
- EXL3 4.00 bpwは、量子化した重みのサイズが小さくてもBF16モデルに近い結果でした。EXL3は5.79 GiBで平均KLDが0.0248だったのに対し、GGUF Q4_K_Mは6.62 GiBで0.0398でした。
- EXL3 4.00 bpwは、高精度の埋め込みを含めると7.79 GiBでした。これはGGUF Q5_K_Mのファイルサイズ7.84 GiBとほぼ同じですが、KLDはGGUF Q5_K_Mのほうが低く、0.0172でした。
- ExLlamaV3は2,048トークンのプロンプトを最大2.5倍の速度で処理しました。一方、ファイルサイズを揃えた2組では、llama.cppのデコードが15-21%高速でした。
- GGUFは幅広い環境に導入しやすい形式です。llama.cppはCPUと複数のGPUバックエンドを利用でき、CPU/GPUの混在実行にも対応しているためです。今回検証したEXL3の実行構成では、CUDA上でExLlamaV3とTabbyAPIを使用しました。
- このテストでは、EXL3の現行のmul1コードブックは、従来のMCGビルドと比べてKLDが低く、デコードのスループットも向上しました。プリフィルの結果は同程度でした。
EXL3量子化とは
EXL3量子化は、低ビットレートでも多くの情報を保持するためにトレリス符号化量子化と非コヒーレンス処理を使うQTIPの考え方に基づいた低ビット量子化方式です。ExLlamaエコシステムの一部であり、品質の低下を比較的小さく抑えながら、モデルの重みを一般的な4ビット未満に圧縮するよう設計されています。EXL3は、すべての重みを同じ固定ビット幅に揃えるのではなく、より柔軟にビットを配分できるため、少ないVRAMにモデルを収めやすくなります。GGUFと比べ、EXL3はExLlamaのGPU推論スタックと新しい量子化技術を中心に最適化されています。
EXL3とEXL2・GGUFの違い
EXL2は、混合精度の重み量子化を中心に設計された、従来のExLlama量子化形式です。ExLlamaV2を通じてNVIDIA GPUで高速に推論する用途に特化して最適化されています。
ExLlamaV3とともに導入されたEXL3では、基盤となる手法が大きく変わりました。EXL2を単に改良したものではなく、手続き的コードブックとトレリスベースのベクトル量子化を使う、QTIPを簡素化した派生方式です。EXL3は、非常に低いビットレートでもモデルの品質をよりよく保持することを目指しており、量子化ツールでは重みあたり2.0、3.0、4.0ビットなどの平均ビットレートを目標に設定できます。また、EXL3はEXL2よりも元のHugging Faceテンソル構造を多く保持するため、ほかのランタイムとの統合が容易になると考えられます。
GGUFは主にllama.cppで使われるモデルファイル形式で、重み、モデルのメタデータ、トークナイザー情報、関連データを格納します。GGUFは、Q4_K、Q5_K、新しい重要度重み付き方式やi-quantの派生方式など、多くの量子化方式に対応しています。GGUFモデルはllama.cppを通じて、CPU、NVIDIA/AMD/AppleのGPU、CPU+GPUの異種混在構成で実行できます。対照的に、EXL3はGPUをより強く重視し、ExLlamaV3ランタイムを中心に緊密に最適化されています。
BPWがモデルサイズとVRAMに与える影響
BPWは「bits per weight」、つまり重みあたりのビット数を意味します。量子化後のモデルの各パラメータを保存するために、平均で何ビットを使うかを示します。FP16で保存したモデルは約16 BPWですが、量子化したモデルでは8、4、3、さらには約2 BPWを使う場合もあります。BPWが低いほどモデルファイルは小さくなり、VRAM使用量も減りますが、通常は品質低下のリスクも高くなります。
例として、今回のテストで使用したEXL3 4.00 bpwのGemma 4モデルを見てみましょう。量子化したレイヤーと出力ヘッドのサイズは5.79 GiBでしたが、モデルファイル全体は7.79 GiBで、その差は2.00 GiBでした。
EXL3とGGUFのベンチマーク
では、EXL3とGGUFの量子化レシピを実際に比較すると、どうなるのでしょうか。この疑問に答えるため、google/gemma-4-12B-itのベンチマークを実施しました。EXL3ファイルはturboderp/gemma-4-12B-it-exl3から、GGUFファイルはunsloth/gemma-4-12b-it-GGUFから取得しました。
各形式に専用のランタイムが必要だったため、速度の結果はコンテナ単体ではなく、EXL3 + ExLlamaV3/TabbyAPIとGGUF + llama.cppのスタックを比較したものです。
| 構成要素 | ベンチマーク環境 |
|---|---|
| プラットフォーム | RunPodコミュニティクラウド、$0.69/時間 |
| GPU | NVIDIA GeForce RTX 5090、32,607 MiB |
| ホスト | 192 vCPU、377 GB RAM |
| OS | Ubuntu 24.04.3 |
| ドライバー | NVIDIA 570.195.03 |
| CUDA | 12.8ツールキット |
| PyTorch | 2.8.0+cu128 |
| EXL3ランタイム | ExLlamaV3 1.4.9、TabbyAPIのコミットde76ff88 |
| GGUFランタイム | llama.cppのコミット8172e6577、品質評価用のロジット取得にllama-cpp-python 0.3.35を使用 |
速度テストでは、バッチサイズ1、16kのFP16キャッシュを使用しました。投機的デコード、複数トークンデコード、プレフィックスキャッシュはいずれも無効にしました。
各構成について、入力2,048トークンと8,192トークン、出力512トークンの条件で、1回のウォームアップ後に5回の測定を行いました。中央値とプリフィルの範囲を掲載します。
品質テストの比較条件を揃えた方法
品質は、BF16の参照モデルと両方の量子化バックエンドに対して、共通のqbench.py評価ハーネスで測定しました。各バックエンドには同じトークンIDを入力し、すべての量子化モデルを、同じBF16実行からキャッシュしたロジットと比較しました。これにより、EXL3のパープレキシティをあるハーネスで測定し、GGUFのパープレキシティを別のハーネスで測定するという、形式間の比較テストでよくある問題を避けています。
モデルサイズが近い場合の品質
カルバック・ライブラー情報量、略してKLDは、各量子化モデルのトークン分布がBF16からどれだけ離れたかを測る指標です。低いほど良い結果です。パープレキシティ、略してPPLも低いほど良い指標ですが、今回はすべての行を同じ参照ロジットと比較しているため、KLDのほうが直接的な指標になります。
| 構成 | レイヤーのBPW | 重み | ファイル | PPL | 平均KLD |
|---|---|---|---|---|---|
| BF16参照モデル | 16.000 | 22.18 GiB | 22.20 GiB | 1.2598 | - |
| EXL3 3.00 bpw | 3.006 | 4.52 GiB | 6.52 GiB | 1.3874 | 0.09399 |
| EXL3 4.00 bpw | 4.006 | 5.79 GiB | 7.79 GiB | 1.2908 | 0.02479 |
| EXL3 4.00 bpw MCG | 4.006 | 5.79 GiB | 7.79 GiB | 1.2910 | 0.02667 |
| EXL3 5.00 bpw | 5.006 | 7.06 GiB | 9.06 GiB | 1.2665 | 0.00946 |
| GGUF IQ4_XS | 4.250 | 5.92 GiB | 5.94 GiB | 1.3266 | 0.05435 |
| GGUF Q4_K_M | 4.798 | 6.62 GiB | 6.63 GiB | 1.3064 | 0.03985 |
| GGUF UD-Q4_K_XL | 4.885 | 6.84 GiB | 6.86 GiB | 1.3021 | 0.03605 |
| GGUF Q5_K_M | 5.653 | 7.82 GiB | 7.84 GiB | 1.2769 | 0.01719 |
| GGUF Q6_K | 6.562 | 9.10 GiB | 9.11 GiB | 1.2657 | 0.00918 |
EXL3の重みには高精度の埋め込みを含めていません。保存容量全体を比較する場合は「ファイル」列を参照してください。
ファイル全体のサイズが近い場合、結果は一様にどちらかの形式が優れるものではなく、構成によって異なりました。
比較対象の量子化した重みだけを見ると、EXL3 4.00 bpwは5.79 GiBでKLDが0.02479、GGUF Q4_K_Mは6.62 GiBで0.03985でした。この比較には、EXL3の高精度の埋め込みを含めていません。ファイル全体のサイズでは、EXL3 4.00 bpwは7.79 GiBで、GGUF Q5_K_Mの7.84 GiBとほぼ同じでした。BF16に対するKLDはQ5_K_Mのほうが低く、EXL3の0.02479に対して0.01719でした。
約9.1 GiBでは、EXL3 5.00 bpwとGGUF Q6_KのKLDはそれぞれ0.00946と0.00918で、実質的に同等でした。
プロンプト処理と生成速度
プロンプト処理は、モデルが回答を始める前に、既存の入力やコンテキストをどれだけ速く読み取って処理するかをtok/sで測るもので、この段階をプリフィルと呼びます。生成速度は、その後にモデルが新しい出力トークンを生成する速さで、こちらもtok/sで測定します。
入力2,048トークン、出力512トークン:
| 構成 | プリフィル中央値 | プリフィル最小値・最大値 | TTFT | デコード中央値 |
|---|---|---|---|---|
| EXL3 3.00 bpw | 4,471 tok/s | 4,443-4,556 tok/s | 0.46秒 | 119.2 tok/s |
| EXL3 4.00 bpw | 4,077 tok/s | 3,638-4,413 tok/s | 0.50秒 | 113.1 tok/s |
| EXL3 4.00 bpw MCG | 4,198 tok/s | 3,694-4,235 tok/s | 0.49秒 | 103.5 tok/s |
| EXL3 5.00 bpw | 3,845 tok/s | 3,733-4,326 tok/s | 0.53秒 | 98.8 tok/s |
| GGUF IQ4_XS | 1,772 tok/s | 1,748-1,813 tok/s | 1.16秒 | 154.6 tok/s |
| GGUF Q4_K_M | 1,762 tok/s | 1,683-1,795 tok/s | 1.16秒 | 139.4 tok/s |
| GGUF UD-Q4_K_XL | 1,752 tok/s | 1,725-1,786 tok/s | 1.17秒 | 137.5 tok/s |
| GGUF Q5_K_M | 1,795 tok/s | 1,758-1,802 tok/s | 1.14秒 | 130.1 tok/s |
| GGUF Q6_K | 1,736 tok/s | 1,722-1,806 tok/s | 1.18秒 | 117.4 tok/s |
入力8,192トークン、出力512トークン:
| 構成 | プリフィル中央値 | プリフィル最小値・最大値 | TTFT | デコード中央値 |
|---|---|---|---|---|
| EXL3 3.00 bpw | 5,238 tok/s | 5,137-5,263 tok/s | 1.56秒 | 114.0 tok/s |
| EXL3 4.00 bpw | 5,199 tok/s | 5,155-5,215 tok/s | 1.58秒 | 108.4 tok/s |
| EXL3 4.00 bpw MCG | 5,184 tok/s | 5,090-5,211 tok/s | 1.58秒 | 99.3 tok/s |
| EXL3 5.00 bpw | 5,175 tok/s | 5,138-5,209 tok/s | 1.58秒 | 95.3 tok/s |
| GGUF IQ4_XS | 4,206 tok/s | 4,200-4,293 tok/s | 1.95秒 | 151.0 tok/s |
| GGUF Q4_K_M | 4,097 tok/s | 4,082-4,207 tok/s | 2.00秒 | 136.4 tok/s |
| GGUF UD-Q4_K_XL | 4,061 tok/s | 4,014-4,180 tok/s | 2.02秒 | 134.4 tok/s |
| GGUF Q5_K_M | 4,106 tok/s | 4,061-4,154 tok/s | 2.00秒 | 127.2 tok/s |
| GGUF Q6_K | 3,728 tok/s | 3,683-3,768 tok/s | 2.20秒 | 115.1 tok/s |
ファイル全体のサイズを揃えた2組では、EXL3のプリフィル速度は2kでそれぞれ2.27倍と2.21倍、8kでそれぞれ1.27倍と1.39倍でした。8kでは、EXL3 4.00 bpwはQ5_K_Mより0.42秒速く最初のトークンを出力し、EXL3 5.00 bpwはQ6_Kより0.62秒速く出力しました。
ファイルサイズを揃えた両方の組で、llama.cppがデコード速度で上回りました。Q5_K_Mは毎秒130.1トークンに達したのに対し、EXL3 4.00 bpwは113.1で、Q6_Kは117.4に達したのに対し、EXL3 5.00 bpwは98.8でした。入力8kでもQ6_Kの優位性は同様で、毎秒115.1トークンに対して95.3でした。プリフィルの速さとデコードの遅さは、リクエスト全体では相殺されることがあります。入力2kの場合、速度の中央値から計算すると、512トークンの出力にEXL3 4.00 bpwは約5.0秒、Q5_K_Mは約5.1秒かかります。
ハードウェアやサーバー構成が異なると結果に影響する可能性があるため、これらの結果は参考として捉えてください。
VRAM使用量とコンテキスト長
| 構成 | ファイル | 読み込み時間 | 読み込み後のVRAM | ピーク時のVRAM |
|---|---|---|---|---|
| EXL3 3.00 bpw | 6.52 GiB | 8秒 | 7.37 GiB | 8.24 GiB |
| EXL3 4.00 bpw | 7.79 GiB | 9秒 | 8.71 GiB | 9.60 GiB |
| EXL3 4.00 bpw MCG | 7.79 GiB | 8秒 | 8.71 GiB | 9.59 GiB |
| EXL3 5.00 bpw | 9.06 GiB | 8秒 | 9.89 GiB | 10.76 GiB |
| GGUF IQ4_XS | 5.94 GiB | 4秒 | 7.34 GiB | 7.84 GiB |
| GGUF Q4_K_M | 6.63 GiB | 4秒 | 8.04 GiB | 8.54 GiB |
| GGUF UD-Q4_K_XL | 6.86 GiB | 4秒 | 8.27 GiB | 8.76 GiB |
| GGUF Q5_K_M | 7.84 GiB | 6秒 | 9.24 GiB | 9.74 GiB |
| GGUF Q6_K | 9.11 GiB | 6秒 | 10.52 GiB | 11.02 GiB |
GGUFモデルの読み込みは4秒から6秒で完了したのに対し、EXL3モデルは8秒から9秒かかりました。最小の構成同士では、ファイルサイズが異なるにもかかわらず、VRAM使用量はほぼ同じになりました。読み込み後の使用量は、EXL3 3.00 bpwが7.37 GiB、IQ4_XSが7.34 GiBでした。
ファイルサイズがほぼ同じ7.8 GiBの構成では、EXL3 4.00 bpwのVRAM使用量はQ5_K_Mより少なくなりました。読み込み後の使用量はEXL3が8.71 GiB、Q5_K_Mが9.24 GiBで、その差は0.53 GiBでした。ピーク使用量の差はさらに小さく、EXL3が9.60 GiB、Q5_K_Mが9.74 GiBでした。
ファイルサイズが9.1 GiB前後でも同じ傾向が見られます。EXL3 5.00 bpwは読み込み後に9.89 GiBを使用し、ピーク時は10.76 GiBでした。一方、Q6_Kは10.52 GiBを使用し、ピーク時は11.02 GiBでした。つまり、EXL3は読み込み後のVRAM使用量で0.63 GiB、ピーク使用量で0.26 GiB少なく済みます。
ExLlamaV3でEXL3モデルを実行する方法
このセクションでは、Linux上でEXL3モデルを実行するために使用した、検証済みのTabbyAPIセットアップを説明します。
検証環境
この構成は、以下の環境で検証しました。
- Linux
- Python 3.12
- NVIDIA GPU
- CUDA 12.8
- PyTorch 2.8.0
- ExLlamaV3 1.4.9
インストール前にExLlamaV3のリリースを確認し、インストール済みのPython、CUDA、PyTorch、OS、CPUアーキテクチャに合うwheelを選んでください。
ExLlamaV3とTabbyAPIをインストールする
転送機能を有効にしてhuggingface_hubをインストールし、対応するExLlamaV3のwheelをインストールしてから、TabbyAPIをクローンしてインストールします。
venvに対応したPython 3.12が必要です。Ubuntuでは、python3.12-venvが未インストールならインストールしてから、以下の環境を作成して有効にしてください。残りのインストールコマンドは、その環境内で実行します。
python3.12 -m venv .venv
source .venv/bin/activate
pip install 'huggingface_hub[hf_transfer]'
pip install torch==2.8.0 --index-url https://download.pytorch.org/whl/cu128
pip install https://github.com/turboderp-org/exllamav3/releases/download/v1.4.9/exllamav3-1.4.9+cu128.torch2.8.0-cp312-cp312-linux_x86_64.whl
git clone https://github.com/theroyallab/tabbyAPI
cd tabbyAPI
git checkout de76ff88
pip install -e .上記のwheelは、Python 3.12、CUDA 12.8、PyTorch 2.8.0、Linux、x86-64専用です。ローカル環境が異なる場合は、別のwheelを使用してください。
EXL3モデルをダウンロードする
Hugging Faceから必要なEXL3ブランチをダウンロードします。このリポジトリでは、ブランチ名が量子化のビットレートとレシピを示しています。
以下の例では、4.00bpw_mul1のバリアントをダウンロードします。
hf download turboderp/gemma-4-12B-it-exl3 \
--revision 4.00bpw_mul1 \
--local-dir models/exl3/4.00bpw_mul1TabbyAPIを設定する
クローンしたtabbyAPIリポジトリのルートにconfig.ymlを作成します。以下の設定では、シーケンス長16,384トークンとFP16キャッシュを使用します。
network:
host: 127.0.0.1
port: 5000
disable_auth: false
model:
model_dir: /absolute/path/to/models/exl3
model_name: 4.00bpw_mul1
max_seq_len: 16384
cache_size: 16384
cache_mode: FP16model_dirには、ダウンロードしたEXL3モデルのディレクトリ群を格納している場所の絶対パスを設定してください。model_nameは、読み込むモデルが入っているディレクトリと一致させる必要があります。
TabbyAPIを起動する
TabbyAPIのリポジトリディレクトリから実行します。
python main.py --config config.ymlデフォルトでは、上記の設定により、以下のアドレスでAPIにアクセスできます。
http://127.0.0.1:5000APIをテストする
初回起動時に、TabbyAPIはリポジトリディレクトリ内にapi_tokens.ymlを作成します。api_keyの値をコピーし、OpenAI互換のチャット補完エンドポイントにリクエストを送信します。
curl http://127.0.0.1:5000/v1/chat/completions \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-d '{
"messages": [
{
"role": "user",
"content": "Explain bits per weight in two sentences."
}
],
"max_tokens": 120,
"temperature": 0
}'リクエストが成功すると、生成されたアシスタントのメッセージを含むJSONレスポンスが返るはずです。
セキュリティとバージョン管理
TabbyAPIをループバックインターフェース(127.0.0.1)にバインドしている場合でも、disable_auth: falseを維持してください。同じコンピューター上で開いているWebページからも、ローカルAPIにアクセスできるためです。リクエストには生成されたAPIキーを使用し、インスタンスをネットワークに直接公開しないでください。
TabbyAPIはローリングリリース方式のプロジェクトとして開発されています。再現可能なデプロイのために、動作確認済みの依存関係のバージョンを固定し、既存の環境に更新を適用する前に検証してください。
EXL3はGPUメモリより大きなモデルを実行できますか?
はい。ただし、限られた場合にのみ可能です。ExLlamaV3 1.4.9には、対応するMixture-of-Experts(MoE)モデル向けの実験的なCPUオフロード機能が含まれています。互換性のあるモデルを使用する場合、選択したブロックスパースMoEレイヤー内のルーティング対象エキスパートを、VRAMではなくシステムRAMに配置できます。これにより、そのエキスパートの重みに必要なGPUメモリを削減できます。
現在のCPUオフロードのドキュメントが対象としているのは、対応するMoEレイヤーのみです。利用できるのは、K ≤ 8と互換性のあるエキスパートのバイアスを備えたmul1エキスパートに限られます。
ただし、このレイヤーのオフロードを使って、llama.cppと同じようにあらゆるデンスモデルをシステムRAMとVRAMに分割できるわけではありません。今回のデンスモデルGemma 4 12Bのベンチマークでは、モデル全体をGPU上に配置したままでした。VRAMに全体が収まらないデンスモデルを実行する場合は、GGUFをllama.cppで実行する構成のほうが適しています。
どちらの形式を選ぶべきか
モデル全体がGPUに収まり、VRAMが主な制約となる場合、特に長いプロンプトを繰り返し処理するワークロードでは、EXL3が適しています。ファイル全体のサイズを揃えた2組では、EXL3はピーク時のVRAM使用量がわずかに少なく、プロンプト処理が速く、最初のトークンが出るまでの時間も短くなりました。ファイルサイズが近い場合の品質は、一様に優れているわけではなく、構成によって結果が異なりました。
CPU推論やCPU/GPUを混在させるオフロードには、GGUFが適しています。対応アプリも幅広く、今回のllama.cppテストでは生成速度も高速でした。GGUFは1つのファイルとして配布しやすく、量子化レシピによって品質とメモリ使用量のバランスを細かく調整できます。
GGUFモデルは、私たちが開発したオフラインAIアプリAtomic Chatで実行できます。オフラインAIモデルを簡単にダウンロードして実行したり、エージェント型ワークフローを設定したり、内蔵インターフェースでモデルと直接チャットしたりできます。
よくある質問
EXL3は常にGGUFより優れていますか?
いいえ。今回のGemma 4 12Bのテストでは、EXL3は量子化した重みの1バイトあたりでモデルの品質をよりよく保持し、プロンプト処理も高速でしたが、GGUFはトークンのデコードが速く、はるかに幅広いハードウェアとアプリケーションに対応しています。それぞれの形式に長所と短所があります。
GGUFモデルをEXL3に変換できますか?
技術的には、すでに量子化された重みを使った変換ワークフローを構築できますが、高品質なEXL3量子化を行うための変換元としてGGUFファイルを使うべきではありません。EXL3量子化は、元のHugging Faceモデルの重みから始めることを想定しています。GGUFファイルがすでに量子化されている場合、再量子化しても元の重みは復元できず、誤差が増える可能性があります。
EXL3に対応しているアプリは?
主な選択肢は、ExLlamaV3自体、TabbyAPI、およびExLlamaV3互換バックエンドを統合したアプリケーションです。ExLlamaV3はEXL3形式の参照実装です。EXL3モデルを直接読み込めるほか、Transformersとの統合機能も提供しています。モデルの互換性は、現行のExLlamaV3リリースがそのアーキテクチャに対応しているかどうかによって決まります。TabbyAPIは、ExLlamaV3の公式かつ推奨のAPIサーバーです。OpenAI互換APIを提供し、ExLlamaV3バックエンドを通じてEXL3モデルに対応しています。

