Ollama: Quantização e Otimização de Modelos
Quantização é a dieta do modelo — sacrifique um pouco de precisão, economize metade do espaço, com quase nenhuma perda de qualidade.
📋 Pré-requisitos: Você deve dominar o seguinte primeiro
- Aula 4: Gerenciamento de Modelos
- Aula 9: Configuração de GPU e CUDA
1. O Que Você Vai Aprender
- Princípios de Quantização: compromissos FP16 → Q8_0 → Q4_K_M → Q2_K
- Quantização embutida do Ollama e especificação manual
- Importação de modelos quantizados personalizados de arquivos GGUF
- Métodos de avaliação de qualidade de modelos quantizados
- Decisões de cenário VRAM: qual nível para 4GB/8GB/16GB
2. Uma História Real de Uma Empreendedora SaaS
(1) O Problema: 8GB VRAM Não Consegue Rodar um Modelo 8B
O servidor da Alice tem apenas 8GB VRAM, e o modelo 8B FP16 requer 16GB — não roda. Mas após Quantização Q4_K_M, precisa apenas de 5GB, o que é suficiente. A questão é: quanto qualidade a Quantização sacrifica?
(2) A Solução: Q4_K_M Oferece o Melhor Custo-Benefício
Testes revelaram que Q4_K_M tem menos de 3% de perda de qualidade em cenários de atendimento ao cliente, enquanto reduz o tamanho em 70%:
# Compare model sizes
ollama show llama3.1:8b # Q4_K_M: ~5GB
ollama show llama3.1:8b-q8_0 # Q8_0: ~8GB
3. Princípios de Quantização em Detalhe
(1) De FP16 a Q2_K: Precisão Decrescente
flowchart LR
A[FP16<br/>16-bit<br/>16 GB] --> B[Q8_0<br/>8-bit<br/>8 GB]
B --> C[Q5_K_M<br/>5-bit<br/>5.7 GB]
C --> D[Q4_K_M<br/>4-bit<br/>5 GB]
D --> E[Q3_K_M<br/>3-bit<br/>3.8 GB]
E --> F[Q2_K<br/>2-bit<br/>3 GB]
(2) Comparação de Níveis de Quantização
| Nível de Quantização | Largura de Bits | Taxa de Compressão | Tamanho Modelo 8B | Retenção de Qualidade | VRAM Adequada |
|---|---|---|---|---|---|
| FP16 | 16-bit | 1x | ~16 GB | 100% | 24 GB+ |
| Q8_0 | 8-bit | 2x | ~8 GB | 99%+ | 12 GB+ |
| Q5_K_M | 5-bit | 3.2x | ~5.7 GB | 98% | 8 GB+ |
| Q4_K_M | 4-bit | 3.5x | ~5 GB | 95-97% | 8 GB |
| Q3_K_M | 3-bit | 4.5x | ~3.8 GB | 90-93% | 4 GB+ |
| Q2_K | 2-bit | 6x | ~3 GB | 80-85% | 4 GB |
(3) Convenção de Nomenclatura K-quant
| Sufixo | Significado | Descrição |
|---|---|---|
| _K | K-quant | Quantização de precisão mista, camadas críticas em precisão mais alta |
| _S | Small | Menor tamanho, qualidade mais baixa |
| _M | Medium | Tamanho e qualidade equilibrados (recomendado) |
| _L | Large | Qualidade mais alta, tamanho maior |
_M oferece o melhor custo-benefício — Q4_K_M é 3% mais qualitativo que Q4_K_S, com apenas 5% a mais de tamanho.
▶ Exemplo 1: Seleção de Quantização Padrão do Ollama
# 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)
Saída:
NAME ID SIZE
llama3.2:latest a80... 2.0 GB
mistral:latest 61... 4.1 GB
4. Quantização Embutida do Ollama
(1) Especificando Nível de Quantização no Pull
| Método | Comando | Descrição |
|---|---|---|
| Auto-selecionar | ollama pull model_name |
Ollama escolhe a Quantização ótima |
| Especificar tag | ollama pull model_name:q4_K_M |
Especificar nível de Quantização |
(2) Tags de Quantização Disponíveis
| Tag | Quantização | Caso de Uso |
|---|---|---|
| q4_K_M | Precisão mista 4-bit | Recomendação geral |
| q5_K_M | Precisão mista 5-bit | Qualidade mais alta |
| q8_0 | Uniforme 8-bit | Quase sem perdas |
| f16 | Original 16-bit | Precisão total |
▶ Exemplo 2: Baixando Variantes de Quantização Diferentes
# 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
Saída:
NAME ID SIZE
llama3.2:latest a80... 2.0 GB
mistral:latest 61... 4.1 GB
5. Importando Quantização Personalizada de Arquivos GGUF
(1) Fontes de Arquivos GGUF
| Fonte | URL | Descrição |
|---|---|---|
| HuggingFace | huggingface.co | Pesquisar por .gguf |
| TheBloke | huggingface.co/TheBloke | Coleção de Quantização GGUF |
| Auto-quantizar | llama.cpp convert | Usar convert.py |
(2) Passos de Importação
flowchart LR
A[Download GGUF] --> B[Criar Modelfile<br/>FROM ./model.gguf]
B --> C[ollama create]
C --> D[ollama run]
▶ Exemplo 3: Importar do GGUF do HuggingFace
# 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"
Saída:
I'm a helpful AI assistant running locally on your machine...
6. Avaliação de Qualidade da Quantização
(1) Comparação de Métodos de Avaliação
| Método | Descrição | Caso de Uso |
|---|---|---|
| Comparação subjetiva | Comparar saídas de diferentes Quantizações para a mesma pergunta | Triagem rápida |
| Benchmark | Benchmarks NLP padrão (MMLU/HellaSwag) | Avaliação por nível de Quantização |
| Avaliação de negócio | Teste de precisão específico da tarefa | Decisão final |
(2) Árvore de Decisão VRAM
flowchart TD
A[VRAM Disponível?] --> B{4 GB ou menos?}
B -->|Sim| C[Modelo 3B Q4_K_M<br/>ou 8B Q2_K]
B -->|Não| D{8 GB?}
D -->|Sim| E[8B Q4_K_M ⭐ Recomendado]
D -->|Não| F{12-16 GB?}
F -->|Sim| G[8B Q8_0 ou 13B Q4_K_M]
F -->|Não| H{24 GB?}
H -->|Sim| I[70B Q2_K ou 8B FP16]
H -->|Não| J{48+ GB multi-GPU?}
J -->|Sim| K[70B Q4_K_M ⭐ Melhor qualidade]
▶ Exemplo 4: Script de Comparação de Qualidade de Quantização
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}")
Saída:
# Function defined successfully
▶ Exemplo 5: Recomendação de Quantização por Cenário
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']})")
Saída:
# Function defined successfully
7. Exemplo Abrangente: Avaliação de Quantização e Decisão de Implantação
# ============================================
# 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()}")
❓ Perguntas Frequentes
P: Devo escolher Q4_K_M ou Q4_K_S? R: Prefira Q4_K_M. _M é precisão Medium, 3-5% mais qualitativo que _S (Small), com apenas 5% a mais de tamanho. _M é amplamente reconhecido como o melhor custo-benefício.
P: E se o modelo quantizado ficar "mais burro"? R: Atualize para Q5_K_M ou Q8_0. Se VRAM for insuficiente, um modelo de parâmetros maiores com Quantização baixa (70B Q2_K) pode superar um modelo menor com Quantização alta (8B Q8_0).
P: O Ollama pode quantizar automaticamente? R: Modelos baixados pelo Ollama já são versões pré-quantizadas (geralmente Q4_K_M). Você não pode especificar um nível de Quantização personalizado no pull — deve importar de um arquivo GGUF.
P: Como quantizar um arquivo GGUF eu mesmo? R: Use as ferramentas convert e quantize do llama.cpp. Primeiro converta o modelo para GGUF F16, depois use quantize para especificar o nível. Adequado para usuários avançados; iniciantes devem baixar versões pré-quantizadas.
P: O nível de Quantização afeta a velocidade de Inferência? R: Quantização mais baixa (Q2_K) significa Inferência mais rápida (menos transferência de dados). Mas diferenças de velocidade Q4_K_M e Q8_0 na GPU são tipicamente < 10%. Na CPU, Q4_K_M é visivelmente mais rápido.
P: Modelos de embedding precisam de Quantização? R: Não. Modelos de embedding já são pequenos (nomic-embed-text tem apenas 274MB), e os benefícios de Quantização são negligenciáveis. Mantenha o padrão.
📖 Resumo
- Quantização comprime modelos de FP16 para larguras de bits menores; Q4_K_M reduz o tamanho em 70% com apenas 3-5% de perda de qualidade
- Sufixos K-quant: _M (recomendado) > _L > _S; escolha _M para melhor custo-benefício
- O Ollama padrão usa Q4_K_M; outros níveis podem ser especificados via tags
- Arquivos GGUF podem ser baixados do HuggingFace e importados com Modelfile
- 8GB VRAM → 8B Q4_K_M (recomendado), 24GB → 70B Q4_K_M
- Modelo maior + Quantização mais baixa > modelo menor + Quantização mais alta (na maioria dos cenários)
📝 Exercícios
- Básico (⭐): Baixe duas variantes de Quantização do mesmo modelo (Q4_K_M e Q8_0), use
ollama listpara comparar tamanhos de arquivo, e compare a qualidade da saída com a mesma pergunta. - Intermediário (⭐⭐): Baixe um arquivo GGUF do HuggingFace, importe-o no Ollama com um Modelfile, e teste que a Inferência funciona corretamente.
- Avançado (⭐⭐⭐): Escreva um script de avaliação de Quantização que teste pontuações de qualidade em diferentes níveis de Quantização em um cenário de atendimento ao cliente (5 perguntas padrão), e produza uma tabela de recomendação de Quantização.