Ya sabes construir capas Conv2D y MaxPooling2D, predecir sus formas de salida y contar sus parámetros. La siguiente pregunta natural es: ¿cómo se combinan esas piezas en redes que funcionan de verdad? La buena noticia es que no hay que inventarlo desde cero: entre 1998 y hoy, una serie de arquitecturas célebres fue resolviendo, una a una, las dificultades de entrenar CNN cada vez más profundas, y sus patrones de diseño se han convertido en el vocabulario estándar del campo. En esta lección recorreremos esa evolución —LeNet-5, AlexNet, VGG, GoogLeNet/Inception, ResNet y las familias eficientes para móvil— entendiendo la idea clave de cada una, y la aterrizaremos implementando en Keras una mini-VGG y un bloque residual. Conocer estas arquitecturas no es cultura general: son exactamente los modelos que TecnoMarket (y tú) reutilizaréis en la práctica.

Contenido

  1. LeNet-5: la pionera (1998)
  2. AlexNet: el despertar (2012)
  3. VGG: la elegancia de la profundidad (2014)
  4. GoogLeNet/Inception: módulos en paralelo (2014)
  5. ResNet: conexiones residuales (2015)
  6. Eficiencia para móvil y edge: MobileNet y EfficientNet
  7. Tabla comparativa
  8. Manos a la obra: una mini-VGG y un bloque residual en Keras

LeNet-5: la pionera (1998)

Mucho antes del boom del deep learning, Yann LeCun diseñó LeNet-5 para leer dígitos manuscritos en cheques bancarios — el mismo problema MNIST que resolviste en 02-05, pero quince años antes y con hardware de los 90. Su estructura te resultará familiar porque es exactamente la anatomía que vimos en 03-01:

Entrada 32×32×1 → Conv 5×5 (6 filtros) → Pooling → Conv 5×5 (16 filtros) → Pooling → Densa 120 → Densa 84 → Salida 10
  • Unos 60 000 parámetros en total: menor que nuestra red densa de 02-05 (~110 000), y sin embargo más precisa en dígitos, porque respeta la estructura espacial.
  • Estableció el patrón canónico conv → pool → conv → pool → densas que seguimos usando.
  • Su limitación no era conceptual sino de época: sin GPUs, sin grandes datasets y con activaciones sigmoide/tanh (con su vanishing gradient, como viste en 02-03), no se podía escalar.

AlexNet: el despertar (2012)

En 01-02 contamos que AlexNet ganó ImageNet 2012 reduciendo el error de forma tan brutal que reactivó todo el campo. Ahora puedes entender qué era AlexNet: en esencia, una LeNet a lo grande más tres ingredientes nuevos.

  • Estructura: 5 capas convolucionales + 3 densas, ~60 millones de parámetros, entrada 224×224×3 (¡la imagen de nuestro cálculo de explosión de parámetros en 03-01!).
  • Ingrediente 1: ReLU en vez de sigmoide/tanh — entrenamiento mucho más rápido y menos vanishing (02-02).
  • Ingrediente 2: GPUs — se entrenó en dos GPUs domésticas durante ~una semana.
  • Ingrediente 3: datos masivos (1.2 millones de imágenes de ImageNet) y trucos contra el sobreajuste como dropout y aumento de datos (los sistematizaremos en 05-04).
  • Resultado: 15.3 % de error top-5 en ImageNet frente al 26.2 % del segundo clasificado. La era moderna del deep learning empieza aquí.

Su lección de diseño: escala (más datos, más cómputo, más capas) + ReLU. Pero AlexNet era artesanal: filtros de 11×11, 5×5 y 3×3 mezclados sin un criterio claro. La siguiente arquitectura puso orden.

VGG: la elegancia de la profundidad (2014)

VGG (Universidad de Oxford, 2014) se construye sobre una única regla de diseño radicalmente simple:

Usa siempre filtros 3×3 con padding same, apílalos en bloques, y tras cada bloque haz max pooling 2×2 duplicando el número de filtros.

VGG-16 (16 capas con pesos) queda así: bloques de 64, 128, 256, 512 y 512 filtros, y la imagen se reduce 224 → 112 → 56 → 28 → 14 → 7.

