Um modelo Llama 3 de 8 mil milhões de parâmetros em formato original (FP16) ocupa cerca de 16 GB de memória. A maioria dos portáteis vendidos em Portugal em 2026 não chega lá perto em VRAM dedicada. É aqui que entra a quantização: a técnica que pega num modelo grande, reduz a precisão numérica dos seus pesos e o faz caber numa GPU de 8 GB sem destruir a qualidade das respostas. Neste tutorial mostramos, passo a passo, como usar o Hugging Face Transformers, o bitsandbytes, o AutoAWQ e o llama.cpp para quantizar um modelo open source, medir a perda de qualidade real e publicar o resultado. No final, vai ter uma API de chat local a correr num modelo quantizado, com números de VRAM e velocidade antes e depois.

O Que é Quantização de Modelos IA e Porque Importa em 2026

Quantização é o processo de representar os pesos de uma rede neuronal com menos bits. Em vez de guardar cada peso em 16 ou 32 bits (o formato de treino padrão), um modelo quantizado guarda-os em 8, 5 ou até 4 bits. O resultado é um ficheiro muito mais pequeno e um consumo de memória muito menor durante a inferência, ao custo de uma pequena perda de precisão numérica.

Estudos de comparação publicados em 2026 mostram que um modelo quantizado em Q8_0 (formato GGUF quase sem perdas) mantém entre 99,5% e 99,96% da qualidade do modelo original em FP16, com uma poupança de memória de cerca de 1,9 vezes. Descer para Q4_K_M aumenta a poupança para cerca de 3,3 vezes, com uma queda de qualidade que ronda 1,5% a 1,9% em testes de perplexidade. Para a maioria das aplicações de produção, essa troca compensa largamente: significa a diferença entre precisar de uma GPU de 80 GB na cloud ou de uma placa de 12 GB em cima da secretária.

Há três razões práticas para dominar esta técnica em 2026. Primeiro, o custo: alugar uma GPU de topo por hora continua caro, e quantizar um modelo pode eliminar essa despesa por completo ao permitir correr tudo localmente. Segundo, a privacidade: para empresas portuguesas sujeitas ao RGPD, correr um modelo quantizado no próprio servidor evita enviar dados de clientes para uma API externa. Terceiro, a disponibilidade: o Hugging Face Hub já tem centenas de modelos publicados em GGUF, com múltiplos níveis de quantização, prontos a usar com llama.cpp, Ollama ou LM Studio.

Este guia não repete o que já mostrámos sobre fine-tuning de modelos com Hugging Face nem sobre o treino eficiente com Unsloth e LoRA. O foco aqui é diferente: pegar num modelo já treinado (o seu ou um pré-treinado) e comprimi-lo para correr rápido e barato em inferência, sem tocar no processo de treino.

Pré-Requisitos: Hardware, Software e Versões

Antes de avançar, confirme que tem o seguinte:

  • Sistema operativo Linux (Ubuntu 22.04 ou mais recente) ou WSL2 no Windows. macOS funciona para GGUF via Metal, mas AutoAWQ exige CUDA.
  • Python 3.10 ou superior instalado, com pip atualizado.
  • GPU NVIDIA com pelo menos 8 GB de VRAM para os exemplos com bitsandbytes e AutoAWQ (uma RTX 3060 de 12 GB ou superior é suficiente). Sem GPU, ainda pode seguir a parte de conversão GGUF, que corre em CPU.
  • Pelo menos 30 GB de espaço livre em disco (os modelos originais em FP16 e as várias versões quantizadas ocupam espaço em simultâneo durante o processo).
  • Git e um compilador C++ (build-essential no Ubuntu) para compilar o llama.cpp a partir do código-fonte.
  • Uma conta gratuita no Hugging Face, com um token de acesso gerado em huggingface.co/settings/tokens, caso queira publicar o modelo quantizado no Hub.

Vamos instalar as bibliotecas transformers, accelerate, bitsandbytes e autoawq via pip, e compilar o llama.cpp diretamente do repositório oficial, já que as suas ferramentas de quantização evoluem semana a semana. Não fixamos aqui um número de versão exato para o llama.cpp ou para o AutoAWQ: confirme sempre a tag mais recente no repositório antes de instalar, porque estas ferramentas lançam atualizações com frequência elevada. A documentação oficial do bitsandbytes mantém uma matriz de compatibilidade entre versões de CUDA, PyTorch e sistema operativo que vale a pena consultar antes de instalar, sobretudo se estiver a usar uma GPU mais recente cujo suporte ainda não esteja completamente estável em todas as distribuições Linux.

