Capítulo 2: Quantização 4-bit com bitsandbytes
Entendendo e Implementando Quantização Eficiente
A biblioteca bitsandbytes permite quantização em 4-bit e 8-bit para carregamento e treinamento eficiente de modelos.
Fundamentos da Quantização
O que é Quantização?
Converter valores de alta precisão para precisão mais baixa:
Float16: 2 bytes por parâmetro
Int8: 1 byte por parâmetro
Int4: 0,5 bytes por parâmetro
Economia de Memória
# Memória do modelo 7B
fp32 = 7e9 * 4 / 1e9 # 28 GB
fp16 = 7e9 * 2 / 1e9 # 14 GB
int8 = 7e9 * 1 / 1e9 # 7 GB
int4 = 7e9 * 0.5 / 1e9 # 3,5 GB
BitsAndBytesConfig
Configuração Completa
from transformers import BitsAndBytesConfig
import torch
bnb_config = BitsAndBytesConfig(
# Usar quantização 4-bit
load_in_4bit=True,
# Tipo de quantização NF4 (recomendado)
bnb_4bit_quant_type="nf4",
# Computar em bfloat16 para maior estabilidade
bnb_4bit_compute_dtype=torch.bfloat16,
# Quantização dupla para economia extra
bnb_4bit_use_double_quant=True,
)
Explicação dos Parâmetros
| Parâmetro | Opções | Recomendação |
|---|---|---|
load_in_4bit | True/False | True para QLoRA |
bnb_4bit_quant_type | "nf4", "fp4" | "nf4" (melhor qualidade) |
bnb_4bit_compute_dtype | torch.bfloat16, torch.float16 | bfloat16 (mais estável) |
bnb_4bit_use_double_quant | True/False | True (mais economia) |
NF4 vs FP4
NF4 (NormalFloat4)
- Projetado para pesos com distribuição normal
- Valores iguais em cada intervalo de quantização
- Melhor qualidade para redes neurais
FP4 (Float4)
- Quantização uniforme
- Mais simples, porém menos ideal para pesos
# NF4 recomendado
bnb_4bit_quant_type="nf4"
Carregando um Modelo Quantizado
from transformers import AutoModelForCausalLM, AutoTokenizer
model = AutoModelForCausalLM.from_pretrained(
"meta-llama/Llama-3.1-8B",
quantization_config=bnb_config,
device_map="auto",
torch_dtype=torch.bfloat16,
)
tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-3.1-8B")
# Verificar memória
print(f"Memória: {torch.cuda.memory_allocated() / 1e9:.2f} GB")
Preparando para o Treinamento
from peft import prepare_model_for_kbit_training
# Etapas necessárias de preparação:
# 1. Ativar gradient checkpointing
# 2. Converter layer norms para float32
# 3. Habilitar gradientes de entrada
model = prepare_model_for_kbit_training(model)
O que o prepare_model_for_kbit_training Faz
- Ativa gradient checkpointing para eficiência de memória
- Converte layer norms para float32 para maior estabilidade
- Define requires_grad de forma apropriada
- Gerencia embeddings para gradientes de entrada
Configuração Completa do QLoRA
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
from peft import LoraConfig, get_peft_model, prepare_model_for_kbit_training
# 1. Configuração de quantização
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype=torch.bfloat16,
bnb_4bit_use_double_quant=True,
)
# 2. Carregar modelo quantizado
model = AutoModelForCausalLM.from_pretrained(
"meta-llama/Llama-3.1-8B",
quantization_config=bnb_config,
device_map="auto",
)
# 3. Preparar para treinamento
model = prepare_model_for_kbit_training(model)
# 4. Adicionar LoRA
lora_config = LoraConfig(
r=16,
lora_alpha=32,
target_modules=["q_proj", "k_proj", "v_proj", "o_proj"],
lora_dropout=0.05,
task_type="CAUSAL_LM",
)
model = get_peft_model(model, lora_config)
model.print_trainable_parameters()
Principais Pontos
✅ bitsandbytes permite quantização 4-bit/8-bit
✅ NF4 é ideal para pesos de redes neurais
✅ Quantização dupla adiciona ~11% de economia extra
✅ Use prepare_model_for_kbit_training antes de adicionar LoRA
✅ O dtype de computação deve ser bfloat16 para maior estabilidade
Continue para o Capítulo 3: Treinamento Eficiente em Memória →