Redes neuronales convolucionales

Introducción

  • Las redes neuronales convolucionales están inspiradas en cómo funciona la visión humana.
  • Las redes convolucionales trabajan con imágenes, aunque se pueden utilizar en otros ámbitos.
  • Las redes convolucionales son capaces de «reconocer» la relación entre regiones de una imagen, también temporales si lo que se analiza es una secuencia de vídeo.

Objetivos de aprendizaje

  • Resumir en qué consisten las principales tareas de la visión por computador.
  • Definir las bases de las redes neuronales convolucionales: convoluciones y pooling.
  • Construir una red neuronal convolucional utilizando Keras y Tensorflow.
  • Valorar si existe sobreajuste durante el proceso de entrenamiento.
  • Describir algunas de las arquitecturas de redes neuronales convolucionales más importantes.

Objetivos de aprendizaje

  • Utilizar la arquitectura YOLO para tareas de visión por computador.
  • Resumir en qué consiste la transferencia de aprendizaje.
  • Construir un modelo utilizando transferencia de aprendizaje.

Referencias

  1. Hands-on machine learning… Aurélien Géron.
  2. Deep Learning, Ian Goodfellow, Joshua Bengio and Aaron Courbille.
  3. Dive into deep learning, Aston Zhang et al.

Redes neuronales en visión por ordenador

Introducción

La visión por computador es una disciplina con una gran trayectoria en las Ciencias de la Computación.

Introducción

Utilizar redes densas en visión por computador es impracticable. El tamaño de una imagen, en píxeles, determina el número de neuronas en la capa de entrada y posteriores.

El número de parámetros que es necesario entrenar es muy elevado.

Introducción

Las redes neuronales convolucionales están inspiradas en el funcionamiento de la percepción de la visión:

Introducción

Las redes convolucionales proponen una solución basada en dos elementos:

  1. Utilizar convoluciones para aprender las características relevantes de las imágenes.
  2. Utilizar pooling para reducir el tamaño de las imágenes.

Además, en muchos casos las últimas capas de una red convolucional están formadas por capas densas.

Esto permite utilizar redes neuronales en las tareas típicas de la visión por computador.

Introducción

Las tareas típicas dentro de la visión por computador son:

  • Clasificación.
  • Ubicación.
  • Detección de objetos.
  • Seguimiento de objetos.
  • Segmentación semántica.

Clasificación

Un modelo de clasificación está entrenado de tal modo que es capaz de asignar una clase, o etiqueta, a una nueva muestra.

Perro

Gato

Ubicación

Encontrar la caja delimitadora de un objeto dentro de una imagen:

Detección de objetos

Encontrar todos los objetos dentro de una imagen:

Seguimiento de objetos

Segmentación semántica

Asigna cada pixel a uno de los objetos detectados.

Fundamentos de la CNN

Convoluciones

Una convolución es una operación entre los píxeles de una imagen. En estos dos casos, el paso es de 1 pixel. La figura de la derecha muestra la opción con márgenes añadidos.

Convoluciones

En este otro caso, el paso es de 2 píxeles.

Convoluciones

Las imágenes en color tienen tres canales: rojo, verde y azul. Las convoluciones pueden ser distintas para cada uno de los canales.

Convoluciones

Ejemplo de convolución que emborrona una imagen:

\[ \begin{equation} \frac{1}{9} \begin{bmatrix} 1 & 1 & 1 \\ 1 & 1 & 1 \\ 1 & 1 & 1 \\ \end{bmatrix} \end{equation} \]

Convoluciones

Ejemplo de convolución que resalta los bordes:

\[ \begin{equation} \frac{1}{9} \begin{bmatrix} 0 & -1 & 0 \\ -1 & 4 & -1 \\ 0 & -1 & 0 \\ \end{bmatrix} \end{equation} \]

Convoluciones

Lo que va a aprender la red convolucional es a ajustar los valores de las matrices de convolución:

\[ \begin{equation} \begin{bmatrix} m_{1,1} & m_{1,2} & m_{1,3} \\ m_{2,1} & m_{2,2} & m_{2,3}\\ m_{3,1} & m_{3,2} & m_{3,3} \\ \end{bmatrix} \end{equation} \]