Também vale a pena decidir já, antes de instalar qualquer coisa, quanto do disco vai reservar para o processo. Uma regra prática que usamos nas nossas próprias quantizações: multiplique o tamanho do modelo original em GB por três. Um modelo de 7B ocupa cerca de 14 GB em FP16; durante o processo vai ter, ao mesmo tempo, o modelo original transferido do Hugging Face, a versão intermédia em GGUF F16 e pelo menos uma versão quantizada final, o que facilmente ultrapassa 40 GB para um modelo desta escala. Para modelos de 13B ou 34B, o cálculo sobe proporcionalmente, e vale a pena apagar os ficheiros intermédios assim que a quantização final estiver validada.

GGUF vs AWQ vs GPTQ: as Diferenças que Importam

Existem três famílias de quantização dominantes em 2026, e escolher a errada significa perder tempo a converter um modelo para o formato que não serve o seu caso de uso. O GGUF (usado por llama.cpp, Ollama e LM Studio) foi desenhado para correr bem tanto em CPU como em GPU, o que o torna a escolha mais popular para quem quer portabilidade entre um portátil sem placa dedicada e um servidor com GPU. O AWQ (Activation-aware Weight Quantization) e o GPTQ (Post-Training Quantization) foram otimizados para correr o mais rápido possível numa GPU, através de motores como o vLLM ou o ExLlama, mas exigem sempre uma placa NVIDIA compatível com CUDA.

Um teste comparativo publicado em 2026 com um modelo da classe 13B, a correr em GPU com aceleração CUDA, mediu os seguintes números: GPTQ 4-bit com o motor Marlin atingiu cerca de 4.930 tokens por segundo com uma pontuação MMLU de 68,8; AWQ 4-bit com o motor GEMM chegou a 4.720 tokens por segundo com MMLU de 68,9; já o GGUF em Q4_K_M via llama.cpp com CUDA ficou nos 1.640 tokens por segundo, mas com uma pontuação MMLU muito próxima, de 68,7. Ou seja: para débito máximo numa GPU dedicada, AWQ e GPTQ ganham com folga. Para flexibilidade entre hardware diferente, o GGUF continua a ser a opção mais prática.

FormatoMelhor paraThroughput típico (13B, GPU)Perplexidade (menor é melhor)Compatibilidade CPU
GGUF (Q4_K_M)Portabilidade CPU + GPU, llama.cpp, Ollama, LM Studio~1.640 tok/s6,43Sim
AWQ (4-bit)Débito máximo em GPU, vLLM~4.720 tok/s6,38Não
GPTQ (4-bit, Marlin)Débito máximo em GPU, ExLlama~4.930 tok/s6,41Não
EXL2 (4,0 bpw)Velocidade e qualidade combinadas em GPU~55 tok/s (classe 7B)5,80Não

Vale a pena perceber de onde vêm estas técnicas antes de as usar às cegas. O método por detrás do AWQ está descrito no artigo científico original “AWQ: Activation-aware Weight Quantization”, que demonstra como proteger apenas 1% dos pesos mais importantes (identificados através da magnitude das ativações, não dos próprios pesos) reduz drasticamente a perda de qualidade face a uma quantização uniforme. O GPTQ segue uma lógica diferente, descrita no artigo “GPTQ: Accurate Post-Training Quantization for Generative Pre-trained Transformers”, que resolve a quantização camada a camada como um problema de otimização, minimizando o erro introduzido em cada camada antes de avançar para a seguinte. Perceber esta diferença ajuda a explicar porque o AWQ tende a proteger melhor os pesos “importantes” em modelos com distribuições de ativação muito assimétricas, enquanto o GPTQ costuma generalizar bem em praticamente qualquer arquitetura.

Neste tutorial vamos cobrir os três caminhos mais usados na prática: quantização rápida com bitsandbytes diretamente dentro do Transformers, conversão para GGUF com llama.cpp, e quantização AWQ com AutoAWQ. Assim pode escolher o formato certo consoante o hardware onde o modelo vai correr.

Passo 1 e 2: Preparar o Ambiente Python

