Chapitre 3 : Entraînement efficace en mémoire
Optimiser l'entraînement pour un matériel limité
Ce chapitre couvre toutes les techniques pour maximiser l'efficacité de l'entraînement avec une mémoire GPU limitée.
Techniques d'optimisation de la mémoire
1. Checkpointing de gradient
Échanger le calcul contre la mémoire en recomputant les activations :
# Activer via les arguments d'entraînement
training_args = TrainingArguments(
gradient_checkpointing=True,
...
)
# Ou directement sur le modèle
model.gradient_checkpointing_enable()
Économies : réduction de mémoire d'environ 30 % Coût : entraînement environ 20 % plus lent
2. Accumulation de gradient
Simuler des lots plus grands avec une mémoire limitée :
training_args = TrainingArguments(
per_device_train_batch_size=1, # Petit lot qui tient en mémoire
gradient_accumulation_steps=16, # Accumuler les gradients
# Taille de lot effective = 1 * 16 = 16
)
3. Optimiseurs efficaces
Adam 8 bits
training_args = TrainingArguments(
optim="adamw_8bit", # Nécessite bitsandbytes
)
Optimiseurs paginés
training_args = TrainingArguments(
optim="paged_adamw_8bit", # Page vers le CPU si nécessaire
)
Script complet d'entraînement efficace en mémoire
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
# Quantification
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype=torch.bfloat16,
bnb_4bit_use_double_quant=True,
)
# Charger le modèle
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
# Préparer pour l'entraînement
model = prepare_model_for_kbit_training(model)
# Config 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)
# Jeu de données
dataset = load_dataset("databricks/dolly-15k", split="train[:1000]")
# Arguments d'entraînement efficace en mémoire
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",
)
# Entraîner
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")
Liste de vérification de la mémoire
□ Utiliser QLoRA (quantification 4 bits)
□ Activer le checkpointing de gradient
□ Utiliser l'accumulation de gradient
□ Utiliser un optimiseur 8 bits ou paginé
□ Utiliser la précision bfloat16
□ Réduire max_seq_length si possible
□ Utiliser des tailles de lot plus petites
Utilisation mémoire attendue
| Modèle | Sans optimisation | Optimisation complète |
|---|---|---|
| 7B | ~14GB | ~4-6GB |
| 13B | ~26GB | ~8-10GB |
| 70B | ~140GB | ~40-48GB |
Points clés à retenir
✅ Combiner plusieurs techniques d'optimisation ✅ Le checkpointing de gradient échange le calcul contre la mémoire ✅ L'accumulation de gradient simule des lots plus grands ✅ Les optimiseurs paginés gèrent les pics de mémoire ✅ QLoRA + toutes les optimisations permettent 7B sur 6GB