Capítulo 1: Comprendiendo LoRA
La intuición detrás de la adaptación de bajo rango
LoRA (Low-Rank Adaptation, Adaptación de Bajo Rango) es una técnica elegante que parte de una observación simple pero poderosa: no es necesario actualizar todos los parámetros para adaptar un modelo a nuevas tareas.
La idea central
Observación clave
Al ajustar modelos preentrenados, las actualizaciones de los pesos suelen tener un "rango intrínseco" bajo—es decir, los cambios pueden capturarse con un conjunto mucho más pequeño de parámetros.
Analogía
Piénselo como editar un documento:
- Ajuste fino completo: Reescribir todo el documento
- LoRA: Añadir notas adhesivas con correcciones
El documento original (modelo base) permanece intacto, y las notas adhesivas (adaptadores LoRA) capturan los cambios.
Cómo funciona LoRA
Ajuste fino tradicional
En una capa de red neuronal:
h = Wx
Donde W es una matriz de pesos de tamaño (d × d).
El ajuste fino completo actualiza W directamente:
W' = W + ΔW
Donde ΔW es el cambio aprendido para todos los parámetros (d × d).
Enfoque de LoRA
LoRA representa ΔW como el producto de dos matrices más pequeñas:
ΔW = BA
Donde:
- B tiene tamaño (d × r)
- A tiene tamaño (r × d)
- r es mucho menor que d (r ≪ d)
La pasada hacia adelante se convierte en:
h = Wx + BAx = (W + BA)x
Representación visual
Ahorro de parámetros
Ejemplo: una matriz de pesos 4096 × 4096
# Original weight matrix
d = 4096
original_params = d * d # 16,777,216 parameters
# LoRA with rank 16
r = 16
lora_params = d * r + r * d # 131,072 parameters
# Savings
reduction = 1 - (lora_params / original_params)
print(f"Parameter reduction: {reduction:.2%}") # 99.22%
Para un modelo completo
| Modelo | Original | LoRA (r=16) | Reducción |
|---|---|---|---|
| 7B | 7,000,000,000 | ~4,000,000 | 99.94% |
| 13B | 13,000,000,000 | ~8,000,000 | 99.94% |
| 70B | 70,000,000,000 | ~40,000,000 | 99.94% |
Por qué funciona el bajo rango
Dimensionalidad intrínseca
La investigación muestra que las actualizaciones durante el ajuste fino tienden a situarse en un subespacio de baja dimensión:
- Los modelos preentrenados ya tienen representaciones ricas
- La adaptación a la tarea requiere "dirigir" en lugar de "reconstruir"
- Muchas dimensiones del espacio de pesos son redundantes para tareas específicas
Evidencia empírica
Del artículo original de LoRA:
- r=4 suele ser suficiente para muchas tareas
- r=8-16 recomendado para adaptaciones complejas
- r=64+ rara vez es necesario, con rendimientos decrecientes
Inicialización
Matriz A: Gaussiana aleatoria
# A is initialized with small random values
A = torch.randn(r, d) * 0.01
Matriz B: Cero
# B is initialized to zero
B = torch.zeros(d, r)
¿Por qué esta inicialización?
Al inicio del entrenamiento: BA = 0 × A = 0
→ La salida no cambia respecto al modelo base
→ Inicio de entrenamiento estable
→ Adaptación gradual
Qué capas seleccionar
Arquitectura Transformer
Attention Block:
├── Query projection (q_proj) ← Objetivo común
├── Key projection (k_proj) ← A veces objetivo
├── Value projection (v_proj) ← Objetivo común
└── Output projection (o_proj) ← A veces objetivo
Feed-Forward Block:
├── Gate projection (gate_proj) ← A veces objetivo
├── Up projection (up_proj) ← A veces objetivo
└── Down projection (down_proj) ← A veces objetivo
Configuraciones comunes
| Configuración | Módulos objetivo | Caso de uso |
|---|---|---|
| Mínima | q_proj, v_proj | Experimentos rápidos |
| Estándar | q_proj, k_proj, v_proj, o_proj | Equilibrado |
| Completa | Toda la atención + FF | Máxima capacidad |
Fusión de LoRA
Durante la inferencia (con adaptador)
# Two paths: base + LoRA
output = W @ x + B @ A @ x
Ligera sobrecarga por el cálculo adicional.
Fusionado (sin adaptador)
# Merge once
W_merged = W + B @ A
# Single path at inference
output = W_merged @ x
Sin sobrecarga—idéntico a un modelo ajustado completamente.
Ejemplo de fusión
from peft import PeftModel
# Load model with adapter
model = PeftModel.from_pretrained(base_model, "path/to/adapter")
# Merge adapter into base model
model = model.merge_and_unload()
# Now model is a regular model without adapter overhead
model.save_pretrained("merged-model")
Variantes de LoRA
LoRA estándar
La formulación original descrita arriba.
LoRA+
Aplica diferentes tasas de aprendizaje a las matrices A y B.
DoRA (Weight-Decomposed Low-Rank Adaptation)
Separa la magnitud y la dirección de los pesos.
GaLore (Gradient Low-Rank Projection)
Proyecta los gradientes en un espacio de bajo rango.
Puntos clave
✅ LoRA representa las actualizaciones de pesos como productos de matrices de bajo rango
✅ Solo entrena ~0.01-0.1% de los parámetros originales
✅ B inicializada en cero garantiza un inicio de entrenamiento estable
✅ Es común seleccionar proyecciones de atención (q_proj, v_proj)
✅ Puede fusionarse para no tener sobrecarga en inferencia
✅ El bajo rango funciona porque el ajuste fino tiene baja dimensionalidad intrínseca
Próximos pasos
Continúe con Capítulo 2: Matemáticas de LoRA para las bases matemáticas.
Comprobación rápida
Antes de continuar, asegúrese de poder responder:
- ¿Cómo representa LoRA las actualizaciones de pesos?
- ¿Por qué B se inicializa en cero?
- ¿Qué significa "bajo rango" en el contexto de LoRA?