Comece por criar um ambiente virtual isolado. Misturar versões de torch, transformers e bitsandbytes com outros projetos é a causa mais comum de erros estranhos neste tipo de trabalho, por isso vale a pena isolar tudo desde o início.

python3 -m venv quant-env
source quant-env/bin/activate

pip install --upgrade pip
pip install torch --index-url https://download.pytorch.org/whl/cu121
pip install transformers accelerate bitsandbytes sentencepiece huggingface_hub

Depois de instalar, confirme que o PyTorch reconhece a GPU antes de avançar. Se este comando devolver False, resolva os drivers CUDA antes de continuar, porque nada do que vem a seguir vai funcionar sem isso.

python3 -c "import torch; print(torch.cuda.is_available()); print(torch.cuda.get_device_name(0))"

Saída esperada num sistema com GPU configurada corretamente:

True
NVIDIA GeForce RTX 4070

Passo 3 e 4: Escolher o Modelo e Quantizar com bitsandbytes

Para este tutorial vamos usar um modelo aberto de tamanho médio, de forma a que os exemplos corram em hardware de consumo. Pode substituir por qualquer modelo compatível com Transformers publicado no Hugging Face Hub, incluindo variantes da família Llama, Qwen ou Mistral.

Antes de escolher o modelo, faça as contas ao contrário: parta da VRAM que tem disponível e trabalhe de trás para a frente. Uma regra prática usada por muitas equipas em 2026 é dividir a VRAM disponível (em GB) por 0,6 para estimar o número máximo de mil milhões de parâmetros que consegue correr confortavelmente em Q4_K_M, deixando margem para o contexto e a KV-cache. Numa GPU de 12 GB, isso aponta para modelos até cerca de 20B de parâmetros em Q4_K_M, ou até 13B com alguma folga extra para conversas longas. Se o objetivo for treino ou ajuste fino em vez de apenas inferência, os requisitos de memória sobem de forma acentuada, e vale a pena rever o nosso guia sobre fine-tuning com Hugging Face antes de decidir o tamanho do modelo base.

A forma mais rápida de reduzir o consumo de memória é carregar o modelo diretamente em 4-bit ou 8-bit através do BitsAndBytesConfig do Transformers. Isto não gera um ficheiro quantizado independente, mas permite correr e testar o modelo imediatamente com uma fração da VRAM.

from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
import torch

model_id = "mistralai/Mistral-7B-Instruct-v0.3"

bnb_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_quant_type="nf4",
    bnb_4bit_compute_dtype=torch.bfloat16,
    bnb_4bit_use_double_quant=True,
)

tokenizer = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForCausalLM.from_pretrained(
    model_id,
    quantization_config=bnb_config,
    device_map="auto",
)

print(f"Memória GPU alocada: {torch.cuda.memory_allocated() / 1e9:.2f} GB")

Num modelo de 7 mil milhões de parâmetros, esta configuração reduz o consumo de VRAM de cerca de 14 GB (FP16) para pouco mais de 5 GB em 4-bit com dupla quantização ativada. O parâmetro bnb_4bit_use_double_quant=True aplica uma segunda quantização às próprias constantes de quantização, poupando ainda mais memória sem impacto percetível na qualidade.

Passo 5 e 6: Converter Para GGUF com llama.cpp

O bitsandbytes é ótimo para testar rapidamente, mas não produz um ficheiro portável que corra fora do Python. Para isso, o caminho padrão em 2026 é converter o modelo para GGUF através do llama.cpp, o mesmo formato usado pelo Ollama e pelo LM Studio. Já mostrámos como correr modelos GGUF prontos a usar no nosso tutorial de llama.cpp com o Llama 4; aqui o objetivo é criar esse ficheiro do zero, a partir de um modelo Transformers.

git clone https://github.com/ggml-org/llama.cpp
cd llama.cpp
cmake -B build -DGGML_CUDA=ON
cmake --build build --config Release -j$(nproc)

pip install -r requirements.txt

python3 convert_hf_to_gguf.py /caminho/para/modelo-original \
  --outfile modelo-f16.gguf \
  --outtype f16

./build/bin/llama-quantize modelo-f16.gguf modelo-q4_k_m.gguf q4_k_m

O primeiro passo (convert_hf_to_gguf.py) transforma os pesos do formato Transformers para GGUF em precisão total (F16), sem qualquer perda. O segundo passo (llama-quantize) é onde acontece a compressão real, reduzindo o ficheiro para o nível escolhido, neste caso Q4_K_M. Para casos onde precisa de controlo mais fino sobre quais as camadas a quantizar com mais ou menos agressividade, o próprio llama-quantize aceita parâmetros dedicados:

./build/bin/llama-quantize \
  --imatrix imatrix.gguf \
  --output-tensor-type q5_k \
  --token-embedding-type q3_k \
  --keep-split \
  modelo-f16.gguf \
  modelo-q4_k_m.gguf q4_k_m

Aqui, --output-tensor-type q5_k mantém os pesos principais numa precisão ligeiramente superior, enquanto --token-embedding-type q3_k aplica quantização mais agressiva à camada de embeddings, que costuma tolerar melhor a perda de precisão. O ficheiro imatrix.gguf é uma matriz de importância calculada previamente a partir de um conjunto de calibração, que ajuda o quantizador a decidir onde a precisão importa mais.

Saída típica do comando de quantização:

llama_model_quantize: version 1
llama_model_quantize: quantizing 'modelo-f16.gguf' to 'modelo-q4_k_m.gguf' as Q4_K_M
[ 1/291] output.weight - [ 4096, 32000, 1, 1], type = f16, converting to q6_K
[ 2/291] token_embd.weight - [ 4096, 32000, 1, 1], type = f16, converting to q4_K
...
llama_model_quantize: model size = 14483.50 MB
llama_model_quantize: quant size = 4108.22 MB

Um modelo que ocupava 14,4 GB em F16 ficou reduzido a 4,1 GB em Q4_K_M, uma redução de cerca de 3,5 vezes, alinhada com os números publicados em comparações de 2026 para modelos desta classe.

Como Escolher o Nível de Quantização Certo (Q4_K_M, Q5_K_M, Q8_0)

O GGUF oferece dezenas de combinações possíveis, mas na prática só precisa de decorar três: Q4_K_M para hardware limitado, Q5_K_M como meio-termo, e Q8_0 quando a qualidade importa mais do que o tamanho. Os formatos legados (Q4_0, Q4_1, Q5_0, Q5_1) ainda funcionam, mas os formatos da série K oferecem melhor qualidade para o mesmo espaço em disco, por isso deixaram de fazer sentido em projetos novos.

NívelTamanho aprox. (modelo 7B)Aumento de perplexidade vs FP16Recomendado para
Q4_K_M~3,8 GB~1,9%GPUs de 8-12 GB ou inferência em CPU
Q5_K_M~4,45 GB~1,0%GPUs de 16 GB, equilíbrio qualidade/tamanho
Q6_K~5,5 GB<0,5%Quando sobra alguma VRAM e quer margem extra
Q8_0~6,7-7,7 GB<0,5%GPUs de 24 GB+, qualidade quase idêntica ao FP16

Em modelos maiores, a mesma lógica escala de forma previsível. Testes de 2026 com a família Llama 3 mostram que a versão de 70B em Q8_0 mantém uma perplexidade de 3,42 (praticamente igual ao FP16), enquanto a mesma versão em Q4_K_M sobe para 3,47, uma diferença de apenas 1,5%, mas com uma poupança de memória de cerca de 3,3 vezes. Na prática, isto significa que um modelo de 70B que exigiria mais de 140 GB em FP16 pode correr com menos de 45 GB em Q4_K_M, tornando-o viável numa única GPU de gama alta em vez de um cluster de GPUs.

Quanto Modelo Cabe em Cada GPU de Consumo

Para tornar isto mais concreto, pense nas placas gráficas mais comuns em setups de programadores em Portugal. Uma RTX 4060 com 8 GB de VRAM aguenta confortavelmente um modelo de 7B em Q4_K_M, com espaço de sobra para um contexto de alguns milhares de tokens. Uma RTX 4070 Ti ou 4080 com 12-16 GB já permite subir para modelos de 13B em Q5_K_M, ou 7B em Q8_0 com bastante margem para a KV-cache. No topo de gama, uma RTX 4090 com 24 GB abre a porta a modelos de 30B a 34B em Q4_K_M, ou a 13B praticamente sem perdas em Q8_0. Estes números são estimativas de referência: o consumo real varia consoante o comprimento do contexto ativo e se a KV-cache também está quantizada, por isso vale sempre a pena confirmar com nvidia-smi durante um teste real antes de assumir que um modelo cabe.

Passo 7: Quantização AWQ com AutoAWQ Para GPU