¿Por qué filtros 3×3 y no más grandes? Dos filtros 3×3 apilados "ven" una zona de 5×5 (el segundo mira una ventana de resultados que a su vez miraron ventanas), y tres apilados ven 7×7. Pero comparemos parámetros para C canales de entrada y salida:

Opción Campo receptivo Parámetros (sin sesgos)
1 conv de 7×7 7×7 49 C²
3 convs de 3×3 7×7 3 × 9 C² = 27 C²

Las tres capas 3×3 ven lo mismo con casi la mitad de parámetros y, además, intercalan tres ReLU en vez de una: más no-linealidad, más capacidad de representación. Esta observación consagró el 3×3 como estándar (por eso lo usamos por defecto en 03-02).

El precio: VGG-16 tiene 138 millones de parámetros, de los cuales ~102 millones están en la primera capa densa tras el Flatten (7×7×512 = 25 088 entradas × 4096 neuronas) — la patología que ya diagnosticamos al leer el summary() en 03-02, llevada al extremo.

GoogLeNet/Inception: módulos en paralelo (2014)

El mismo año, Google atacó la pregunta "¿qué tamaño de filtro uso en cada capa?" con una respuesta lateral: no elijas — usa varios a la vez. El módulo Inception aplica en paralelo, sobre la misma entrada, convoluciones 1×1, 3×3, 5×5 y un max pooling, y concatena todos los mapas resultantes por el eje de canales: la red decide durante el entrenamiento a qué rama dar peso.

flowchart TB
    E["Entrada del modulo"] --> A["Conv 1x1"]
    E --> B["Conv 1x1 -> Conv 3x3"]
    E --> C["Conv 1x1 -> Conv 5x5"]
    E --> D["MaxPool 3x3 -> Conv 1x1"]
    A --> F["Concatenar canales"]
    B --> F
    C --> F
    D --> F

Dos ideas de este diseño se volvieron patrimonio común:

  • La convolución 1×1 ("bottleneck"): un filtro 1×1×C no mira vecinos espaciales, pero mezcla y comprime canales (p. ej. de 256 canales a 64) antes de las convoluciones caras. Es una capa densa aplicada píxel a píxel sobre el vector de canales, y abarata drásticamente el módulo.
  • Global average pooling al final: en vez de Flatten + densas gigantes, se promedia cada mapa de características completo a un solo número. GoogLeNet logró así 22 capas con solo ~7 millones de parámetros — 20 veces menos que VGG con mejor error.

ResNet: conexiones residuales (2015)

Con ReLU, GPUs y buenos diseños, cabría esperar que apilar más capas siempre mejorase. Pero los experimentos mostraban lo contrario: a partir de cierta profundidad (~20 capas), añadir capas empeoraba incluso el error de entrenamiento. No era sobreajuste (eso empeoraría solo la validación): era un problema de optimización — la degradación. El gradiente, tras atravesar decenas de capas multiplicando derivadas (la regla de la cadena y el "reparto de culpa" de 02-03), llegaba a las primeras capas desvanecido, y la red profunda ni siquiera lograba aprender lo que la superficial ya sabía.

ResNet (Microsoft Research, 2015) lo resolvió con un cambio mínimo y genial: la conexión residual (skip connection). En vez de pedir a un bloque de capas que aprenda una transformación completa H(x), se le pide que aprenda solo la corrección F(x) sobre la identidad, y la entrada se suma directamente a la salida:

salida = F(x) + x
flowchart LR
    X["x"] --> C1["Conv 3x3 + ReLU"]
    C1 --> C2["Conv 3x3"]
    C2 --> S(("+"))
    X -->|"atajo (identidad)"| S
    S --> R["ReLU"] --> Y["salida"]

Por qué funciona, en dos lecturas:

  • Lectura de aprendizaje: si un bloque no aporta nada útil, le basta con aprender F(x) = 0 (pesos a cero, fácil) y el bloque se convierte en la identidad: la red de 50 capas nunca puede ser peor que la de 20, porque las capas sobrantes pueden "apartarse". Aprender una corrección pequeña es más fácil que aprender una transformación entera.
  • Lectura del gradiente: al derivar F(x) + x, la rama + x tiene derivada 1, así que en backpropagation el gradiente dispone de una autopista directa hacia las capas tempranas, sin atravesar (y sin ser encogido por) todas las multiplicaciones intermedias. Es la solución arquitectónica al vanishing gradient que analizamos en 02-03.