Show me the code

Para instanciar una capa convolucional en Keras:

tf.keras.layers.Conv2D(6, 
                    kernel_size=(5, 5), 
                    strides=(1, 1), 
                    activation='tanh', 
                    input_shape=[28, 28, 1], 
                    padding="same")
  • El primer número 6 indica el número de subcapas de convolución.

Show me the code

tf.keras.layers.Conv2D(6, 
                    kernel_size=(5, 5), 
                    strides=(1, 1), 
                    activation='tanh', 
                    input_shape=[28, 28, 1], 
                    padding="same")
  • kernel_size: es el tamaño del kernel ancho x alto.
  • strides: es el tamaño del salto en horizontal y vertical.
  • input_shape: es el tamaño de la (imagen de) entrada ancho, alto y profundidad, en este caso la imagen es b/n y sólo hay una capa de color.

Show me the code

  • padding: se añaden píxeles nulos para que la imagen de la salida sea \(ancho_{entrada}/salto\).

Pooling

El número de parámetros que hay que entrenar crece al aplicar capas de convoluciones. Una manera de reducir el número de parámetros es aplicar capas de pooling:

Show me the code

Keras nos proporciona capas para poder hacer pooling.

Para instanciar capas de pooling máximo en Keras:

keras.layers.MaxPool2D(pool_size=2)

Para instanciar capas de pooling promedio en Keras:

keras.layers.AvgPool(pool_size=2)

En ambos casos pool_size es el tamaño del lado del cuadrado de recorte.

Con estos dos nuevos tipos de capas podemos crear redes convolucionales.

Arquitecturas

Arquitectura básica de una CNN

Esta es la arquitectura básica de una CNN. Observa cómo se van alternando las capas convolucionales con las capas de pooling.

Al final hay una estructura de capas totalmente conectadas.

LeNet5

Esta es la arquitectura original presentada por Yann Le-Cunn et al.

Las Gaussian connections del final son la activación softmax.

LeNet5

La implementación:

lenet5 = tf.keras.models.Sequential([
    tf.keras.layers.Conv2D(6, kernel_size=(5, 5), 
                            strides=(1, 1), activation='tanh', 
                            input_shape=[28, 28, 1], padding="same"),
    tf.keras.layers.AveragePooling2D(pool_size=(2, 2), 
                            strides=(2, 2), padding='valid'),
    tf.keras.layers.Conv2D(16, kernel_size=(5, 5), 
                            strides=(1, 1), activation='tanh', 
                            padding='valid'),
    tf.keras.layers.AveragePooling2D(pool_size=(2, 2), 
                            strides=(2, 2), padding='valid'),
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dense(120, activation='tanh'),
    tf.keras.layers.Dense(84, activation='tanh'),
    tf.keras.layers.Dense(units=10, activation='softmax')
])

En este libro de Colab tienes una implementación de LeNet5.

LeNet5

MINIST es el conjunto con el que se entrenó LeNet5:

LeNet5

Si entrenamos LeNet5 con el conjunto MNIST, utilizando como función de activación la función tanh y como optimizador Stocastic Gradient Descent (SGD), durante 20 épocas, obtenemos una precisión sobre el conjunto de pruebas del 98%!!!.

Historia

Matriz de confusión

LeNet5

Si utilizamos como función de activación la función relu y como optimizador Adam, durante 20 épocas, obtenemos una precisión sobre el conjunto de pruebas de casi el 99%.

Historia

Matriz de confusión

LeNet5

Aquí puedes comparar el desempeño de ambas implementaciones:

Tanh + sgd (precisión: 98%)

ReLu + Adam (precision: 99%)

LeNet5

Algunos ejemplos:

[1.0795905e-19 5.6615489e-12 1.5740088e-13 8.3432508e-14 8.5658287e-16 9.8535682e-16 3.1860348e-19 1.0000000e+00 1.1258355e-17 3.4307670e-12]

LeNet5

Algunos ejemplos:

[3.57783143e-16 4.28349088e-13 1.00000000e+00 1.95093300e-16 8.98499199e-17 1.41323059e-23 1.89028567e-12 1.19629157e-14 2.68268784e-17 1.12507135e-17]

