Introducción a las Redes Convolucionales Históricas
Las redes neuronales convolucionales (CNN) han sido fundamentales en el avance de la visión por computadora. Este artículo explora arquitecturas emblemáticas, analiza sus diseños y proporciona ejemplos de implementación usando el framwork PyTorch.
LeNet-5: Los Cimientos de las CNN
Esta red pionera introdujo la arquitectura básica de capas convolucionales y de pooling. Su estructura procesa imágenes de entrada de 32x32 píxeles mediante:
- Capas convolucionales con filtros de 5x5 para extracción de características locales.
- Capas de max-pooling 2x2 para reducción de dimensionalidad.
- Capas totalmente conectadas para la clasificación final.
Implementación en PyTorch
import torch
from torch import nn
class RedLeNet(nn.Module):
def __init__(self):
super().__init__()
self.conv1 = nn.Conv2d(1, 6, 5)
self.pool = nn.MaxPool2d(2, 2)
self.conv2 = nn.Conv2d(6, 16, 5)
self.fc1 = nn.Linear(16 * 5 * 5, 120)
self.fc2 = nn.Linear(120, 84)
self.fc3 = nn.Linear(84, 10)
def forward(self, x):
x = self.pool(torch.relu(self.conv1(x)))
x = self.pool(torch.relu(self.conv2(x)))
x = x.view(-1, 16 * 5 * 5)
x = torch.relu(self.fc1(x))
x = torch.relu(self.fc2(x))
x = self.fc3(x)
return x
modelo = RedLeNet()
entrada = torch.randn(1, 1, 32, 32)
salida = modelo(entrada)
AlexNet: El Impulso de la Era Moderna
AlexNet demostró el poder de las redes más profundas en copmeticiones a gran escala. Sus innovaciones clave incluyen:
- Uso de la función de activación ReLU para un entrenamiento más rápido.
- Arquitectura extendida con 5 capas convolucionales y 3 capas densas.
- Técnicas de regularización como Dropout para reducir el sobreajuste.
Esquema de la Red
La red procesa imágenes de 224x224x3 a través de bloques secuenciales de convolución, ReLU, pooling, y finalmente clasificadores densos con Dropout.
VGGNet: Profundidad con Convoluciones Pequeñas
La familia VGG demostró que apilar múltiples capas de convolución 3x3 puede emular campos receptivos más grandes con menos parámetros. Su diseño es notable por:
- La uniformidad estructural, utilizando exclusiavmente convoluciones 3x3 y pooling 2x2.
- La creación de redes muy profundas (hasta 19 capas) de manera escalable.
Estructura Tipo VGG-16
class VGG16(nn.Module):
def __init__(self, num_clases=1000):
super().__init__()
self.capas_caracteristicas = nn.Sequential(
nn.Conv2d(3, 64, 3, padding=1), nn.ReLU(True),
nn.Conv2d(64, 64, 3, padding=1), nn.ReLU(True),
nn.MaxPool2d(2, 2),
# ... bloques repetitivos ...
nn.Conv2d(512, 512, 3, padding=1), nn.ReLU(True),
nn.MaxPool2d(2, 2)
)
self.clasificador = nn.Sequential(
nn.Linear(512 * 7 * 7, 4096), nn.ReLU(True), nn.Dropout(),
nn.Linear(4096, 4096), nn.ReLU(True), nn.Dropout(),
nn.Linear(4096, num_clases)
)
def forward(self, x):
x = self.capas_caracteristicas(x)
x = x.view(x.size(0), -1)
x = self.clasificador(x)
return x
GoogLeNet: El Módulo Inception
GoogLeNet introdujo un diseño paralelo innovador dentro de cada bloque, el módulo Inception, que:
- Ejecuta convoluciones de diferentes tamaños (1x1, 3x3, 5x5) y pooling simultáneamente.
- Concatena las salidas para combinar características a múltiples escalas.
- Utiliza convoluciones 1x1 como proyecciones para reducir la dimensionalidad y el costo computacional.
ResNet: Aprendizaje con Conexiones Residuales
Las Redes Residuales (ResNet) abordaron el problema de la degradación en redes muy profundas mediante bloques residuales. La idea central es:
Aprender una función residual F(x) = H(x) - x, de modo que la salida del bloque sea H(x) = F(x) + x. Esto facilita el aprendizaje de la identidad y permite un flujo de gradientes estable a través de cientos de capas.
Bloque Residual Básico
class BloqueResidual(nn.Module):
def __init__(self, canales_entrada, canales_salida, stride=1):
super().__init__()
self.conv1 = nn.Conv2d(canales_entrada, canales_salida, 3, stride, 1, bias=False)
self.bn1 = nn.BatchNorm2d(canales_salida)
self.conv2 = nn.Conv2d(canales_salida, canales_salida, 3, 1, 1, bias=False)
self.bn2 = nn.BatchNorm2d(canales_salida)
# Atajo para ajustar dimensiones si es necesario
self.atajo = nn.Sequential()
if stride != 1 or canales_entrada != canales_salida:
self.atajo = nn.Sequential(
nn.Conv2d(canales_entrada, canales_salida, 1, stride, bias=False),
nn.BatchNorm2d(canales_salida)
)
def forward(self, x):
residual = self.atajo(x)
out = torch.relu(self.bn1(self.conv1(x)))
out = self.bn2(self.conv2(out))
out += residual
return torch.relu(out)
La arquitectura ResNet completa apila estos bloques, permitiendo modelos de 50, 101 o más capas, consiguiendo un rendimiento sobresaliente sin un aumento excesivo en el error de entrenamiento.