Con esto, la profundidad se desbloqueó: ResNet-152 (152 capas) ganó ImageNet 2015 con un error top-5 del 3.6 %, por debajo del humano de referencia (~5 %), y ResNet-50 sigue siendo hoy uno de los caballos de batalla de la visión por computador. Las conexiones residuales aparecen desde entonces en casi todo, incluidos los transformers (05-05).

Eficiencia para móvil y edge: MobileNet y EfficientNet

Mención breve, porque te los cruzarás constantemente: no todo es ganar ImageNet. Si TecnoMarket quisiera que su app móvil clasificara la foto en el teléfono del vendedor (sin subirla a un servidor), necesitaría redes pequeñas y rápidas:

  • MobileNet (2017): sustituye la convolución estándar por la convolución separable en profundidad (primero un filtro espacial por canal, luego una conv 1×1 que mezcla canales), reduciendo el cómputo ~8-9 veces con poca pérdida de precisión. Ideal para móvil y dispositivos edge.
  • EfficientNet (2019): parte de una base eficiente y define una regla de escalado compuesto (aumentar a la vez profundidad, anchura y resolución de entrada en proporciones equilibradas), generando una familia B0...B7 que cubre desde móvil hasta servidor con precisión puntera por cada nivel de cómputo.

Tabla comparativa

Arquitectura Año Capas (con pesos) Parámetros Idea clave Error top-5 ImageNet
LeNet-5 1998 7 ~60 K Patrón conv→pool→densas — (dígitos, no ImageNet)
AlexNet 2012 8 ~60 M Escala + ReLU + GPU 15.3 %
VGG-16 2014 16 ~138 M Profundidad con solo filtros 3×3 7.3 %
GoogLeNet 2014 22 ~7 M Módulos Inception en paralelo, convs 1×1 6.7 %
ResNet-152 2015 152 ~60 M Conexiones residuales 3.6 %
MobileNetV2 2018 ~53 ~3.5 M Convs separables (móvil/edge) ~9 % (top-5, modelo pequeño)
EfficientNet-B7 2019 ~200+ ~66 M Escalado compuesto ~1.9 %

La tendencia que cuenta la tabla: el error cae de 15 % a menos de 2 % en siete años, y no a base de inflar parámetros (GoogLeNet y MobileNet los reducen), sino a base de mejores ideas de arquitectura.

Manos a la obra: una mini-VGG y un bloque residual en Keras

No vamos a implementar VGG-16 ni ResNet-50 enteras (no tendría sentido entrenarlas desde cero aquí, y enseguida veremos por qué tampoco hace falta). Vamos a implementar los patrones a escala reducida, que es lo que de verdad se transfiere.

Mini-VGG para fotos de producto

El patrón VGG en miniatura para imágenes 64×64×3 de TecnoMarket, con la regla "dos convs 3×3 same + pooling, duplicando filtros" y cierre moderno con global average pooling en lugar del Flatten glotón:

from tensorflow import keras
from tensorflow.keras import layers

def bloque_vgg(x, filtros):
    """Dos convs 3x3 'same' + ReLU, y un max pooling que reduce a la mitad."""
    x = layers.Conv2D(filtros, (3, 3), padding="same", activation="relu")(x)
    x = layers.Conv2D(filtros, (3, 3), padding="same", activation="relu")(x)
    return layers.MaxPooling2D((2, 2))(x)

entrada = keras.Input(shape=(64, 64, 3))
x = bloque_vgg(entrada, 32)    # 64x64 -> 32x32, 32 canales
x = bloque_vgg(x, 64)          # 32x32 -> 16x16, 64 canales
x = bloque_vgg(x, 128)         # 16x16 -> 8x8, 128 canales
x = layers.GlobalAveragePooling2D()(x)   # 8x8x128 -> vector de 128 (media de cada mapa)
salida = layers.Dense(4, activation="softmax")(x)  # 4 categorias de producto

