Continuando con mi serie sobre la construcción de redes neuronales convolucionales clásicas que revolucionaron el campo de la visión por computadora en los últimos 1-2 decenios, en la próxima parte construiremos VGG, una red neuronal convolucional muy profunda, desde cero utilizando PyTorch. Puede ver los artículos anteriores de la serie en mi perfil, principalmente LeNet5 y AlexNet.
Como antes, examinaremos la arquitectura y la intuión detrás de VGG y cómo los resultados eran en aquel entonces. Luego, exploraremos nuestro conjunto de datos, CIFAR100, y cargaremoslo en nuestro programa utilizando código eficiente en memoria. A continuación, implementaremos VGG16 (el número se refiere al número de capas, existen dos versiones básicas: VGG16 y VGG19) desde cero utilizando PyTorch y entrenaremosla con nuestro conjunto de datos, además de evaluarla en nuestro conjunto de prueba para ver cómo se comporta con datos no vistos
VGG
Sobre la base del trabajo de AlexNet, VGG se enfoca en otro aspecto crucial de las redes neuronales convolucionales (CNNs), la profundidad. Fue desarrollado por Simonyan y Zisserman. Normalmente consta de 16 capas convolucionales, pero también se puede ampliar a 19 capas (de ahí las dos versiones, VGG-16 y VGG-19). Todas las capas convolucionales consisten en filtros de 3×3. Puede leer más sobre la red en el artículo oficial aquí
arquitectura VGG16. Fuente
Carga de Datos
Conjunto de Datos
Antes de construir el modelo, una de las cosas más importantes en cualquier proyecto de Aprendizaje Automático es cargar, analizar y preprocesar el conjunto de datos. En este artículo, utilizaremos el conjunto de datos CIFAR-100. Este conjunto de datos es muy similar al CIFAR-10, excepto que tiene 100 clases con 600 imágenes cada una. Hay 500 imágenes de entrenamiento y 100 imágenes de prueba por clase. Las 100 clases en el CIFAR-100 están agrupadas en 20 superclases. Cada imagen viene con una etiqueta “fina” (la clase a la que pertenece) y una etiqueta “cruzada” (la superclase a la que pertenece). Aquí usaremos la etiqueta “fina”. Aquí está la lista de clases en el CIFAR-100:
Lista de Clases para el Conjunto de Datos CIFAR-100
Importando las bibliotecas
Principalmente trabajaremos con torch
(utilizado para construir el modelo y entrenar), torchvision
(para cargar/procesar datos, contiene conjuntos de datos y métodos para procesar estos conjuntos de datos en computación visual) y numpy
(para manipulación matemática). También definiremos una variable device
para que el programa pueda utilizar la GPU si está disponible.
Cargando los Datos
torchvision
es una biblioteca que proporciona fácil acceso a toneladas de conjuntos de datos de visión computacional y métodos para preprocesar estos conjuntos de datos de manera fácil e intuitiva
- Definimos una función
data_loader
que devuelve datos de entrenamiento/validación o de prueba dependiendo de los argumentos - Empezamos definiendo la variable
normalize
con las media y desviaciones típicas de cada uno de los canales (rojo, verde y azul) en el conjunto de datos. Estos pueden calcularse manualmente, pero también están disponibles en línea. Esto se utiliza en la variabletransform
donde reembolsamos los datos, los convertimos en tensores y luego los normalizamos - Si el argumento
test
es verdadero, simplemente cargamos la partición de prueba del conjunto de datos y lo devolvemos usando cargadores de datos (explicado a continuación) - En caso de que
test
sea falso (comportamiento predeterminado también), cargamos la partición de entrenamiento del conjunto de datos y lo dividimos aleatoriamente en entrenamiento y validación (0.9:0.1) - Finalmente, hacemos uso de los cargadores de datos. Esto puede no afectar el rendimiento en el caso de un pequeño conjunto de datos como CIFAR100, pero realmente puede impedir el rendimiento en caso de grandes conjuntos de datos y generalmente se considera una buena práctica. Los cargadores de datos nos permiten iterar sobre los datos en lotes, y los datos se cargaron mientras iteraba y no todo a la vez en el inicio de su RAM
VGG16 desde cero
Para construir el modelo desde cero, primero necesitamos entender cómo funcionan las definiciones de modelos en torch
y los diferentes tipos de capas que utilizaremos aquí:
- Cada modelo personalizado debe heredar de la clase
nn.Module
ya que proporciona algunas funciones básicas que ayudan al modelo a entrenarse. - En segundo lugar, hay dos cosas principales que debemos hacer. Primero, definir las diferentes capas de nuestro modelo dentro de la función
__init__
y la secuencia en la que estas capas serán ejecutadas en el input dentro de la funciónforward
Vamos a definir ahora los diferentes tipos de capas que estamos utilizando aquí:
nn.Conv2d
: Estas son las capas convolucionales que aceptan el número de canales de entrada y salida como argumentos, junto con el tamaño del kernel para el filtro. También acepta cualquier strides o relleno si quieres aplicar esosnn.BatchNorm2d
: Esto aplica la normalización por lotes al output de la capa convolucionalnn.ReLU
: Esta es la activación aplicada a varios outputs en la red.nn.MaxPool2d
: Esto aplica max pooling a la salida con el tamaño del kernel dadonn.Dropout
: Esto se utiliza para aplicar dropout a la salida con una probabilidad dadann.Linear
: Esto es básicamente una capa completamente conectadann.Sequential
: Esto técnicamente no es un tipo de capa, pero ayuda en la combinación de diferentes operaciones que forman parte del mismo paso
Usando este conocimiento, ahora podemos construir nuestro modelo VGG16 utilizando la arquitectura descrita en el documento:
VGG16 desde cero
Hipotecarios
Una de las partes importantes de cualquier proyecto de máquina o aprendizaje profundo es optimizar los hiperparámetros. Aquí, no experimentaremos con diferentes valores para esos, sino que tendremos que definirlos previo mente. Estos incluyen definir el número de épocas, el tamaño de lote, la tasa de aprendizaje, la función de pérdida junto con el optimizador
Estableciendo los hiperparámetros
Entrenamiento
Ahora estamos listos para entrenar nuestro modelo. Primero veremos cómo entrenamos nuestro modelo en torch
y luego examinaremos el código:
- Para cada época, recorremos las imágenes y las etiquetas dentro de nuestro
train_loader
y movemos esas imágenes y etiquetas a la GPU si está disponible. Esto sucede automáticamente - Usamos nuestro modelo para predecir sobre las etiquetas (
model(images)
) y luego calculamos la pérdida entre las predicciones y las etiquetas verdaderas usando nuestra función de pérdida (criterion(outputs, labels)
) - Luego usamos esa pérdida para propagar hacia atrás (
loss.backward
) y actualizar las pesos (optimizer.step()
). Pero recuerda que debes establecer las gradientes en cero antes de cada actualización. Esto se hace usandooptimizer.zero_grad()
- También, al final de cada época usamos nuestro conjunto de validación para calcular la precisión del modelo. En este caso, no necesitamos gradientes así que usamos
with torch.no_grad()
para una evaluación más rápida
Ahora, combinamos todo esto en el siguiente código:
Entrenamiento
Podemos ver la salida del código anterior como se muestra a continuación, que muestra que el modelo está aprendiendo realmente ya que la pérdida disminuye con cada época:
Pérdidas de entrenamiento
Pruebas
Para las pruebas, utilizamos exactamente el mismo código que para la validación, pero con el test_loader
:
Pruebas
Usando el código anterior y entrenando el modelo durante 20 épocas, logramos alcanzar una precisión de 75% en el conjunto de prueba.
Conclusión
Ahora vamos a concluir lo que hemos hecho en este artículo:
- Empezamos entendiendo la arquitectura y los diferentes tipos de capas del modelo VGG-16
- A continuación, cargamos y preprocesamos el conjunto de datos CIFAR100 usando
torchvision
- Luego, usamos
PyTorch
para construir nuestro modelo VGG-16 desde cero, junto con la comprensión de diferentes tipos de capas disponibles entorch
- Finalmente, entrenamos y probamos nuestro modelo en el conjunto de datos CIFAR100, y el modelo pareció funcionar bien en el conjunto de prueba con un 75% de precisión
Trabajo futuro
Con este artículo, obtienes una buena introducción y aprendizaje práctico, pero aprenderás mucho más si extendes esto y veas qué otras cosas puedes hacer:
- Puedes probar con diferentes conjuntos de datos. Uno de estos conjuntos es CIFAR10 o una subcolección del conjunto de datos ImageNet.
- Puedes experimentar con diferentes hiperparámetros y ver la mejor combinación de ellos para el modelo
- Finalmente, puedes intentar agregar o eliminar capas del conjunto de datos para ver su impacto en la capacidad del modelo. Aún mejor, intenta construir la versión VGG-19 de este modelo.
Source:
https://www.digitalocean.com/community/tutorials/vgg-from-scratch-pytorch