Java >> Tutorial de Java >  >> Java

Cómo implementar una CNN con Deeplearning4j

1. Resumen

En este tutorial, construiremos y entrenaremos una red neuronal convolucional modelo utilizando la biblioteca Deeplearning4j en Java.

Para obtener más información sobre cómo configurar la biblioteca, consulte nuestra guía sobre Deeplearning4j.

2. Clasificación de imágenes

2.1. Declaración del problema

Supongamos que tenemos un conjunto de imágenes. Cada imagen representa un objeto de una clase particular. Además, el objeto de la imagen pertenece a la única clase conocida. Entonces, la declaración del problema es construir el modelo que podrá reconocer la clase del objeto en la imagen dada .

Por ejemplo, digamos que tenemos un conjunto de imágenes con diez gestos con las manos. Construimos un modelo y lo entrenamos para clasificarlos. Luego, después del entrenamiento, podemos pasar otras imágenes y clasificar los gestos de las manos en ellas. Por supuesto, el gesto dado debe pertenecer a las clases conocidas.

2.2. Representación de imágenes

En la memoria de la computadora, la imagen se puede representar como una matriz de números. Cada número es un valor de píxel, que va de 0 a 255.

Una imagen en escala de grises es una matriz 2D. De manera similar, la imagen RGB es una matriz 3D con dimensiones de ancho, alto y profundidad.

Como podemos ver, la imagen es un conjunto de números . Por lo tanto, podemos construir modelos de red multicapa para entrenarlos para clasificar imágenes.

3. Redes neuronales convolucionales

Una red neuronal convolucional (CNN) es un modelo de red multicapa que tiene una estructura específica. La estructura de una CNN se puede dividir en dos bloques:capas convolucionales y capas totalmente conectadas (o densas) . Veamos cada uno de ellos.

3.1. Capa convolucional

Cada capa convolucional es un conjunto de matrices cuadradas, llamadas núcleos . Sobre todo, los necesitamos para realizar la convolución en la imagen de entrada. Su cantidad y tamaño pueden variar, dependiendo del conjunto de datos dado. En su mayoría usamos núcleos de 3×3 o 5×5, y rara vez de 7×7. El tamaño y la cantidad exactos se seleccionan mediante prueba y error.

Además, seleccionamos aleatoriamente las variables de las matrices kernel al comienzo del tren. Son los pesos de la red.

Para realizar la convolución, podemos usar el núcleo como ventana deslizante. Multiplicaremos los pesos del núcleo por los píxeles de la imagen correspondiente y calcularemos la suma. Luego, podemos mover el kernel para cubrir la siguiente parte de la imagen usando stride (mover a la derecha) y padding (mover hacia abajo). Como resultado, tendremos valores que se utilizarán en cálculos posteriores.

En resumen, con esta capa, obtenemos una imagen convolucionada . Algunas variables pueden ser menores que cero. Esto generalmente significa que estas variables son menos importantes que las otras. Es por eso que aplicar la función ReLU es un buen enfoque para realizar menos cálculos.

3.2. Capa de submuestreo

La capa de submuestreo (o agrupación) es una capa de la red, generalmente utilizada después de la convolucional. Después de la convolución, obtenemos muchas variables calculadas . Sin embargo, nuestra tarea es elegir los más valiosos entre ellos .

El enfoque es aplicar un algoritmo de ventana deslizante a la imagen convolucionada. En cada paso elegiremos el valor máximo en la ventana cuadrada de un tamaño predefinido, normalmente entre 2×2 y 5×5 píxeles. Como resultado, tendremos menos parámetros calculados. Por lo tanto, esto reducirá los cálculos.

3.3. Capa densa

Una capa densa (o completamente conectada) es aquella que consta de múltiples neuronas. Necesitamos esta capa para realizar la clasificación. Además, puede haber dos o más de tales capas consecuentes. Es importante destacar que la última capa debe tener un tamaño igual al número de clases para la clasificación.

La salida de la red es la probabilidad de que la imagen pertenezca a cada una de las clases . Para predecir las probabilidades, utilizaremos la función de activación de Softmax.

3.4. Técnicas de optimización

Para realizar el entrenamiento, necesitamos optimizar los pesos. Recuerde, elegimos aleatoriamente estas variables inicialmente. La red neuronal es una gran función . Y tiene muchos parámetros desconocidos, nuestros pesos.

Cuando pasamos una imagen a la red, nos da la respuesta . Entonces, podemos construir una función de pérdida, que dependerá de esta respuesta . En términos de aprendizaje supervisado, también tenemos una respuesta real:la verdadera clase. Nuestra misión es minimizar esta función de pérdida . Si tenemos éxito, entonces nuestro modelo está bien entrenado.

Para minimizar la función, tenemos que actualizar los pesos de la red . Para hacer eso, podemos calcular la derivada de la función de pérdida con respecto a cada uno de estos parámetros desconocidos. Luego, podemos actualizar cada peso.