mini_vgg = keras.Model(entrada, salida, name="mini_vgg")
mini_vgg.summary()

Detalles que conviene notar:

  • Usamos la API funcional de Keras (keras.Input, capas aplicadas como funciones, keras.Model) en vez del Sequential de 02-05 y 03-02. Para VGG daría igual, pero es imprescindible para el bloque residual de abajo, porque Sequential solo sabe encadenar capas en línea recta y un atajo no es una línea recta.
  • Cada bloque_vgg apila dos convs antes del pooling: campo receptivo 5×5 con parámetros de 3×3+3×3 y dos ReLU — el argumento de VGG.
  • GlobalAveragePooling2D convierte los 128 mapas de 8×8 en un vector de 128 medias: la salida densa solo necesita 128×4+4 = 516 parámetros. El modelo entero queda en ~300 K parámetros, sin la densa monstruosa que en 03-02 concentraba el 85 % del total.

Un bloque residual

El patrón ResNet mínimo — dos convs y la suma del atajo:

def bloque_residual(x, filtros):
    """Bloque residual basico: salida = ReLU( F(x) + x )."""
    atajo = x                                                # guardamos la entrada
    y = layers.Conv2D(filtros, (3, 3), padding="same", activation="relu")(x)
    y = layers.Conv2D(filtros, (3, 3), padding="same")(y)    # sin activacion aun
    y = layers.Add()([y, atajo])                             # F(x) + x
    return layers.Activation("relu")(y)                      # ReLU tras la suma

entrada = keras.Input(shape=(16, 16, 64))
salida = bloque_residual(entrada, 64)
bloque = keras.Model(entrada, salida)
bloque.summary()

Lectura del código, línea a línea:

  • atajo = x: la conexión de salto no es una capa, es simplemente conservar la referencia a la entrada para usarla después.
  • La segunda conv va sin activación: primero se suma el atajo y después se aplica la ReLU. Si activáramos antes de sumar, F(x) solo podría añadir valores positivos y la corrección perdería la mitad de su rango.
  • layers.Add()([y, atajo]) exige que ambos tensores tengan la misma forma — por eso usamos padding same y los mismos 64 filtros que trae la entrada. Cuando un bloque cambia el número de canales o reduce el tamaño (stride 2), el atajo se adapta con una conv 1×1 (el truco bottleneck de Inception reutilizado); las ResNet reales alternan ambos tipos de bloque.
  • Apilar bloque_residual decenas de veces es, literalmente, cómo se construye una ResNet: cada bloque añade su pequeña corrección y el gradiente siempre tiene su autopista de vuelta.

Errores Comunes y Consejos

  • Intentar entrenar VGG-16 o ResNet-50 desde cero con pocos datos. Estas redes se entrenaron con 1.2 millones de imágenes; con las decenas de miles de fotos de TecnoMarket (o menos) sobreajustarían masivamente. La solución es reutilizarlas preentrenadas (ver conclusión).
  • Confundir degradación con sobreajuste. El sobreajuste empeora la validación pero mejora el entrenamiento; la degradación que motivó ResNet empeoraba también el entrenamiento. Son males distintos con remedios distintos (05-04 para el primero, skip connections para el segundo).
  • Olvidar que Add suma, no concatena. layers.Add() suma elemento a elemento (formas idénticas, patrón ResNet); layers.Concatenate() apila canales (patrón Inception). Elegir el equivocado cambia el diseño por completo.
  • Poner la ReLU antes de la suma residual. El orden canónico es conv → conv → sumar atajo → ReLU. Actívalo antes y estarás restringiendo la corrección F(x) a valores no negativos.
  • Memorizar arquitecturas en vez de ideas. Dentro de tres años habrá otra arquitectura de moda; lo que permanece es el repertorio: 3×3 apilados, convs 1×1 para comprimir canales, global average pooling, conexiones residuales. Aprende el vocabulario, no la enciclopedia.

Ejercicios

Ejercicio 1: ordenar la historia

Sin mirar la tabla, asigna cada idea a su arquitectura y ordénalas cronológicamente: (a) módulos con varias convoluciones en paralelo, (b) atajos que suman la entrada a la salida, (c) solo filtros 3×3 apilados en bloques, (d) primer gran éxito con ReLU + GPU en ImageNet, (e) patrón original conv→pool→densas para dígitos.