LeNet5

En este vídeo, de 1989, tienes una demo.

LeNet5

Podemos probar con un conjunto de datos más difícil Fashion MNIST, que tiene el mismo número de imágenes que MNIST, pero esta vez de objetos más complejos, ropa y complementos (10 clases).

LeNet5

La historia del entrenamiento y la matriz de confusión:

Tanh + sgd (precisión: 88%)

Matriz de confusión

ResNet

ResNet introdujo una novedad en su diseño para reducir el problema del desvanecimiento del gradiente. La novedad es en saltar capas:

\[ H(x) = F(x) + x \rightarrow F(x) = H(x) - x \]

ResNet

Lo que aprenden las dos capas intermedias de la figura (representadas por la función \(F(x)\)) es a ajustar la diferencia entre la entrada real a la capa y el resultado de la aplicación de la capa.

Show me the code

Keras proporciona una implementación de ResNet perfectamente funcional:

resetnet50 = tf.keras.applications.ResNet50(weights="imagenet")
path = "bicicleta2.jpg"
img = tf.keras.preprocessing.image.load_img(path, target_size=[224, 224])

x = tf.keras.utils.img_to_array(img)
x = np.expand_dims(x, axis=0)
x = tf.keras.applications.resnet50.preprocess_input(x)
y = resetnet50.predict(x)
print("Predicción: ", tf.keras.applications.resnet50.decode_predictions(y, top=3)[0])

ImageNet es un conjunto de datos con 1.000 clases , 1.281.167 imágenes de entrenamiento, 50.000 imágenes de validación y 100.000 imágenes de prueba.

Otras redes

En Keras hay implementadas y entrenadas un buen número de redes.

Aquí tienes la lista de todas las redes convolucionales disponibles en Keras.

YOLO - You Only Look Once

YOLO

You Only Look Once (YOLO) es una red convolucional con un gran desempeño en muchas de la tareas típicas en visión por computador.

YOLO es mantenida por la empresa Ultralytics.

Este es el artículo donde se presentó esta arquitectura de red neuronal.

YOLO

Y esta es la arquitectura tal y como se presenta en el artículo:

YOLO

Una de la novedades de YOLO es que a la salida propociona la caja envolvente de los objetos detectados, así como la probabilidad de su clasificación, y también es capaz de realizar segmentación semántica.

YOLO se presenta en varias versiones, basándose en el número de parámetros presente en la red (tamaño). Las versiones más pequeñas tienen en desempeño más bajo que las versiones grandes, pero, como contrapartida, se pueden ejecutar en dispositivos con hardware más modesto.

Todas las versiones están entrenadas con el cojunto de datos COCO.

Show me the code

Para comparar las prestaciones de cada modelo, vamos a empezar con el de menor tamaño, 2.6 millones de parámetros y tarea de detección:

from ultralytics import YOLO

modelo = YOLO("Modelos/yolo11n.pt")
ruta = "./Imagenes/imagen"
resultado = modelo(ruta)
resultado[0].show()

El tiempo de inferencia, en mi portátil, es de 36.1 ms.

Show me the code

Veamos ahora con el mayor modelo, 56.9 millones de parámetros

from ultralytics import YOLO

modelo = YOLO("Modelos/yolo11x.pt")
ruta = "./Imagenes/imagen"
resultado = modelo(ruta)
resultado[0].show()

El tiempo de inferencia, en mi portátil, es de 360.0 ms.

Show me the code

Pasemos ahora a la segmentación semántica, lo único que tenemos que hacer es cambiar el modelo, el resto de código es el mismo:

modelo = YOLO("Modelos/yolo11n-seg.pt")

El tiempo de inferencia, en mi portátil, es de 54.3 ms.

Show me the code

Con el modelo más grande para segmentación:

modelo = YOLO("Modelos/yolo11x-seg.pt")

El tiempo de inferencia, en mi portátil, es de 520.8 ms.

Show me the code

YOLO también es capaz de encontrar el esqueleto:

modelo = YOLO("Modelos/yolo11x-pose.pt")

El tiempo de inferencia, en mi portátil, es de 35.7 ms.

