LECCIÓN 13 · AVANZADO

Transfer learning

El truco que usa casi todo el mundo en la práctica: en vez de entrenar desde cero (caro y necesita muchísimos datos), partes de una red ya entrenada y la adaptas a tu problema.

Recuerda de la lección anterior: las CNNs usan filtros que se deslizan por la imagen para detectar patrones locales. Entrenarlas desde cero requiere muchos datos y tiempo. Hoy: cómo saltarte esa parte aprovechando una red que ya lo hizo.

1. La idea: no reinventes la rueda

Entrenar una red potente desde cero requiere millones de ejemplos y mucho cómputo. Pero ya existen redes entrenadas sobre datasets enormes (ImageNet — más de un millón de imágenes clasificadas en 1000 categorías — o grandes corpus de texto) que ya saben extraer características útiles. El transfer learning reutiliza ese conocimiento:

Tomas una red preentrenada, congelas sus capas (al bloque principal de la red — las capas que extraen características — se le llama backbone, del inglés "columna vertebral"). Esas capas ya aprendieron a detectar bordes, texturas, conceptos… y las conservas. Solo entrenas una capa final nueva para tu tarea específica. Con poquísimos datos consigues resultados excelentes.

2. Paso 1 — Congelar los pesos preentrenados

"Congelar" = poner requires_grad = False para que el optimizador no los toque. Simulemos un "backbone" preentrenado y congelémoslo:

backbone = nn.Sequential(nn.Linear(10,8), nn.ReLU(), nn.Linear(8,5))

for p in backbone.parameters():
    p.requires_grad = False        # congelar TODO

print(sum(p.requires_grad for p in backbone.parameters()))
salida realparams entrenables tras congelar: 0

Cero parámetros entrenables: la red está "congelada", conserva lo que ya sabía.

3. Paso 2 — Reemplazar la cabeza por una tuya

La última capa de la red original predice las clases de su problema. La cambias por una nueva, adaptada a tu tarea. La capa nueva nace descongelada (entrenable):

backbone[2] = nn.Linear(8, 2)   # backbone[2] = tercera capa (índice 0=Linear, 1=ReLU, 2=Linear) — la "cabeza"

entrenables = sum(p.numel() for p in backbone.parameters() if p.requires_grad)  # numel() = total de números del tensor
print(entrenables)
salida realparams entrenables tras nueva cabeza: 18

Ahora solo son entrenables los 18 pesos de la cabeza nueva (8×2 + 2 bias). El resto de la red aporta sus características ya aprendidas, sin cambiar. Entrenas muy poco y muy rápido.

4. Cómo se ve con un modelo real (torchvision)

En la práctica usarías un modelo preentrenado de verdad. El patrón es idéntico al de arriba:

from torchvision import models

modelo = models.resnet18(weights='DEFAULT')   # red entrenada en ImageNet

for p in modelo.parameters():
    p.requires_grad = False                  # congelar el backbone

modelo.fc = nn.Linear(modelo.fc.in_features, 2)  # nueva cabeza: 2 clases
# entrenas normal: solo se ajustará modelo.fc
📦 Esto requiere instalar torchvision (pip install torchvision), que no está en este entorno. Pero el mecanismo — congelar + reemplazar la cabeza — es exactamente el que ejecutamos arriba con resultados reales.

5. ¿Cuándo usarlo?

Lo que aprendiste hoy: transfer learning = partir de una red preentrenada (el backbone), congelar sus pesos (requires_grad=False) y entrenar solo una cabeza nueva para tu tarea. Resultado: con 18 parámetros entrenables en vez de cientos, y muy pocos datos, obtienes resultados excelentes. Es la técnica más rentable del deep learning práctico.

En la próxima lección: técnicas pro (schedulers, gradient clipping, capas custom) antes del proyecto final.