Podemos aumentar o disminuir el valor del peso para encontrar el mínimo local de nuestra función de pérdida porque conocemos la pendiente. Además, este proceso es iterativo y se llama Gradient Descent . La retropropagación utiliza el descenso de gradiente para propagar la actualización del peso desde el final hasta el principio de la red.

En este tutorial, utilizaremos el algoritmo de optimización Stochastic Gradient Decent (SGD). La idea principal es que elegimos aleatoriamente el lote de imágenes de trenes en cada paso. Luego aplicamos retropropagación.

3.5. Métricas de evaluación

Finalmente, después de entrenar la red, necesitamos obtener información sobre el desempeño de nuestro modelo.

La métrica más utilizada es la precisión . Esta es la relación entre las imágenes correctamente clasificadas y todas las imágenes. Mientras tanto, el recuerdo, la precisión y la puntuación F1 son métricas muy importantes para la clasificación de imágenes también.

4. Preparación del conjunto de datos

En esta sección, prepararemos las imágenes. Usemos el conjunto de datos CIFAR10 incrustado en este tutorial. Crearemos iteradores para acceder a las imágenes:

public class CifarDatasetService implements IDataSetService {

    private CifarDataSetIterator trainIterator;
    private CifarDataSetIterator testIterator;

    public CifarDatasetService() {
         trainIterator = new CifarDataSetIterator(trainBatch, trainImagesNum, true);
         testIterator = new CifarDataSetIterator(testBatch, testImagesNum, false);
    }

    // other methods and fields declaration

}

Podemos elegir algunos parámetros por nuestra cuenta. Entrenar por lotes y testBatch son los números de imágenes por tren y paso de evaluación respectivamente. Número de imágenes de tren y testImagesNum son los números de imágenes para entrenamiento y prueba. Una época dura trainImagesNum / entrenar por lotes pasos . Entonces, tener 2048 imágenes de trenes con un tamaño de lote =32 conducirá a 2048/32 =64 pasos por época.

5. Red neuronal convolucional en Deeplearning4j

5.1. Construyendo el modelo

A continuación, construyamos nuestro modelo CNN desde cero. Para hacerlo, usaremos capas convolucionales, de submuestreo (agrupación) y completamente conectadas (densas) .

MultiLayerConfiguration configuration = new NeuralNetConfiguration.Builder()
  .seed(1611)
  .optimizationAlgo(OptimizationAlgorithm.STOCHASTIC_GRADIENT_DESCENT)
  .learningRate(properties.getLearningRate())
  .regularization(true)
  .updater(properties.getOptimizer())
  .list()
  .layer(0, conv5x5())
  .layer(1, pooling2x2Stride2())
  .layer(2, conv3x3Stride1Padding2())
  .layer(3, pooling2x2Stride1())
  .layer(4, conv3x3Stride1Padding1())
  .layer(5, pooling2x2Stride1())
  .layer(6, dense())
  .pretrain(false)
  .backprop(true)
  .setInputType(dataSetService.inputType())
  .build();

network = new MultiLayerNetwork(configuration);

Aquí especificamos la tasa de aprendizaje, el algoritmo de actualización, el tipo de entrada de nuestro modelo y la arquitectura en capas . Podemos experimentar con estas configuraciones. Así, podemos entrenar muchos modelos con diferentes arquitecturas y parámetros de entrenamiento. Además, podemos comparar los resultados y elegir el mejor modelo.

5.2. Entrenando al modelo

Luego, entrenaremos el modelo construido. Esto se puede hacer en unas pocas líneas de código:

public void train() {
    network.init();    
    IntStream.range(1, epochsNum + 1).forEach(epoch -> {
        network.fit(dataSetService.trainIterator());
    });
}

El número de épocas es el parámetro que podemos especificar nosotros mismos . Tenemos un pequeño conjunto de datos. Como resultado, varios cientos de épocas serán suficientes.

5.3. Evaluación del modelo

Finalmente, podemos evaluar el modelo ahora entrenado. La biblioteca Deeplearning4j proporciona la capacidad de hacerlo fácilmente:

public Evaluation evaluate() {
   return network.evaluate(dataSetService.testIterator());
}

Evaluación es un objeto que contiene métricas calculadas después de entrenar el modelo. Esos son exactitud, precisión, recuperación y puntuación F1 . Además, tiene una interfaz imprimible amigable:

==========================Scores=====================
# of classes: 11
Accuracy: 0,8406
Precision: 0,7303
Recall: 0,6820
F1 Score: 0,6466
=====================================================

6. Conclusión

En este tutorial, aprendimos sobre la arquitectura de los modelos CNN, las técnicas de optimización y las métricas de evaluación. Además, hemos implementado el modelo utilizando la biblioteca Deeplearning4j en Java.

Como de costumbre, el código de este ejemplo está disponible en GitHub.


Etiqueta Java