Se o destino final do modelo é um servidor com GPU dedicada a servir pedidos via vLLM, o AWQ costuma ser a escolha mais rápida em inferência. O AutoAWQ automatiza todo o processo de calibração e quantização.

pip install autoawq

python3 - <<'EOF'
from awq import AutoAWQForCausalLM
from transformers import AutoTokenizer

model_path = "mistralai/Mistral-7B-Instruct-v0.3"
quant_path = "mistral-7b-awq"

quant_config = {
    "zero_point": True,
    "q_group_size": 128,
    "w_bit": 4,
    "version": "GEMM",
}

model = AutoAWQForCausalLM.from_pretrained(model_path)
tokenizer = AutoTokenizer.from_pretrained(model_path)

model.quantize(tokenizer, quant_config=quant_config)
model.save_quantized(quant_path)
tokenizer.save_pretrained(quant_path)
print("Modelo AWQ guardado em", quant_path)
EOF

O parâmetro q_group_size controla quantos pesos partilham a mesma constante de escala: valores mais baixos (64 ou 32) melhoram a qualidade mas aumentam ligeiramente o tamanho do ficheiro final. O valor 128 é o compromisso mais usado em modelos entre 7B e 70B. O processo de calibração corre sobre um pequeno conjunto de texto representativo, escolhido automaticamente pela biblioteca, e demora entre alguns minutos e cerca de uma hora, consoante o tamanho do modelo e a GPU disponível.

Em benchmarks de 2026 com modelos de 7B, o AWQ em 4-bit atingiu uma perplexidade de 5,82 contra 5,91 do GPTQ equivalente, com um débito próximo de 52 tokens por segundo numa GPU de gama alta. Na prática, isto coloca o AWQ ligeiramente à frente do GPTQ tanto em qualidade como em velocidade para a maioria dos modelos testados, embora a diferença seja pequena o suficiente para não justificar sozinha a escolha de um sobre o outro.

Passo 8: Quantizar a KV-Cache Para Poupar Ainda Mais Memória

Quantizar os pesos do modelo é apenas metade da equação. Durante a inferência, o modelo também mantém uma cache de chave-valor (KV-cache) que cresce com o comprimento da conversa, e que em contextos longos pode consumir tanta memória quanto os próprios pesos. Desde 2025-2026, o llama.cpp e o Ollama suportam nativamente a quantização desta cache, sem necessidade de forks ou patches externos.

# No llama.cpp: quantizar a KV-cache para Q8_0 (recomendado, quase sem perdas)
./build/bin/llama-server -m modelo-q4_k_m.gguf -ctk q8_0 -ctv q8_0 -fa

# No Ollama: ativar via variáveis de ambiente antes de iniciar o serviço
export OLLAMA_KV_CACHE_TYPE=q8_0
export OLLAMA_FLASH_ATTENTION=1
ollama serve

Com -ctk q8_0 -ctv q8_0, a memória usada pela cache cai para cerca de metade, com um aumento de perplexidade insignificante, na ordem de 0,002 a 0,05. Descer para Q4_0 em ambas reduz a cache para um quarto do tamanho original, mas já com um custo de qualidade mais visível, de cerca de 7,6%. Para chatbots com conversas longas ou vários utilizadores em simultâneo, ativar Q8_0 na KV-cache costuma ser a otimização mais barata que existe: quase não perde qualidade e liberta memória suficiente para servir o dobro de pedidos em paralelo.

Passo 9 e 10: Medir a Qualidade e Publicar no Hugging Face Hub

Antes de confiar num modelo quantizado em produção, meça a perda de qualidade em vez de assumir os números publicados noutros benchmarks, já que o impacto varia consoante o modelo base e o domínio dos dados. O llama.cpp inclui uma ferramenta dedicada para calcular a perplexidade sobre um conjunto de teste:

./build/bin/llama-perplexity -m modelo-q4_k_m.gguf -f wikitext-2-raw/wiki.test.raw

# Saída esperada (exemplo):
# [1]4.5230,[2]5.1102,[3]5.3390...
# Final estimate: PPL = 5.8821 +/- 0.03214

Corra o mesmo comando sobre a versão F16 original e compare os dois valores de PPL (perplexidade). Uma diferença abaixo de 2% costuma ser impercetível em uso real; acima de 5%, vale a pena subir um nível de quantização ou rever o processo de calibração.

