Inteligencia artificial / Material de consulta
Adaptación de un transformer
Transformers + PEFT · CPU
Consulte las explicaciones, el código y las salidas de referencia en esta página.
Volver al aula →Especialización · LoRA en un transformer diminuto
Overtone Education · Curso de inteligencia artificial
Objetivo
Ejecutar adaptación LoRA real con PyTorch, Transformers y PEFT en CPU. Se crea un GPT-2 diminuto con pesos aleatorios y tokens numéricos sintéticos. No descarga pesos preentrenados ni demuestra calidad de lenguaje. Su propósito es comprobar parámetros congelados, actualizaciones de bajo rango y backpropagation.
Preparación
Ejecute de arriba abajo en Jupyter con Python 3.12 (entorno validado). Entorno externo al aula. Instale en un entorno virtual:
python -m pip install numpy torch transformers peft ipykernelLas versiones comprobadas se distribuyen en requirements-ia.txt. No necesita claves de API. Los ejemplos son educativos y no validan aplicaciones de impacto alto.
Pasos
1. Construir un modelo pequeño
Dos capas, dos cabezas y vocabulario de 32 tokens permiten observar la mecánica sin GPU. Para adaptar un modelo preentrenado real necesitará verificar licencia, memoria, datos y configuración de su arquitectura.
Código de referencia
import math
import torch
import transformers
import peft
from transformers import GPT2Config, GPT2LMHeadModel
from peft import LoraConfig, get_peft_model
torch.manual_seed(7)
torch.set_num_threads(2)
config = GPT2Config(vocab_size=32,n_positions=32,n_embd=32,n_layer=2,n_head=2,bos_token_id=1,eos_token_id=2,pad_token_id=0,resid_pdrop=0,embd_pdrop=0,attn_pdrop=0)
base = GPT2LMHeadModel(config)
print({"torch":torch.__version__,"transformers":transformers.__version__,"peft":peft.__version__})Salida comprobada
{'torch': '2.14.1', 'transformers': '5.20.2', 'peft': '0.21.2'}
2. Añadir adaptadores
c_attn es específico de GPT-2. Sus proyecciones usan una convención que requiere fan_in_fan_out=True. No copie nombres de módulos a otra arquitectura sin inspeccionarla.
Código de referencia
lora = LoraConfig(r=4,lora_alpha=8,lora_dropout=0,target_modules=["c_attn"],fan_in_fan_out=True,task_type="CAUSAL_LM")
modelo = get_peft_model(base,lora)
total = sum(p.numel() for p in modelo.parameters())
entrenables = sum(p.numel() for p in modelo.parameters() if p.requires_grad)
print({"parametros_totales":total,"entrenables":entrenables,"fraccion":entrenables/total})
assert 0<entrenables<totalSalida comprobada
{'parametros_totales': 28544, 'entrenables': 1024, 'fraccion': 0.03587443946188341}
3. Secuencias sintéticas de entrenamiento
Los tokens 0 son padding y se excluyen de la pérdida mediante -100. Las secuencias son artificiales y diminutas; no use la caída de pérdida como prueba de comprensión ni de generalización lingüística.
Código de referencia
ids = torch.tensor([[1,3,4,5,6,2,0,0],[1,4,5,6,7,2,0,0],[1,5,6,7,8,2,0,0],[1,6,7,8,9,2,0,0]])
mascara = (ids!=0).long()
labels = ids.masked_fill(ids==0,-100)
modelo.eval()
with torch.no_grad():
inicial = float(modelo(input_ids=ids,attention_mask=mascara,labels=labels).loss)
print("Pérdida inicial:",round(inicial,4))Salida comprobada
Pérdida inicial: 3.4919
4. Optimizar solo los adaptadores
El optimizador recibe parámetros entrenables. Conservamos una copia de un peso base congelado para comprobar que no cambia. En una adaptación real reserve datos de evaluación y controle también regresiones de capacidades previas.
Código de referencia
nombre_base,peso_base = next((n,p) for n,p in modelo.named_parameters() if not p.requires_grad)
antes = peso_base.detach().clone()
opt = torch.optim.AdamW((p for p in modelo.parameters() if p.requires_grad),lr=.02)
modelo.train()
for paso in range(30):
opt.zero_grad()
loss = modelo(input_ids=ids,attention_mask=mascara,labels=labels).loss
loss.backward()
opt.step()
modelo.eval()
with torch.no_grad():
final = float(modelo(input_ids=ids,attention_mask=mascara,labels=labels).loss)
print({"perdida_inicial":round(inicial,4),"perdida_final_train":round(final,4)})Salida comprobada
{'perdida_inicial': 3.4919, 'perdida_final_train': 3.112}
Comprobaciones
Se comprueba ejecución, parámetros congelados y gradientes de los adaptadores. Esta pérdida usa entrenamiento y no estima rendimiento fuera de él.
Código de referencia
assert math.isfinite(inicial) and math.isfinite(final)
assert torch.equal(antes,peso_base.detach())
assert any("lora_" in n and p.requires_grad for n,p in modelo.named_parameters())
assert any(p.grad is not None and torch.isfinite(p.grad).all() for p in modelo.parameters() if p.requires_grad)
print("Comprobaciones aprobadas; el peso base verificado no cambió")Salida comprobada
Comprobaciones aprobadas; el peso base verificado no cambió
Siguientes pasos
- Añada validación sintética realmente reservada y mida pérdida fuera de entrenamiento.
- Compare rangos 2, 4 y 8 con el mismo presupuesto y semilla.
- Antes de usar
from_pretrained, revise licencia, memoria, tokenizador y formato de diálogo del modelo elegido. - Compare prompt, RAG y ajuste antes de invertir en adaptación.
Referencia: https://huggingface.co/docs/peft/main/en/conceptual_guides/lora