Ejercicio 2: el argumento de VGG con números

Una capa recibe y produce 128 canales. Compara los parámetros (ignora sesgos) de (a) una sola conv 7×7 frente a (b) tres convs 3×3 apiladas. ¿Qué ventaja adicional a la reducción de parámetros aportan las tres capas?

Ejercicio 3: depurar un bloque residual

Este bloque lanza un error al construirse. Explica por qué y propón dos arreglos distintos:

def bloque_mal(x):                       # x llega con forma (8, 8, 64)
    atajo = x
    y = layers.Conv2D(128, (3, 3), padding="same", activation="relu")(x)
    y = layers.Conv2D(128, (3, 3), padding="same")(y)
    return layers.Activation("relu")(layers.Add()([y, atajo]))

Soluciones

Ejercicio 1: (e) LeNet-5, 1998 → (d) AlexNet, 2012 → (c) VGG, 2014 → (a) GoogLeNet/Inception, 2014 → (b) ResNet, 2015.

Ejercicio 2:

  • (a) Una conv 7×7: 7 × 7 × 128 × 128 = 802 816 parámetros.
  • (b) Tres convs 3×3: 3 × (3 × 3 × 128 × 128) = 442 368 parámetros — un 45 % menos con el mismo campo receptivo de 7×7.
  • Ventaja adicional: las tres capas intercalan tres ReLU en vez de una, así que la transformación es más no lineal y expresiva (y el razonamiento de 02-02 explica por qué eso importa).

Ejercicio 3: La entrada x tiene 64 canales pero F(x) produce 128; layers.Add() exige formas idénticas y falla con (8, 8, 64) frente a (8, 8, 128). Arreglos: (1) usar 64 filtros en las dos convs del bloque, de modo que F(x) conserve la forma de la entrada; (2) adaptar el atajo con una conv 1×1 de 128 filtros — atajo = layers.Conv2D(128, (1, 1), padding="same")(x) — que proyecta los 64 canales a 128 antes de la suma (es lo que hacen las ResNet reales al cambiar de etapa).

Conclusión

Has recorrido veinte años de evolución en una lección: LeNet fijó el patrón conv→pool→densas; AlexNet demostró que escala + ReLU + GPU cambiaban las reglas; VGG destiló el diseño a bloques de filtros 3×3; Inception introdujo las ramas paralelas, las convs 1×1 y el global average pooling; ResNet desbloqueó la profundidad arbitraria con conexiones residuales que dan al gradiente una autopista contra el vanishing de 02-03; y MobileNet/EfficientNet optimizan el coste para llegar al teléfono del vendedor. Además, has implementado los dos patrones más reutilizados —el bloque VGG y el bloque residual— con la API funcional de Keras.

Queda una observación con enormes consecuencias prácticas: todas estas arquitecturas están disponibles ya entrenadas sobre ImageNet (en Keras, a una línea de distancia: keras.applications.ResNet50(...)). Sus primeras capas aprendieron detectores de bordes, texturas y formas que sirven para cualquier imagen — también para las fotos de productos de TecnoMarket. Reutilizar ese conocimiento en vez de entrenar desde cero se llama transfer learning, y es la técnica que estudiaremos en 05-03 (y aplicaremos con fine-tuning en 07-05). Antes de llegar ahí, en la próxima lección levantaremos la vista de la clasificación pura: veremos todo lo que las CNN saben hacer con imágenes — localizar, detectar, segmentar, leer y buscar por similitud — y cómo encaja cada tarea en la operativa de TecnoMarket.

Curso de Deep Learning

Módulo 1: Introducción a Deep Learning

Módulo 2: Fundamentos de Redes Neuronales

Módulo 3: Redes Neuronales Convolucionales (CNN)

Módulo 4: Redes Neuronales Recurrentes (RNN)

Módulo 5: Técnicas Avanzadas en Deep Learning

Módulo 6: Herramientas y Frameworks

Módulo 7: Proyectos Prácticos

Módulo 8: Consideraciones Éticas y Futuro del Deep Learning

© Copyright 2026. Todos los derechos reservados