Transferencia de aprendizaje

Transferencia de aprendizaje

Entrenar una red convolucional desde cero es una tarea muy costosa:

  • Se necesita un conjunto de datos etiquetado muy grande (cientos de miles de imágenes).
  • Se necesitan recursos hardware que no son comunes.
  • Se necesita tiempo de entrenamiento.
  • Se necesita energía para alimentar el hardware.

Sin embargo, existe un atajo para poder (re)entrenar redes convolucionales ya existentes sobre conjuntos de datos, de nuestro interés, para tareas específicas.

Transferencia de aprendizaje

El atajo consiste en lo siguiente:

  1. Utilizar una arquitectura inicial ya entrenada.
  2. Eliminar las capas más cercanas a la salida y sustituirlas por nuevas capas adaptadas a nuestro problema.
  3. Durante la fase de entrenamiento:
    1. Congelar los pesos de las capas preexistentes.
    2. Entrenar durante unas épocas hasta que la precisión sobre el conjunto de validación se estabilice.
    3. Descongelar todas las capas y entrenar hasta conseguir una buena precisión.

Show me the code

  1. Utilizar una arquitectura ya entrenada, y eliminar la última capa
modelo = tf.keras.applications.ResNet50(weights="imagenet", include_top=False)
  1. Añadir nuevas capas adaptadas a nuestro problema.
avg = keras.layers.GlobalAveragePooling2D()(modelo.output)
salida = keras.layers.Dense(n_classes, activation="softmax")(avg)
modelo = keras.Model(inputs=modelo.input, outputs=salida)

Show me the code

3.1. Congelar los pesos de las capas preexistentes.

for capa in modelo.layers:
    capa.trainable = False

3.2. Entrenar hasta que la precisión sobre el conjunto de validación se estabilice.

optimizador = keras.optimizers.SGD(lr=0.2, momentum=0.9, decay=0.01)
modelo.compile(loss="sparse_categorical_crossentropy", optimizer=optimizador,
    metrics=["accuracy"])
historia = modelo.fit(train_set, epochs=5, validation_data=valid_set)

Show me the code

3.3. Descongelar todas las capas y entrenar hasta conseguir una buena precisión.

for capa in modelo.layers:
    capa.trainable = True

optimizador = keras.optimizers.SGD(lr=0.2, momentum=0.9, decay=0.001)
modelo.compile(loss="sparse_categorical_crossentropy", optimizer=optimizador,
    metrics=["accuracy"])
historia = modelo.fit(train_set, epochs=5, validation_data=valid_set)

Transferencia de aprendizaje con YOLO

Con YOLO tenemos dos opciones para reentrenas modelos:

  1. Utilizar un conjunto de datos disponible a través de Ultralytics.
from ultralytics import YOLO

# Cargar un modelo existente
modelo = YOLO("yolo11n.pt")  

# Entrenar con un conjunto de datos disponible
resultados = modelo.train(data="coco8.yaml", epochs=100, imgsz=640)

Transferencia de aprendizaje con YOLO

  1. Utilizar nuestro propio conjunto de datos.
# Train/val/test sets as 1) dir: path/to/imgs, 2) file: path/to/imgs.txt, or 3) list: [path/to/imgs1, path/to/imgs2, ..]
path: ../datasets/coco8 # dataset root dir
train: images/train # train images (relative to 'path') 4 images
val: images/val # val images (relative to 'path') 4 images
test: # test images (optional)

# Classes (80 COCO classes)
names:
    0: person
    1: bicycle
    2: car
    # ...
    77: teddy bear
    78: hair drier
    79: toothbrush

Transferencia de aprendizaje con YOLO

Ultralytics espera la siguiente estructura en los datos de entrenamiento:

Show me the result

Este es un ejemplo del trabajo de Arturo, estudiante de máster:

Resumen

  • Las redes convolucionales introducen dos técnicas para trabajar con imágenes:
    • Convoluciones.
    • Pooling.
  • Hemos revisado algunas de las arquitecturas más interesantes.
  • Hemos visto con detalle el trabajo con YOLO.
  • La transferencia de aprendizaje nos permite adaptar redes existentes para trabajar en problemas específicos.

Recursos