Capítulo 3: Treinamento Eficiente em Memória
Otimizando o Treinamento para Hardware Limitado
Este capítulo aborda todas as técnicas para maximizar a eficiência do treinamento com memória de GPU limitada.
Técnicas de Otimização de Memória
1. Gradient Checkpointing
Troque computação por memória ao recomputar ativações:
# Enable via training args
training_args = TrainingArguments(
gradient_checkpointing=True,
...
)
# Or directly on model
model.gradient_checkpointing_enable()
Economia: redução de memória de ~30% Custo: treinamento ~20% mais lento
2. Gradient Accumulation
Simule batches maiores com memória limitada:
training_args = TrainingArguments(
per_device_train_batch_size=1, # Batch pequeno cabe na memória
gradient_accumulation_steps=16, # Acumula gradientes
# Effective batch size = 1 * 16 = 16
)
3. Otimizadores Eficientes
Adam 8 bits
training_args = TrainingArguments(
optim="adamw_8bit", # Requer bitsandbytes
)
Otimizadores Paginados
training_args = TrainingArguments(
optim="paged_adamw_8bit", # Pagina para a CPU quando necessário
)
Script Completo de Treinamento Eficiente em Memória
import torch
from transformers import (
AutoModelForCausalLM,
AutoTokenizer,
BitsAndBytesConfig,
TrainingArguments,
)
from peft import LoraConfig, get_peft_model, prepare_model_for_kbit_training
from trl import SFTTrainer
from datasets import load_dataset
# Quantization
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype=torch.bfloat16,
bnb_4bit_use_double_quant=True,
)
# Load model
model = AutoModelForCausalLM.from_pretrained(
"meta-llama/Llama-3.1-8B",
quantization_config=bnb_config,
device_map="auto",
)
tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-3.1-8B")
tokenizer.pad_token = tokenizer.eos_token
# Prepare for training
model = prepare_model_for_kbit_training(model)
# LoRA config
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)
# Dataset
dataset = load_dataset("databricks/dolly-15k", split="train[:1000]")
# Memory-efficient training args
training_args = TrainingArguments(
output_dir="./qlora-output",
num_train_epochs=1,
per_device_train_batch_size=1,
gradient_accumulation_steps=16,
learning_rate=2e-4,
bf16=True,
gradient_checkpointing=True,
optim="paged_adamw_8bit",
logging_steps=10,
save_strategy="epoch",
)
# Train
trainer = SFTTrainer(
model=model,
train_dataset=dataset,
args=training_args,
dataset_text_field="text",
max_seq_length=512,
tokenizer=tokenizer,
)
trainer.train()
model.save_pretrained("./qlora-adapter")
Checklist de Memória
□ Use QLoRA (quantização em 4 bits)
□ Ative gradient checkpointing
□ Use gradient accumulation
□ Use otimizador 8 bits ou paginado
□ Use precisão bfloat16
□ Reduza o max_seq_length se possível
□ Use batches menores
Uso de Memória Esperado
| Modelo | Sem Otimização | Otimização Completa |
|---|---|---|
| 7B | ~14GB | ~4-6GB |
| 13B | ~26GB | ~8-10GB |
| 70B | ~140GB | ~40-48GB |
Principais Pontos
✅ Combine múltiplas técnicas de otimização
✅ Gradient checkpointing troca computação por memória
✅ Gradient accumulation simula batches maiores
✅ Otimizadores paginados lidam com picos de memória
✅ QLoRA + todas as otimizações permitem 7B em 6GB