En este módulo, aprenderemos a construir una Red Neuronal Convolucional (CNN) desde cero utilizando PyTorch. Las CNNs son especialmente efectivas para tareas de visión por computadora, como la clasificación de imágenes. Vamos a desglosar el proceso en pasos claros y detallados.

Objetivos del Módulo

  1. Comprender la arquitectura básica de una CNN.
  2. Implementar una CNN simple en PyTorch.
  3. Entrenar la CNN con un conjunto de datos de imágenes.
  4. Evaluar el rendimiento de la CNN.

  1. Arquitectura Básica de una CNN

Una CNN típica consta de las siguientes capas:

  • Capas Convolucionales: Aplican filtros para extraer características de la imagen.
  • Capas de Pooling: Reducen la dimensionalidad de las características extraídas.
  • Capas Completamente Conectadas: Realizan la clasificación final basándose en las características extraídas.

Ejemplo de Arquitectura

  1. Entrada: Imagen de 32x32x3 (ancho x alto x canales de color).
  2. Capa Convolucional 1: 32 filtros de 3x3, stride=1, padding=1.
  3. Capa de Pooling 1: MaxPooling de 2x2.
  4. Capa Convolucional 2: 64 filtros de 3x3, stride=1, padding=1.
  5. Capa de Pooling 2: MaxPooling de 2x2.
  6. Capa Completamente Conectada: 512 neuronas.
  7. Salida: 10 neuronas (para clasificación en 10 clases).

  1. Implementación de una CNN en PyTorch

Paso 1: Importar Librerías Necesarias

import torch
import torch.nn as nn
import torch.optim as optim
import torchvision
import torchvision.transforms as transforms

Paso 2: Definir la Arquitectura de la CNN

class SimpleCNN(nn.Module):
    def __init__(self):
        super(SimpleCNN, self).__init__()
        self.conv1 = nn.Conv2d(in_channels=3, out_channels=32, kernel_size=3, stride=1, padding=1)
        self.pool = nn.MaxPool2d(kernel_size=2, stride=2, padding=0)
        self.conv2 = nn.Conv2d(in_channels=32, out_channels=64, kernel_size=3, stride=1, padding=1)
        self.fc1 = nn.Linear(in_features=64 * 8 * 8, out_features=512)
        self.fc2 = nn.Linear(in_features=512, out_features=10)

    def forward(self, x):
        x = self.pool(F.relu(self.conv1(x)))
        x = self.pool(F.relu(self.conv2(x)))
        x = x.view(-1, 64 * 8 * 8)  # Aplanar el tensor
        x = F.relu(self.fc1(x))
        x = self.fc2(x)
        return x

Paso 3: Preparar el Conjunto de Datos

Usaremos el conjunto de datos CIFAR-10 para este ejemplo.

transform = transforms.Compose(
    [transforms.ToTensor(),
     transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])

trainset = torchvision.datasets.CIFAR10(root='./data', train=True,
                                        download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=4,
                                          shuffle=True, num_workers=2)

testset = torchvision.datasets.CIFAR10(root='./data', train=False,
                                       download=True, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=4,
                                         shuffle=False, num_workers=2)

classes = ('plane', 'car', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck')

Paso 4: Definir la Función de Pérdida y el Optimizador

net = SimpleCNN()
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)

Paso 5: Entrenar la CNN

for epoch in range(2):  # número de épocas

    running_loss = 0.0
    for i, data in enumerate(trainloader, 0):
        inputs, labels = data

        optimizer.zero_grad()

        outputs = net(inputs)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()

        running_loss += loss.item()
        if i % 2000 == 1999:    # imprimir cada 2000 mini-batches
            print(f'[Epoch {epoch + 1}, Batch {i + 1}] loss: {running_loss / 2000:.3f}')
            running_loss = 0.0

print('Finished Training')

Paso 6: Evaluar la CNN

correct = 0
total = 0
with torch.no_grad():
    for data in testloader:
        images, labels = data
        outputs = net(images)
        _, predicted = torch.max(outputs.data, 1)
        total += labels.size(0)
        correct += (predicted == labels).sum().item()

print(f'Accuracy of the network on the 10000 test images: {100 * correct / total} %')

Ejercicio Práctico

Ejercicio 1: Modificar la Arquitectura

Modifica la arquitectura de la CNN para agregar una tercera capa convolucional con 128 filtros y una tercera capa de pooling. Entrena y evalúa la nueva red.

Solución

class ModifiedCNN(nn.Module):
    def __init__(self):
        super(ModifiedCNN, self).__init__()
        self.conv1 = nn.Conv2d(in_channels=3, out_channels=32, kernel_size=3, stride=1, padding=1)
        self.pool = nn.MaxPool2d(kernel_size=2, stride=2, padding=0)
        self.conv2 = nn.Conv2d(in_channels=32, out_channels=64, kernel_size=3, stride=1, padding=1)
        self.conv3 = nn.Conv2d(in_channels=64, out_channels=128, kernel_size=3, stride=1, padding=1)
        self.fc1 = nn.Linear(in_features=128 * 4 * 4, out_features=512)
        self.fc2 = nn.Linear(in_features=512, out_features=10)

    def forward(self, x):
        x = self.pool(F.relu(self.conv1(x)))
        x = self.pool(F.relu(self.conv2(x)))
        x = self.pool(F.relu(self.conv3(x)))
        x = x.view(-1, 128 * 4 * 4)  # Aplanar el tensor
        x = F.relu(self.fc1(x))
        x = self.fc2(x)
        return x

# Entrenamiento y evaluación se realizan de la misma manera que antes.

Conclusión

En este módulo, hemos aprendido a construir una CNN desde cero utilizando PyTorch. Hemos cubierto la arquitectura básica de una CNN, cómo implementarla, entrenarla y evaluarla. Además, hemos realizado un ejercicio práctico para modificar y mejorar la arquitectura de la red. En el próximo módulo, exploraremos el aprendizaje por transferencia y cómo utilizar modelos preentrenados para mejorar el rendimiento de nuestras redes neuronales.

© Copyright 2024. Todos los derechos reservados