Ollama: モデル量子化と最適化
量子化はモデルのダイエット——精度を少し犠牲にして、容量を半分に、品質はほぼ変わらない。
💡 ヒント: 量子化レベル選択ガイド——Q4_K_Mが最もコスパが良い(70%容量削減、5%未満の品質低下)、主流の8GB VRAMシナリオに適する;Q8_0はほぼロスレス(99%以上の品質保持)、VRAMが豊富(12GB以上)で精度に敏感なシナリオ(コード生成、数学的推論)に適する。
📋 前提条件: まず以下を習得していること
- レッスン4: モデル管理
- レッスン9: GPUとCUDA設定
1. 学べること
- 量子化原理:FP16 → Q8_0 → Q4_K_M → Q2_Kのトレードオフ
- Ollama組み込み量子化と手動指定
- GGUFファイルからのカスタム量子化モデルのインポート
- 量子化モデル品質評価方法
- VRAMシナリオの決定:4GB/8GB/16GBでどのレベルを選ぶか
2. SaaS起業家のリアルな事例
ℹ️ 情報: OllamaはデフォルトでQ4_K_M量子化を使用——これは「最もコスパが良い」選択であり、「最高品質」の選択ではない。VRAMが十分(16GB以上)ならQ8_0でほぼロスレス品質を試すことが可能;VRAMが極めて限られている(4GB)場合、Q3_K_MがQ2_Kより良い下限。
(1) ペインポイント:8GB VRAMで8Bモデルが動かない
Aliceのサーバーは8GB VRAMしかなく、8B FP16モデルは16GBを必要とするため実行できない。しかしQ4_K_M量子化後は5GBで済み、十分に動作する。問題は:量子化でどれほど品質が犠牲になるか?
(2) ソリューション:Q4_K_Mが最もコスパが良い
テストの結果、Q4_K_Mはカスタマーサービスシナリオで3%未満の品質低下で、容量を70%削減:
BASH
# Compare model sizes
ollama show llama3.1:8b # Q4_K_M: ~5GB
ollama show llama3.1:8b-q8_0 # Q8_0: ~8GB
3. 量子化原理詳細
⚠️ 注: 量子化は必然的に精度を犠牲にする——Q2_K量子化は最小容量だが品質低下が顕著(80〜85%の保持)、特にコード生成や数学的推論のような精度タスクに影響する。VRAMが極めて限られている(4GB未満)場合のみ推奨;それ以外はQ4_K_Mを優先。
⚠️ 警告: Q2_K量子化は最小容量(8Bモデルでわずか約3GB)だが、品質低下が顕著で、特にコード生成や数学的推論のような精度タスクに影響する。VRAMが極めて限られている(4GB未満)場合のみ推奨;それ以外はQ4_K_Mを優先。
(1) FP16からQ2_Kへ:精度の低下
flowchart LR
A[FP16<br/>16ビット<br/>16 GB] --> B[Q8_0<br/>8ビット<br/>8 GB]
B --> C[Q5_K_M<br/>5ビット<br/>5.7 GB]
C --> D[Q4_K_M<br/>4ビット<br/>5 GB]
D --> E[Q3_K_M<br/>3ビット<br/>3.8 GB]
E --> F[Q2_K<br/>2ビット<br/>3 GB]
(2) 量子化レベル比較
| 量子化レベル | ビット幅 | 圧縮率 | 8Bモデル容量 | 品質保持 | 適するVRAM |
|---|---|---|---|---|---|
| FP16 | 16ビット | 1倍 | 約16 GB | 100% | 24 GB以上 |
| Q8_0 | 8ビット | 2倍 | 約8 GB | 99%以上 | 12 GB以上 |
| Q5_K_M | 5ビット | 3.2倍 | 約5.7 GB | 98% | 8 GB以上 |
| Q4_K_M | 4ビット | 3.5倍 | 約5 GB | 95〜97% | 8 GB |
| Q3_K_M | 3ビット | 4.5倍 | 約3.8 GB | 90〜93% | 4 GB以上 |
| Q2_K | 2ビット | 6倍 | 約3 GB | 80〜85% | 4 GB |
(3) K-quant命名規則
| サフィックス | 意味 | 説明 |
|---|---|---|
| _K | K-quant | 混合精度量子化、重要層は高精度を保持 |
| _S | Small | 最小容量、最低品質 |
| _M | Medium | 容量と品質のバランス(推奨) |
| _L | Large | 高品質、大容量 |
💡 ヒント:
_Mサフィックスの選択が最もコスパが良い——Q4_K_MはQ4_K_Sより3%高品質で、容量は5%増加のみ。
(4) ▶ サンプル:Ollamaデフォルト量子化選択
BASH
# Default pull uses optimal quantization (usually Q4_K_M)
ollama pull llama3.1:8b
# Show quantization details
ollama show llama3.1:8b
# Look for: quantization: Q4_K_M
# Compare sizes across quantizations
ollama list | grep llama
# llama3.1:8b 4.9 GB (Q4_K_M)
出力:
TEXT
NAME ID SIZE
llama3.2:latest a80... 2.0 GB
mistral:latest 61... 4.1 GB
4. Ollama組み込み量子化
(1) プル時の量子化レベル指定
| 方法 | コマンド | 説明 |
|---|---|---|
| 自動選択 | ollama pull model_name |
Ollamaが最適な量子化を選択 |
| タグ指定 | ollama pull model_name:q4_K_M |
量子化レベルを指定 |
(2) 利用可能な量子化タグ
| タグ | 量子化 | ユースケース |
|---|---|---|
| q4_K_M | 4ビット混合精度 | 汎用推奨 |
| q5_K_M | 5ビット混合精度 | 高品質 |
| q8_0 | 8ビット均一 | ほぼロスレス |
| f16 | 16ビット元の精度 | フル精度 |
(3) ▶ サンプル:異なる量子化バリアントのプル
BASH
# Pull specific quantization
ollama pull llama3.1:8b-q4_K_M # 4-bit, ~5GB
ollama pull llama3.1:8b-q5_K_M # 5-bit, ~5.7GB
ollama pull llama3.1:8b-q8_0 # 8-bit, ~8GB
# Not all models have all variants
# Check available tags on ollama.com/library/model-name
出力:
TEXT
NAME ID SIZE
llama3.2:latest a80... 2.0 GB
mistral:latest 61... 4.1 GB
5. GGUFファイルからのカスタム量子化インポート
(1) GGUFファイル入手先
| ソース | URL | 説明 |
|---|---|---|
| HuggingFace | huggingface.co | .ggufを検索 |
| TheBloke | huggingface.co/TheBloke | GGUF量子化コレクション |
| 自前量子化 | llama.cpp convert | convert.pyを使用 |
(2) インポート手順
flowchart LR
A[GGUFダウンロード] --> B[Modelfile作成<br/>FROM ./model.gguf]
B --> C[ollama create]
C --> D[ollama run]
(3) ▶ サンプル:HuggingFace GGUFからのインポート
BASH
# Step 1: Download GGUF file from HuggingFace
wget "https://huggingface.co/TheBloke/Mistral-7B-Instruct-v0.2-GGUF/resolve/main/mistral-7b-instruct-v0.2.Q4_K_M.gguf"
# Step 2: Create Modelfile
cat > Modelfile <<EOF
FROM ./mistral-7b-instruct-v0.2.Q4_K_M.gguf
SYSTEM You are a helpful AI assistant.
PARAMETER temperature 0.7
PARAMETER num_ctx 4096
TEMPLATE """[INST] {{ if .System }}{{ .System }}{{ end }}
{{ .Prompt }} [/INST]
"""
EOF
# Step 3: Create model in Ollama
ollama create my-mistral -f Modelfile
# Step 4: Run
ollama run my-mistral "Explain quantum computing in simple terms"
出力:
TEXT
I'm a helpful AI assistant running locally on your machine...
6. 量子化品質評価
(1) 評価方法比較
| 方法 | 説明 | ユースケース |
|---|---|---|
| 主観的比較 | 同じ質問で異なる量子化の出力を比較 | 簡易スクリーニング |
| ベンチマーク | 標準NLPベンチマーク(MMLU/HellaSwag) | 量子化レベル評価 |
| ビジネス評価 | タスク固有の精度テスト | 最終決定 |
(2) VRAM決定ツリー
flowchart TD
A[利用可能VRAM?] --> B{4 GB以下?}
B -->|はい| C[3Bモデル Q4_K_M<br/>または 8B Q2_K]
B -->|いいえ| D{8 GB?}
D -->|はい| E[8B Q4_K_M ⭐ 推奨]
D -->|いいえ| F{12〜16 GB?}
F -->|はい| G[8B Q8_0 または 13B Q4_K_M]
F -->|いいえ| H{24 GB?}
H -->|はい| I[70B Q2_K または 8B FP16]
H -->|いいえ| J{48 GB以上マルチGPU?}
J -->|はい| K[70B Q4_K_M ⭐ 最高品質]
(3) ▶ サンプル:量子化品質比較スクリプト
PYTHON
import ollama
import time
from statistics import mean
def compare_quantizations(model_base: str, quantizations: list[str],
test_prompt: str, runs: int = 3):
"""Compare output quality and speed across quantizations."""
results = {}
for quant in quantizations:
model_name = f"{model_base}:{quant}" if ":" not in model_base else model_base
try:
# Warm up
ollama.chat(model=model_name,
messages=[{"role": "user", "content": "warm up"}],
stream=False)
speeds = []
responses = []
for _ in range(runs):
start = time.time()
resp = ollama.chat(
model=model_name,
messages=[{"role": "user", "content": test_prompt}],
stream=False
)
elapsed = time.time() - start
speeds.append(len(resp["message"]["content"]) / elapsed)
responses.append(resp["message"]["content"])
results[quant] = {
"avg_speed": round(mean(speeds), 1),
"sample_response": responses[0][:200]
}
except Exception as e:
results[quant] = {"error": str(e)}
return results
# Compare (if you have multiple quantizations pulled)
# results = compare_quantizations(
# "llama3.1", ["q4_K_M", "q8_0"],
# "Explain machine learning in 3 sentences"
# )
# for quant, data in results.items():
# print(f"\n{quant}:")
# for k, v in data.items():
# print(f" {k}: {v}")
出力:
TEXT
# Function defined successfully
(4) ▶ サンプル:シナリオ別量子化推奨
PYTHON
def recommend_quantization(vram_gb: float, use_case: str) -> dict:
"""Recommend optimal quantization based on VRAM and use case."""
recommendations = {
"chat": {
"precision_priority": ("Q8_0", "Best quality, needs more VRAM"),
"balanced": ("Q4_K_M", "Best quality/size ratio"),
"size_priority": ("Q3_K_M", "Smallest usable quantization")
},
"code": {
"precision_priority": ("Q8_0", "Code needs high precision"),
"balanced": ("Q5_K_M", "Good precision for code tasks"),
"size_priority": ("Q4_K_M", "Minimal quality loss for code")
},
"classification": {
"precision_priority": ("Q5_K_M", "Overkill for classification"),
"balanced": ("Q4_K_M", "More than enough"),
"size_priority": ("Q2_K", "Classification is robust to quantization")
}
}
# Determine priority based on VRAM
if vram_gb >= 12:
priority = "precision_priority"
elif vram_gb >= 8:
priority = "balanced"
else:
priority = "size_priority"
quant, reason = recommendations.get(use_case, recommendations["chat"])[priority]
# Model size recommendation
if vram_gb >= 40:
model_size = "70B"
elif vram_gb >= 8:
model_size = "8B"
else:
model_size = "3B"
return {
"vram_gb": vram_gb,
"use_case": use_case,
"priority": priority,
"quantization": quant,
"model_size": model_size,
"reason": reason
}
# Example usage
for vram in [4, 8, 24]:
rec = recommend_quantization(vram, "chat")
print(f"VRAM {vram}GB: {rec['model_size']} {rec['quantization']} ({rec['reason']})")
出力:
TEXT
# Function defined successfully
7. 総合サンプル:量子化評価とデプロイ決定
PYTHON
# ============================================
# Comprehensive: Quantization decision engine
# Evaluates quality, speed, and VRAM tradeoffs
# ============================================
import ollama
import time
import json
from pathlib import Path
class QuantizationAdvisor:
def __init__(self, vram_gb: float, use_case: str = "chat"):
self.vram_gb = vram_gb
self.use_case = use_case
self.results = {}
def estimate_model_fit(self, params_b: float, quant: str) -> dict:
"""Estimate if a model+quantization fits in available VRAM."""
quant_bytes = {
"FP16": 2.0, "Q8_0": 1.0, "Q5_K_M": 0.625,
"Q4_K_M": 0.5, "Q3_K_M": 0.375, "Q2_K": 0.25
}
bytes_per_param = quant_bytes.get(quant, 0.5)
vram_needed = params_b * bytes_per_param * 1.2 # 20% overhead
fits = vram_needed <= self.vram_gb
return {
"params": f"{params_b}B",
"quantization": quant,
"vram_needed_gb": round(vram_needed, 1),
"vram_available_gb": self.vram_gb,
"fits": fits,
"headroom_gb": round(self.vram_gb - vram_needed, 1)
}
def generate_recommendations(self) -> list[dict]:
"""Generate all viable model+quantization combinations."""
models = [
(3.2, "llama3.2"), (8.0, "llama3.1:8b"), (70.0, "llama3.1:70b")
]
quants = ["Q4_K_M", "Q5_K_M", "Q8_0"]
viable = []
for params, name in models:
for quant in quants:
fit = self.estimate_model_fit(params, quant)
if fit["fits"]:
viable.append({
"model": name,
**fit
})
# Sort by params descending (prefer larger model)
viable.sort(key=lambda x: x["params"], reverse=True)
return viable
def best_recommendation(self) -> dict:
"""Return the single best recommendation."""
viable = self.generate_recommendations()
if not viable:
return {"error": "No model fits in available VRAM. Use CPU mode."}
# Prefer largest model, then highest quantization
best = viable[0]
return {
"recommended_model": best["model"],
"recommended_quantization": best["quantization"],
"vram_used": f"{best['vram_needed_gb']}GB",
"headroom": f"{best['headroom_gb']}GB",
"reason": f"Largest model that fits {self.vram_gb}GB VRAM with Q4_K_M+"
}
# Usage
if __name__ == "__main__":
advisor = QuantizationAdvisor(vram_gb=8, use_case="chat")
print("=== Quantization Recommendations (8GB VRAM) ===")
for rec in advisor.generate_recommendations():
print(f" {rec['model']} {rec['quantization']}: "
f"{rec['vram_needed_gb']}GB (headroom: {rec['headroom_gb']}GB)")
print(f"\nBest: {advisor.best_recommendation()}")
❓ よくある質問
Q Q4_K_MとQ4_K_Sはどちらを選ぶ?
A Q4_K_Mを優先。_MはMedium精度で、_S(Small)より3〜5%高品質で、容量は5%増加のみ。_Mは最もコスパが良いと広く認識されている。
Q 量子化モデルが「バカになった」場合は?
A Q5_K_MまたはQ8_0にアップグレード。VRAMが不足する場合、パラメータ数の多い低量子化モデル(70B Q2_K)が、パラメータ数の少ない高量子化モデル(8B Q8_0)より性能が良いことがある。
Q Ollamaは自動的に量子化できる?
A Ollamaがプルするモデルはすでに事前量子化版(通常Q4_K_M)。プル時にカスタム量子化レベルは指定できない——GGUFファイルからインポートする必要がある。
Q GGUFファイルを自分で量子化するには?
A llama.cppのconvertとquantizeツールを使用。まずモデルをGGUF F16に変換し、quantizeでレベルを指定。上級者向け;初心者は事前量子化版をダウンロードすべき。
Q 量子化レベルは推論速度に影響する?
A 低量子化(Q2_K)ほど推論が高速(データ転送量が少ない)。しかしGPU上でのQ4_K_MとQ8_0の速度差は通常10%未満。CPU上ではQ4_K_Mが明らかに高速。
Q 埋め込みモデルは量子化が必要?
A 不要。埋め込みモデルはすでに小さい(nomic-embed-textは274MBのみ)で、量子化の効果は微少。デフォルトのまま使用。
📖 まとめ
- 量子化はモデルをFP16から低ビット幅に圧縮;Q4_K_Mは容量を70%削減し、品質低下は3〜5%のみ
- K-quantサフィックス:_M(推奨)> _L > _S;最もコスパが良いのは_M
- OllamaはデフォルトでQ4_K_M;他のレベルはタグで指定可能
- GGUFファイルはHuggingFaceからダウンロードし、Modelfileでインポート可能
- 8GB VRAM → 8B Q4_K_M(推奨)、24GB → 70B Q4_K_M
- 大きいモデル+低量子化 > 小さいモデル+高量子化(ほとんどのシナリオで)
📝 練習問題
- 基本(難易度 ⭐):同じモデルの2つの量子化バリアント(Q4_K_MとQ8_0)をプルし、
ollama listでファイルサイズを比較し、同じ質問で出力品質を比較する。 - 中級(難易度 ⭐⭐):HuggingFaceからGGUFファイルをダウンロードし、ModelfileでOllamaにインポートし、推論が正しく動作することをテストする。
- 上級(難易度 ⭐⭐⭐):量子化評価スクリプトを作成し、カスタマーサービスシナリオで異なる量子化レベルの品質スコアをテスト(5つの標準質問)、量子化推奨表を出力する。