Depois de validar a qualidade, publicar o modelo no Hugging Face Hub torna-o acessível a qualquer pessoa via huggingface_hub, seguindo o mesmo formato usado por milhares de repositórios GGUF já disponíveis publicamente:

huggingface-cli login

python3 - <<'EOF'
from huggingface_hub import HfApi

api = HfApi()
api.create_repo(repo_id="seu-utilizador/mistral-7b-gguf-q4km", exist_ok=True)
api.upload_file(
    path_or_fileobj="modelo-q4_k_m.gguf",
    path_in_repo="modelo-q4_k_m.gguf",
    repo_id="seu-utilizador/mistral-7b-gguf-q4km",
)
print("Publicado com sucesso.")
EOF

Consulte a documentação oficial do Hugging Face sobre GGUF para conhecer as convenções de nomenclatura recomendadas (incluir o nível de quantização no nome do ficheiro, por exemplo) que facilitam a descoberta do modelo por outros utilizadores.

Projeto Completo: API de Chat Local com o Modelo Quantizado

Com o modelo quantizado pronto, o passo final é colocá-lo a servir pedidos através de uma API simples. Este exemplo usa FastAPI e o binding Python do llama.cpp para expor um endpoint de chat, um projeto pequeno mas completo que pode servir de base para uma aplicação real.

pip install fastapi uvicorn llama-cpp-python
# app.py
from fastapi import FastAPI
from pydantic import BaseModel
from llama_cpp import Llama

app = FastAPI(title="API de Chat Quantizada")

llm = Llama(
    model_path="modelo-q4_k_m.gguf",
    n_ctx=4096,
    n_gpu_layers=-1,
    verbose=False,
)

class Pergunta(BaseModel):
    mensagem: str
    max_tokens: int = 256

@app.post("/chat")
def chat(pergunta: Pergunta):
    resposta = llm.create_chat_completion(
        messages=[{"role": "user", "content": pergunta.mensagem}],
        max_tokens=pergunta.max_tokens,
    )
    return {"resposta": resposta["choices"][0]["message"]["content"]}

@app.get("/saude")
def saude():
    return {"estado": "operacional", "modelo": "modelo-q4_k_m.gguf"}
uvicorn app:app --host 0.0.0.0 --port 8000

# Testar com curl:
curl -X POST http://localhost:8000/chat \
  -H "Content-Type: application/json" \
  -d '{"mensagem": "Explica quantização de modelos em duas frases."}'

O parâmetro n_gpu_layers=-1 tenta colocar todas as camadas do modelo na GPU; se a placa não tiver VRAM suficiente, reduza o valor para um número fixo de camadas e o resto corre em CPU. Com esta configuração e um modelo Q4_K_M de 7B, é razoável esperar entre 30 e 60 tokens por segundo numa GPU de 12 GB, dependendo do comprimento do contexto e da carga do sistema.

Eis um resumo do impacto real da quantização, comparando o mesmo modelo antes e depois do processo completo:

MétricaModelo original (FP16)Após quantização (Q4_K_M)
Tamanho em disco~14,4 GB~4,1 GB
VRAM necessária (inferência)~16 GB~5-6 GB
Hardware mínimo viávelGPU 24 GB dedicadaGPU de consumo 8-12 GB
Perplexidade (menor é melhor)Referência (baseline)+1,9% face à referência

Erros Comuns e Armadilhas ao Quantizar Modelos

Estes são os erros que mais vemos repetidamente em projetos de quantização, e que custam horas de depuração desnecessária:

  • Quantizar sem medir a perplexidade antes e depois. Assumir que "Q4_K_M está sempre bem" leva a surpresas em modelos sensíveis, sobretudo em domínios técnicos ou multilingues onde a perda de precisão afeta mais o vocabulário raro.
  • Misturar formatos incompatíveis com o motor de inferência. Um ficheiro AWQ não corre em llama.cpp, e um GGUF não carrega em vLLM sem uma camada de compatibilidade adicional. Confirme sempre qual o formato que o seu motor de servir espera antes de quantizar.
  • Ignorar a memória da KV-cache em conversas longas. Um modelo quantizado que cabe confortavelmente em 6 GB pode ficar sem memória a meio de uma conversa longa se a cache não for também controlada.
  • Usar um conjunto de calibração pouco representativo no AWQ ou GPTQ. Se o texto de calibração for todo em inglês genérico mas a aplicação final é em português técnico, a qualidade em produção pode ficar bastante abaixo do esperado nos benchmarks públicos.
  • Quantizar demasiado agressivamente modelos já pequenos. Modelos abaixo de 3B de parâmetros perdem qualidade de forma mais acentuada em 4-bit do que modelos maiores, porque têm menos redundância nos pesos para absorver o erro de arredondamento.
  • Esquecer de atualizar o tokenizer junto com o modelo quantizado. Publicar apenas o ficheiro de pesos sem o tokenizer correspondente é uma das causas mais comuns de respostas corrompidas quando outra pessoa tenta usar o modelo.

