Las Redes Neuronales Convolucionales (CNNs) son un pilar de la visión por computadora moderna, permitiendo aplicaciones como el reconocimiento de imágenes, la detección facial y los autos autónomos. Estas redes están diseñadas para extraer automáticamente patrones y características de las imágenes, lo que las hace más poderosas que las técnicas tradicionales de aprendizaje automático para tareas visuales.
En este tutorial, implementaremos una CNN utilizando PyTorch, un marco de aprendizaje profundo que es tanto fácil de usar como altamente eficiente para aplicaciones de investigación y producción.
Prerrequisitos: Aprendizaje Profundo y PyTorch
Antes de entrar en los detalles de las CNNs, debes estar familiarizado con el campo del aprendizaje profundo y las bibliotecas de Python que utilizaremos durante la configuración de nuestro entorno.
El aprendizaje profundo es un subconjunto del aprendizaje automático, donde la estructura fundamental del modelo es una red de entradas, capas ocultas y salidas. Dicha red puede tener una o muchas capas ocultas. La intuición original detrás del aprendizaje profundo era crear modelos inspirados en cómo el cerebro humano aprende: a través de células interconectadas llamadas neuronas. Por eso seguimos llamando a los modelos de aprendizaje profundo “redes” neuronales. Estas estructuras de modelos en capas requieren mucho más datos para aprender que otros modelos de aprendizaje supervisado para derivar patrones de los datos no estructurados. Normalmente hablamos de al menos cientos de miles de puntos de datos.
Aunque existen varios marcos y paquetes para implementar algoritmos de aprendizaje profundo, nos centraremos en PyTorch, uno de los marcos más populares y mejor mantenidos. Además de ser utilizado por ingenieros de aprendizaje profundo en la industria, PyTorch es una herramienta favorita entre los investigadores. Muchos artículos de aprendizaje profundo se publican utilizando PyTorch. Está diseñado para ser intuitivo y fácil de usar, compartiendo mucho terreno común con la biblioteca de Python NumPy.
Si necesitas una introducción a estos conceptos, considera inscribirte en el curso de Deep Learning with PyTorch hoy.
¿Qué es una Red Neuronal Convolucional (CNN)?
Las redes neuronales convolucionales, comúnmente llamadas CNN o ConvNet, son un tipo específico de red neuronal profunda bien adaptada para tareas de visión por computadora. La invención de las CNN se remonta a la década de 1980. Sin embargo, solo se volvieron populares en la década de 2010, tras los avances informáticos que resultaron de la implementación de unidades de procesamiento gráfico (GPUs). De hecho, la rápida popularización de las CNN ayudó al campo de las redes neuronales a recuperar prominencia, lo que llevó a la llamada “tercera ola de redes neuronales” en la que todavía vivimos hoy.
Las CNN están específicamente inspiradas en la corteza visual biológica. La corteza tiene pequeñas regiones de células que son sensibles a áreas específicas del campo visual. Esta idea fue ampliada por un experimento fascinante realizado por Hubel y Wiesel en 1962.
Las CNN intentan replicar esta característica creando redes neuronales complejas compuestas por diferentes capas específicas para cada tarea. Las CNN se denominan “feed-forward” porque la información fluye directamente a través del modelo. No hay conexiones de retroalimentación en las que las salidas del modelo se retroalimenten a sí mismas, en comparación con otros modelos que utilizan técnicas como la retropropagación.
En particular, una CNN típicamente consta de las siguientes capas:
Capa convolucional
Este es el primer bloque de construcción de una CNN. Como sugiere el nombre, la tarea matemática principal realizada se llama convolución, que es la aplicación de una función de ventana deslizante a una matriz de píxeles que representan una imagen. La función deslizante aplicada a la matriz se llama kernel o filtro. En la capa de convolución, se aplican varios filtros de igual tamaño, y cada filtro se utiliza para reconocer un patrón específico de la imagen, como la curvatura de los dígitos, los bordes, la forma completa de los dígitos, y más.
Función de activación
Normalmente, se aplica una función de activación ReLU después de cada operación de convolución. Esta función ayuda a la red a aprender relaciones no lineales entre las características de la imagen, haciendo que la red sea más robusta para identificar diferentes patrones. También ayuda a mitigar los problemas de desvanecimiento del gradiente.
Capa de agrupación
El objetivo de la capa de agrupación es extraer las características más significativas de la matriz convolucionada. Esto se logra aplicando algunas operaciones de agregación, las cuales reducen la dimensión del mapa de características (matriz convolucionada), disminuyendo así la memoria utilizada durante el entrenamiento de la red. La agrupación también es relevante para mitigar el sobreajuste.
Capas completamente conectadas
Estas capas se encuentran en la última capa de la red neuronal convolucional, y sus entradas corresponden a la matriz unidimensional aplanada generada por la última capa de agrupación. Se les aplican funciones de activación ReLU para no linealidad.
Arquitectura de la Red Neuronal Convolucional. Fuente: DataCamp
Puedes leer una explicación más detallada de las matemáticas detrás de las CNN en nuestro tutorial, Redes Neuronales Convolucionales en Python.
¿Por qué usar CNN para clasificación de imágenes?
Las redes neuronales convolucionales han sido una de las innovaciones más influyentes en el campo de la visión por computadora. Han tenido un rendimiento mucho mejor que los modelos tradicionales de aprendizaje automático, como SVMs y árboles de decisión, y han producido resultados de vanguardia.
Además, las capas convolucionales otorgan a las CNN sus características invariantes ante la traducción, lo que les permite identificar y extraer patrones y características de los datos independientemente de las variaciones en posición, orientación, escala o traducción.
Las CNN han demostrado ser exitosas en muchos estudios de caso y aplicaciones del mundo real, como:
- Clasificación de imágenes, detección de objetos, segmentación, reconocimiento facial;
- Autos autónomos que aprovechan sistemas de visión basados en CNN;
- Clasificación de estructuras cristalinas utilizando una red neuronal convolucional;
- Sistemas de cámaras de seguridad.
Más allá de las tareas de clasificación de imágenes, las CNN son versátiles y se pueden aplicar a una variedad de otros dominios, como procesamiento de lenguaje natural, análisis de series temporales y reconocimiento de voz.
Implementando una CNN con PyTorch.
Ahora que estás familiarizado con la teoría de las CNNs, estamos listos para ponernos manos a la obra. En esta sección, construiremos y entrenaremos una CNN simple con PyTorch. Nuestro objetivo es construir un modelo para clasificar dígitos en imágenes. Para entrenar y probar nuestro modelo, utilizaremos el famoso conjunto de datos MNIST, una colección de 70,000 imágenes en escala de grises de 28×28 píxeles con dígitos escritos a mano.
1. Importación de bibliotecas requeridas
A continuación puedes encontrar las bibliotecas que utilizaremos en este tutorial. En esencia, aprovecharemos PyTorch para construir nuestra CNN, y el módulo de visión por computadora de PyTorch torchvision
, para descargar y cargar el conjunto de datos MNIST. Finalmente, también utilizaremos torchmetrics
para evaluar el rendimiento de nuestro modelo.
import numpy as np import pandas as pd import matplotlib.pyplot as plt import torch from torch import optim from torch import nn from torch.utils.data import DataLoader from tqdm import tqdm # !pip install torchvision import torchvision import torch.nn.functional as F import torchvision.datasets as datasets import torchvision.transforms as transforms # !pip install torchmetrics import torchmetrics
2. Carga y preprocesamiento del conjunto de datos
PyTorch también cuenta con un rico ecosistema de herramientas y extensiones, incluido torchvision, un módulo para visión por computadora. Torchvision incluye varios conjuntos de datos de imágenes que se pueden utilizar para entrenar y probar redes neuronales. En nuestro tutorial, utilizaremos el conjunto de datos MNIST.
Primero, descargaremos y convertiremos el conjunto de datos MNIST en un tensor, la estructura de datos principal en PyTorch, similar a los arrays de NumPy pero con capacidades de aceleración de GPU.
Entonces, también utilizaremos DataLoader para manejar el agrupamiento y la mezcla de los conjuntos de datos de entrenamiento y prueba. Un DataLoader de PyTorch puede crearse a partir de un Dataset para cargar datos, dividirlos en lotes y realizar transformaciones en los datos si se desea. Luego, genera una muestra de datos lista para el entrenamiento. En el código a continuación, cargamos los datos y los guardamos en DataLoaders con un tamaño de lote de 60 imágenes:
batch_size = 60 train_dataset = datasets.MNIST(root="dataset/", download=True, train=True, transform=transforms.ToTensor()) train_loader = DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=True) test_dataset = datasets.MNIST(root="dataset/", download=True, train=False, transform=transforms.ToTensor()) test_loader = DataLoader(dataset=test_dataset, batch_size=batch_size, shuffle=True)
Opcionalmente, el conjunto de datos de entrenamiento podría dividirse aún más en dos particiones de entrenamiento y validación. La validación es una técnica utilizada en el aprendizaje profundo para evaluar el rendimiento del modelo durante el entrenamiento. Ayuda a detectar posibles sobreajustes y subajustes de nuestros modelos, y es particularmente útil para optimizar hiperparámetros. Sin embargo, por simplicidad, no utilizaremos la validación para este tutorial. Si deseas aprender más sobre la validación, puedes consultar una explicación completa en nuestro Curso de Introducción al Aprendizaje Profundo con PyTorch.
Ahora que tenemos nuestros datos, veamos cómo se ven un lote aleatorio de dígitos:
def imshow(img): npimg = img.numpy() plt.imshow(np.transpose(npimg, (1, 2, 0))) plt.show() # obtener algunas imágenes de entrenamiento aleatorias dataiter = iter(dataloader_train) images, labels = next(dataiter) labels # mostrar imágenes imshow(torchvision.utils.make_grid(images))
3. Definición de la arquitectura de la CNN
Para resolver el problema de clasificación, aprovecharemos la clase nn.Module
, el bloque de construcción de PyTorch para crear de manera intuitiva arquitecturas de redes neuronales sofisticadas.
En el código a continuación, creamos una clase llamada CNN
, que hereda las propiedades de la clase nn.Module
. La clase CNN
será el modelo de una CNN con dos capas convolucionales, seguidas de una capa totalmente conectada.
En PyTorch, utilizamos nn.Conv2d
para definir una capa convolucional. Le pasamos el número de mapas de características de entrada y salida. También configuramos algunos de los parámetros para que la capa convolucional funcione, incluido el tamaño del kernel o filtro y el relleno.
A continuación, agregamos una capa de max pooling con nn.MaxPool2d
. En ella, deslizamos una ventana no superpuesta sobre la salida de la capa convolucional anterior. En cada posición, seleccionamos el valor máximo de la ventana para pasar hacia adelante. Esta operación reduce las dimensiones espaciales de los mapas de características, lo que reduce el número de parámetros y la complejidad computacional en la red. Finalmente, agregamos una capa lineal totalmente conectada.
La función forward()
define cómo se conectan las diferentes capas, agregando varias funciones de activación ReLU después de cada capa convolucional.
class CNN(nn.Module): def __init__(self, in_channels, num_classes): """ Building blocks of convolutional neural network. Parameters: * in_channels: Number of channels in the input image (for grayscale images, 1) * num_classes: Number of classes to predict. In our problem, 10 (i.e digits from 0 to 9). """ super(CNN, self).__init__() # 1ra capa convolucional self.conv1 = nn.Conv2d(in_channels=in_channels, out_channels=8, kernel_size=3, padding=1) # Capa de agrupación máxima self.pool = nn.MaxPool2d(kernel_size=2, stride=2) # 2da capa convolucional self.conv2 = nn.Conv2d(in_channels=8, out_channels=16, kernel_size=3, padding=1) # Capa completamente conectada self.fc1 = nn.Linear(16 * 7 * 7, num_classes) def forward(self, x): """ Define the forward pass of the neural network. Parameters: x: Input tensor. Returns: torch.Tensor The output tensor after passing through the network. """ x = F.relu(self.conv1(x)) # Aplicar primera convolución y activación ReLU x = self.pool(x) # Aplicar agrupación máxima x = F.relu(self.conv2(x)) # Aplicar segunda convolución y activación ReLU x = self.pool(x) # Aplicar agrupación máxima x = x.reshape(x.shape[0], -1) # Aplanar el tensor x = self.fc1(x) # Aplicar capa completamente conectada return x x = x.reshape(x.shape[0], -1) # Aplanar el tensor x = self.fc1(x) # Aplicar capa completamente conectada return x
Una vez que hemos definido la clase CNN
, podemos crear nuestro modelo y moverlo al dispositivo donde se entrenará y ejecutará.
Las redes neuronales, incluidas las CNN, muestran un mejor rendimiento al ejecutarse en GPUs, pero puede que no sea el caso en tu computadora. Por lo tanto, ejecutaremos el modelo en una GPU solo cuando esté disponible; de lo contrario, utilizaremos una CPU regular.
device = "cuda" if torch.cuda.is_available() else "cpu" model = CNN(in_channels=1, num_classes=10).to(device) print(model) >>> CNN( (conv1): Conv2d(1, 8, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (pool): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False) (conv2): Conv2d(8, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (fc1): Linear(in_features=784, out_features=10, bias=True) )
4. Entrenando el modelo de CNN
Ahora que tenemos nuestro modelo, es hora de entrenarlo. Para hacerlo, primero necesitaremos determinar cómo mediremos el rendimiento del modelo. Dado que estamos tratando con un problema de clasificación multiclase, utilizaremos la función de pérdida de entropía cruzada, disponible en PyTorch como nn.CrossEntropyLoss
. También utilizaremos el optimizador Adam, uno de los algoritmos de optimización más populares.
# Definir la función de pérdida criterion = nn.CrossEntropyLoss() # Definir el optimizador optimizer = optim.Adam(model.parameters(), lr=0.001)
Iteraremos durante diez épocas y lotes de entrenamiento para entrenar el modelo y realizar la secuencia habitual de pasos para cada lote, como se muestra a continuación.
num_epochs=10 for epoch in range(num_epochs): # Iterar sobre los lotes de entrenamiento print(f"Epoch [{epoch + 1}/{num_epochs}]") for batch_index, (data, targets) in enumerate(tqdm(dataloader_train)): data = data.to(device) targets = targets.to(device) scores = model(data) loss = criterion(scores, targets) optimizer.zero_grad() loss.backward() optimizer.step()
Epoch [1/10] 100%|██████████| 1000/1000 [00:13<00:00, 72.94it/s] Epoch [2/10] 100%|██████████| 1000/1000 [00:12<00:00, 77.27it/s] Epoch [3/10] 100%|██████████| 1000/1000 [00:12<00:00, 77.16it/s] Epoch [4/10] 100%|██████████| 1000/1000 [00:12<00:00, 77.00it/s] Epoch [5/10] 100%|██████████| 1000/1000 [00:13<00:00, 75.69it/s] Epoch [6/10] 100%|██████████| 1000/1000 [00:12<00:00, 77.24it/s] Epoch [7/10] 100%|██████████| 1000/1000 [00:12<00:00, 78.23it/s] Epoch [8/10] 100%|██████████| 1000/1000 [00:12<00:00, 78.16it/s] Epoch [9/10] 100%|██████████| 1000/1000 [00:12<00:00, 77.96it/s] Epoch [10/10] 100%|██████████| 1000/1000 [00:12<00:00, 77.93it/s]
5. Evaluando el modelo
Una vez que el modelo esté entrenado, podemos evaluar su rendimiento en el conjunto de datos de prueba. Utilizaremos la precisión, una métrica popular para problemas de clasificación. La precisión mide la proporción de casos clasificados correctamente del número total de objetos en el conjunto de datos. Se calcula dividiendo el número de predicciones correctas por el número total de predicciones realizadas por el modelo.
Primero, configuramos la métrica de precisión desde torchmetrics. Luego, utilizamos el método .eval del modelo para ponerlo en modo de evaluación, ya que algunas capas en los modelos de PyTorch se comportan de manera diferente en las etapas de entrenamiento versus pruebas. También añadimos un contexto de Python con torch.no_grad
, indicando que no realizaremos cálculos de gradiente.
Después, iteramos sobre ejemplos de prueba sin cálculo de gradiente. Para cada lote de prueba, obtenemos las salidas del modelo, tomamos la clase más probable y la pasamos a la función de precisión junto con las etiquetas. Finalmente, calculamos las métricas e imprimimos los resultados. Obtenemos una puntuación de precisión de 0,98, lo que significa que nuestro modelo clasificó correctamente el 98% de los dígitos. ¡No está mal!
# Configuración de la métrica de precisión multiclase acc = Accuracy(task="multiclass",num_classes=10) # Iterar sobre los lotes del conjunto de datos model.eval() with torch.no_grad(): for images, labels in dataloader_test: # Obtener las probabilidades predichas para el lote de datos de prueba outputs = model(images) _, preds = torch.max(outputs, 1) acc(preds, labels) precision(preds, labels) recall(preds, labels) # Calcular la precisión total de la prueba test_accuracy = acc.compute() print(f"Test accuracy: {test_accuracy}") >>> Test accuracy: 0.9857000112533569
También podrías utilizar otras métricas de clasificación populares, incluyendo la recuperación y la precisión. Te contamos todo sobre estas métricas con ejemplos prácticos en nuestro Curso Intermedio de Deep Learning con PyTorch.
Mejorando el Rendimiento del Modelo
Aunque nuestro modelo CNN logra un rendimiento sólido, existen varias estrategias que podemos utilizar para mejorar aún más su precisión, robustez y generalización a nuevos datos.
En esta sección, exploraremos técnicas clave como la augmentación de datos, ajuste de hiperparámetros y aprendizaje por transferencia para optimizar el rendimiento de nuestro modelo.
Técnicas de augmentación de datos
Augmentación de datos es una técnica utilizada para mejorar la precisión de nuestro modelo al crear aleatoriamente nuevos datos de entrenamiento. Por ejemplo, durante la carga, se pueden aplicar transformaciones a las imágenes de entrenamiento, como cambiar el tamaño, voltear horizontal o verticalmente, rotación aleatoria, y así sucesivamente. De esta manera, se pueden crear imágenes aumentadas y asignarles la misma etiqueta que la imagen original, aumentando así el tamaño del conjunto de entrenamiento.
Agregar transformaciones aleatorias a las imágenes originales nos permite generar más datos mientras aumentamos el tamaño y la diversidad del conjunto de entrenamiento. Esto hace que el modelo sea más robusto a las variaciones y distorsiones comúnmente encontradas en imágenes del mundo real, y reduce el sobreajuste a medida que el modelo aprende a ignorar las transformaciones aleatorias.
Sin embargo, es importante tener cuidado con la augmentación de datos, ya que a veces puede perjudicar el proceso de entrenamiento. Por ejemplo, en nuestro problema, si aplicamos el volteo vertical al número “6”, se verá como el número “9”. Pasarlo al modelo etiquetado como “6” confundirá al modelo y obstaculizará el entrenamiento. Estos ejemplos muestran que, a veces, las augmentaciones específicas pueden afectar la etiqueta.
Ajuste de hiperparámetros
Otra estrategia para mejorar el rendimiento de nuestro modelo es cambiando los valores de los hiperparámetros involucrados en las diferentes capas del modelo. Este ajuste de hiperparámetros requiere una comprensión profunda de las matemáticas detrás de las redes neuronales y la importancia de los diferentes hiperparámetros.
Por ejemplo, podrías ajustar tus capas de CNN cambiando el tamaño de los filtros o aumentando el padding. También podrías establecer un valor diferente para los pesos iniciales de las neuronas.
Dado que no conoceremos los valores óptimos de los hiperparámetros de antemano, se requerirá un cierto grado de prueba y error. Esto se suele hacer a través de una técnica conocida como búsqueda en cuadrícula, que te permite evaluar sistemáticamente un modelo a través de una cuadrícula de valores de parámetros.
Sin embargo, ten cuidado al utilizar esta técnica, ya que normalmente es computacionalmente costosa, especialmente al tratar con redes neuronales complejas y grandes conjuntos de datos de entrenamiento.
Igualmente, podrías aumentar la complejidad de tu modelo añadiendo más capas convolucionales y lineales. Sin embargo, ten cuidado al agregar nuevas capas, ya que el número de neuronas puede aumentar drásticamente, lo que resulta en tiempos de entrenamiento más largos y posibles sobreajustes.
Puedes aprender más sobre el ajuste de hiperparámetros en nuestro Curso de Introducción al Aprendizaje Profundo con PyTorch.
Usando modelos preentrenados
Entrenar modelos de aprendizaje profundo desde cero es un proceso largo y tedioso, y típicamente requiere una gran cantidad de datos de entrenamiento. En lugar de eso, a menudo podemos usar modelos pre-entrenados, es decir, modelos que ya han sido entrenados en alguna tarea.
A veces, podemos reutilizar directamente un modelo pre-entrenado si ya puede resolver la tarea que nos interesa. En otras ocasiones, es posible que necesitemos ajustar el modelo pre-entrenado para que se adapte a la nueva tarea. Esto se conoce como transfer learning.
Usar modelos pre-entrenados en PyTorch es bastante sencillo. Torchvision proporciona una colección de modelos pre-entrenados para diversas tareas relacionadas con imágenes. Estos modelos están pre-entrenados en conjuntos de datos de imágenes a gran escala y están fácilmente disponibles. Echa un vistazo a nuestro Curso de Aprendizaje Profundo para Imágenes con PyTorch para aprender todo lo que necesitas saber sobre ellos.
Desplegando el Modelo CNN
Después de haber entrenado tu modelo de clasificación altamente preciso en PyTorch, ahora puedes guardar el modelo y sus pesos pre-entrenados para uso futuro y compartirlo con tu equipo, asegurándote de que puedan cargarlo sin problemas.
Para guardar un modelo, podemos usar torch.save
. Una extensión de archivo común para los modelos de torch es ya sea pt
o pth
. Para guardar los pesos del modelo, pasamos model.state_dict
a torch.save
proporcionando el nombre del archivo de salida, por ejemplo, MulticlassCNN.pth
.
Para cargar un modelo guardado, inicializamos un modelo nuevo con la misma arquitectura. Luego utilizamos el método de carga de estado dict
junto con torch.load
para cargar los parámetros en el nuevo modelo.
# Guardar el modelo torch.save(model.state_dict(), 'MulticlassCNN.pth') # Crear un modelo nuevo loaded_model = CNN(in_channels=1, num_classes=10) # Cargar el modelo guardado loaded_model.load_state_dict(torch.load('MulticlassCNN.pth')) print(loaded_model) CNN( (conv1): Conv2d(1, 8, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (pool): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False) (conv2): Conv2d(8, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (fc1): Linear(in_features=784, out_features=10, bias=True) )
Conclusión
Hemos cubierto una visión completa de las CNN, proporcionando detalles sobre cada capa de la arquitectura de la CNN. Además, brindamos una guía sobre cómo implementar una CNN en PyTorch, cubriendo los principales pasos, desde la carga de datos y el diseño del modelo hasta el entrenamiento y la evaluación del modelo. Finalmente, también analizamos varias estrategias para mejorar el rendimiento de nuestro modelo. Aplicamos todas estas habilidades a un escenario del mundo real relacionado con una tarea de clasificación multiclase.
Hay mucho por aprender sobre el aprendizaje profundo, posiblemente uno de los campos más emocionantes y exigentes en IA. Afortunadamente, DataCamp está aquí para ayudar. Consulta nuestros materiales y cursos dedicados y conviértete en un experto en redes neuronales:
- Una Introducción a las Redes Neuronales Convolucionales: Una Guía Integral de las CNN en Aprendizaje Profundo
- Redes Neuronales Convolucionales en Python con Keras
- Python Redes Neuronales Convolucionales (CNN) con Tutorial de TensorFlow
- Introducción a las Funciones de Activación en Redes Neuronales
- Domina el Aprendizaje Profundo para Texto con el Curso de PyTorch
- Aprendizaje Profundo en Python
- Cómo Aprender Aprendizaje Profundo en el 2025: Una Guía Completa
- Curso Intermedio de Aprendizaje Profundo con PyTorch
- Una Guía sobre Certificaciones y Diplomas de PyTorch
Source:
https://www.datacamp.com/tutorial/pytorch-cnn-tutorial