Resolução de Problemas: 8 Situações Frequentes

1. Erro "CUDA out of memory" durante a quantização com bitsandbytes. Reduza o max_memory por dispositivo ou force device_map="cpu" apenas para o processo de quantização, movendo o modelo para GPU só depois de carregado.

2. O comando convert_hf_to_gguf.py falha com "unsupported architecture". A arquitetura do modelo ainda não tem suporte no llama.cpp. Verifique a lista de arquiteturas suportadas no repositório e confirme se existe uma atualização mais recente que já a inclua.

3. O modelo quantizado gera texto repetitivo ou incoerente. Normalmente indica um nível de quantização demasiado agressivo para aquele modelo específico. Suba de Q4_K_M para Q5_K_M ou Q6_K e repita o teste de perplexidade.

4. AutoAWQ trava ou fica pendurado durante a calibração. Confirme que a versão do torch instalada corresponde à versão de CUDA da GPU. Incompatibilidades aqui são a causa mais frequente de bloqueios silenciosos sem mensagem de erro clara.

5. A conversão GGUF demora horas ou parece parada. Modelos grandes em CPU sem otimizações podem realmente demorar bastante na fase de conversão F16. Confirme que está a usar uma máquina com RAM suficiente (pelo menos o dobro do tamanho do modelo original) para evitar troca de memória para disco.

6. llama-server arranca mas responde muito devagar. Verifique se n_gpu_layers está mesmo a colocar camadas na GPU com nvidia-smi durante a inferência. Um valor mal configurado pode fazer o modelo correr inteiramente em CPU sem qualquer aviso.

7. O upload para o Hugging Face Hub falha a meio com timeout. Ficheiros GGUF acima de 5 GB beneficiam do upload em modo multipart automático da biblioteca; confirme que está a usar uma versão recente de huggingface_hub e uma ligação estável, já que uploads grandes são sensíveis a quebras de rede.

8. Resultados diferentes entre a versão Transformers e a versão GGUF do mesmo modelo. Pequenas diferenças na implementação do template de chat entre bibliotecas podem alterar o resultado. Confirme que o template de prompt usado no GGUF corresponde exatamente ao usado no treino original do modelo.

Dicas Avançadas e o Que Isto Significa Para Portugal

Depois de dominar o fluxo básico, há técnicas que fazem diferença em produção. A quantização por camada mista, usada no exemplo com --output-tensor-type e --token-embedding-type, permite poupar ainda mais espaço ao aplicar quantização mais agressiva apenas onde o impacto na qualidade é menor. Combinar isto com uma matriz de importância (imatrix) calculada sobre dados no idioma-alvo, em vez de usar apenas o conjunto de calibração padrão em inglês, costuma melhorar visivelmente a qualidade de modelos quantizados para português.

Vale também a pena testar a quantização de camadas de forma seletiva: manter as primeiras e últimas camadas do modelo em precisão mais alta (Q6_K ou Q8_0) enquanto se aplica Q4_K às camadas intermédias, já que as camadas nas extremidades tendem a ser mais sensíveis a erros de arredondamento.

Outra técnica útil é monitorizar o uso real de VRAM durante a inferência, em vez de confiar apenas nas estimativas teóricas do tamanho do ficheiro. Corra nvidia-smi --query-gpu=memory.used --format=csv -l 1 numa janela de terminal separada enquanto envia pedidos à API, e observe o pico de consumo com diferentes comprimentos de contexto. É comum descobrir que o modelo em si consome menos do que o esperado, mas que a KV-cache em conversas de vários milhares de tokens acaba por dominar o consumo total, especialmente quando várias conversas correm em paralelo no mesmo servidor.

Se planeia distribuir o modelo quantizado publicamente, vale a pena estudar como repositórios de referência no Hugging Face Hub, como os mantidos pelo utilizador TheBloke, organizam as suas publicações: normalmente incluem várias versões GGUF do mesmo modelo (Q4_K_M, Q5_K_M, Q8_0) no mesmo repositório, com uma tabela no README a explicar o tamanho e o caso de uso recomendado para cada uma. Seguir essa convenção facilita a vida de quem descarrega o seu modelo e não sabe à partida qual o nível de quantização mais adequado ao próprio hardware.

Para equipas em Portugal, a quantização resolve um problema muito concreto: correr modelos de IA com dados de clientes sem os enviar para fora da organização, um requisito cada vez mais relevante à luz do RGPD. Um modelo de 32B ou 70B quantizado em Q4_K_M ou AWQ deixa de exigir um cluster de GPUs de datacenter e passa a caber numa única placa de gama alta, o que reduz tanto o investimento inicial em hardware como o consumo elétrico associado, um fator que pesa cada vez mais nos custos operacionais de infraestrutura local.

Perguntas Frequentes

Quantização reduz sempre a qualidade do modelo?

Sim, tecnicamente reduz sempre alguma precisão numérica, mas o impacto varia muito consoante o nível escolhido. Em Q8_0, a perda fica normalmente abaixo de 0,5% em testes de perplexidade, o que é impercetível na maioria das aplicações. Só em níveis mais agressivos como Q3_K ou Q2_K a diferença se torna claramente visível nas respostas.

Qual é melhor: GGUF, AWQ ou GPTQ?

Depende do hardware de destino. Para correr em CPU, portáteis sem GPU dedicada, ou ferramentas como Ollama e LM Studio, GGUF é a única opção prática. Para servir muitos pedidos em simultâneo numa GPU dedicada através de vLLM ou ExLlama, AWQ ou GPTQ oferecem melhor débito.

Preciso de uma GPU para quantizar um modelo?

Para converter para GGUF e aplicar quantização K-series com llama.cpp, não é obrigatório, o processo corre em CPU, embora demore mais tempo em modelos grandes. Para AWQ e GPTQ, uma GPU compatível com CUDA é necessária durante a fase de calibração.

Posso quantizar qualquer modelo do Hugging Face?

Na prática, apenas modelos cuja arquitetura já tenha suporte explícito nas ferramentas de conversão. As famílias mais populares (Llama, Mistral, Qwen, Gemma) costumam ter suporte rápido assim que são lançadas; arquiteturas muito recentes ou pouco comuns podem exigir esperar por uma atualização do llama.cpp ou do AutoAWQ.

Qual a diferença entre quantizar os pesos e quantizar a KV-cache?

Quantizar os pesos reduz o tamanho fixo do modelo em disco e na memória. Quantizar a KV-cache reduz a memória que cresce durante a conversa, à medida que o contexto aumenta. São otimizações independentes e complementares: pode e deve aplicar as duas ao mesmo tempo.

Modelos quantizados servem para fazer fine-tuning depois?

Sim, através de técnicas como QLoRA, que combinam um modelo base quantizado em 4-bit com adaptadores LoRA treináveis em precisão mais alta. Já explorámos esse fluxo especificamente no nosso guia sobre fine-tuning com Unsloth e QLoRA, que é o passo seguinte natural depois de dominar a quantização para inferência.

Quanto tempo demora a quantizar um modelo de 7B?

A conversão para GGUF F16 costuma demorar entre 5 e 15 minutos numa máquina moderna. A quantização final para Q4_K_M ou Q5_K_M é rápida, geralmente sob 5 minutos. A calibração AWQ ou GPTQ costuma demorar mais, entre 20 minutos e uma hora, consoante a GPU disponível e o tamanho do conjunto de calibração.

Um modelo quantizado consome menos eletricidade?

Sim, de forma indireta mas real. Um modelo quantizado exige menos memória ativa e menos GPUs em simultâneo para o mesmo trabalho, o que reduz o consumo elétrico total do servidor. Substituir um setup com duas ou três GPUs de datacenter por uma única placa de consumo a correr o mesmo modelo em Q4_K_M ou AWQ não só baixa o investimento inicial em hardware, como reduz a fatura de eletricidade associada a manter várias placas ligadas e refrigeradas ao longo do tempo, algo que pesa cada vez mais nos custos operacionais de quem gere infraestrutura de IA localmente em Portugal.