sábado, 23 de enero de 2021

Clasificador de imágenes con una red neuronal Keras

Ya hemos comentado aquí lo que es una red neuronal, ahora vamos a descargar el dataset MNIST  de prendas de ropa que contiene 60.000 imágenes de prendas de vestir en escala de grises de 28x28 pixels. El dataset contiene 10 categorías o clases de prendas de vestir. Previamente tendremos instalado en nuestro equipo un entorno virtual de Anaconda con Tensorflow instalado (enlace), o podemos optar también por ejecutar las instrucciones en la nube con Colaboratory.

Hecho esto importamos Tensorflow y Keras 

import tensorflow as tf

from tensorflow import keras

Cargamos el dataset de Moda de MNIST

fashion_mnist = keras.datasets.fashion_mnist

(X_train_full, y_train_full), (X_test, y_test) = fashion_mnist.load_data()

Si hacemos

X_train_full.shape

Nos devuelve  (60000, 28, 28) lo que significa que contiene 60.000 imágenes de 28 por 28 pixels.

Dividimos el dataset de entrenamiento completo en un dataset de validación y otro de entrenamiento (más pequeño). También escalamos las intensidades de píxeles para dejarlas dentro del rango 0-1, como sus valores van de 0 a 255 las dividimos entre 255, esto hace que pasen a ser valores flotantes.

X_valid, X_train = X_train_full[:5000] / 255, X_train_full[5000:] / 255

y_valid, y_train = y_train_full[:5000], y_train_full[5000:]

X_test = X_test / 255

Vamos a mostrar una imagen del conjunto

plt.imshow(X_train[23], cmap="binary")

plt.axis('off')

plt.show()

En este caso hemos tomado al azar el número 23 que ha resultado ser una bota.

class_names = ["Camiseta""Pantalones""Jersey""Vestido""Abrigo","Sandalia""Camisa""Deportivas""Bolso""Bota"]

Por ejemplo elegimos la etiqueta de nuestra imagen 23.

class_names[y_train[23]]

Clasificador de imágenes con una red neuronal Keras

En nuestro caso está clasificada como deportivas.

El dataset de validación contiene 5000 imágenes y el dataset de prueba contiene 10000 imágenes:

X_valid.shape

X_test.shape

Crear un modelo usando la API Secuencial

Ahora vamos a construir una red neuronal  con dos capas ocultas

model = keras.models.Sequential()

model.add(keras.layers.Flatten(input_shape=[2828]))

model.add(keras.layers.Dense(300, activation="relu"))

model.add(keras.layers.Dense(100, activation="relu"))

model.add(keras.layers.Dense(10, activation="softmax"))

La primera fila crea el modelo secuencial, la segunda línea crea una capa de entrada aplanada (Flatten), su cometido es convertir cada imagen de 28x28 pixels en un array de una dimensión y 784 bits de tamaño, no tiene parámetros simplemente realiza un preprocesamiento.

La siguiente fila, crea una capa densa de 300 neuronas ( o perceptrones)  y utilizará la función ReLU como función de activación. Cada capa densa gestiona su propia matriz de pesos y contiene todas las conexiones con la capa de entrada, también gestiona los sesgos de cada neurona (Bias). 

La siguiente línea añade una segunda capa de 100 neuronas. Finalmente añadimos una capa de salida de 10 neuronas, una por clase. Y utiliza softmax como función de activación pues las 10 clases son exclusivas.

En vez de añadir las capas una por una, podemos pasar una lista de las capas al crear el modelo secuencial.

model = keras.models.Sequential([

    keras.layers.Flatten(input_shape=[2828]),

    keras.layers.Dense(300, activation="relu"),

    keras.layers.Dense(100, activation="relu"),

    keras.layers.Dense(10, activation="softmax")

])

Si queremos saber las capas que tiene nuestro modelo podemos hacer 

model.layers

También podemos ver un pequeño resumen de nuestra red poniendo

model.summary()

Y para ver un esquema 

keras.utils.plot_model(model, "mnist_modelo_prendas_ropa.png", show_shapes=True)

Esquema de una red neuronal keras

Para obtener el nombre de la primera capa oculta

hidden1 = model.layers[1]

hidden1.name

Esta devuelve true si la capa es oculta

model.get_layer(hidden1.name) is hidden1

Todos los parámetros de una capa pueden ser accedidos utilizando los métodos get_weights() y set_weghts() si la capa es densa, incluye los pesos de las conexiones y los términos de sesgo (bias).

weights, biases = hidden1.get_weights()

weights

weights.shape

biases

biases.shape

Compilando el modelo

Después de crear nuestro modelo necesitamos compilarlo, para ello llamamos al método compile 

model.compile(loss="sparse_categorical_crossentropy",

              optimizer="sgd",

              metrics=["accuracy"])

Para especificar la función de pérdida y el optimizador a utilizar. Opcionalmente podemos especificar una lista de métricas extra para computar durante el entrenamiento y evaluación.

hemos utilizado sparse_categorical_crossentropy porque tenemos etiquetas escasas (una por instancia) y las clases son exclusivas. Respecto al optimizador sgd significa que vamos a entrenar el modelo utilizando Descenso de gradiente estocástico simple (Stochastic Gradient Descent). Finalmente debido a que es un clasificador, es útil medir su exactitud "accuracy" durante su entrenamiento y evaluación.

Entrenando y evaluando el modelo

Ahora el modelo está preparado para ser entrenado, para ello llamamos al método fit().

history = model.fit(X_train, y_train, epochs=30,

                    validation_data=(X_valid, y_valid))

Para entrenar el modelo, le pasamos las características de entrada X_train y las clases objetivo y_train así como el número de épocas a entrenar, también le pasamos el set de validación aunque esto último es opcional. 

Keras mide la perdida y otras métricas del modelo al final de cada época, lo cual es muy útil para ver cómo se va entrenando el modelo.

Entrenar un modelo

Para ver los diferentes parámetros del entrenamiento

history.params

print(history.epoch)

history.history.keys()

Si creamos un diccionario con estos valores, podemos visualizar las gráficas del entrenamiento.

import pandas as pd

pd.DataFrame(history.history).plot(figsize=(85))

plt.grid(True)

plt.gca().set_ylim(01)

save_fig("curvas_de_aprendizaje_keras")

plt.show()


Visualizar entrenamiento de un modelo keras

Una vez estamos satisfechos con la exactitud del modelo podemos evaluar el set para estimar el error antes de desplegarlo en producción. Podemos hacerlo fácilmente con el método evaluate().

model.evaluate(X_test, y_test)

313/313 [==============================] - 0s 2ms/step - loss: 0.3364 - accuracy: 0.8812

[0.33643999695777893, 0.8812000155448914]

Utilizando el modelo para hacer predicciones

A continuación utilizaremos el método predict() para hacer predicciones sobre nuevas instancias. Como no tenemos nuevas instancias reales, vamos a utilizar las cuatro primeras instancias del dataset

X_new = X_test[:4]

y_proba = model.predict(X_new)

y_proba.round(2)

array([[0.  , 0.  , 0.  , 0.  , 0.  , 0.  , 0.  , 0.01, 0.  , 0.99],

       [0.  , 0.  , 1.  , 0.  , 0.  , 0.  , 0.  , 0.  , 0.  , 0.  ],

       [0.  , 1.  , 0.  , 0.  , 0.  , 0.  , 0.  , 0.  , 0.  , 0.  ],

       [0.  , 1.  , 0.  , 0.  , 0.  , 0.  , 0.  , 0.  , 0.  , 0.  ]],

      dtype=float32)

Para cada instancia estima una probabilidad por clase entre la 0 y la 9, para la primera instancia ha estimado una probabilidad de 0,99 a la clase 9 que es una bota, y 0,01 para la clase 7 que es deportivas. Lo mismo para el resto de instancias.

Si queremos obtener sólo un valor para la clase de mayor probabilidad, en vez del método predict() utilizaremos np.argmax().

y_pred =np.argmax(model.predict(X_new), axis=-1)

y_pred

array([9, 2, 1, 1])

para ver el significado de cada clase hacemos

np.array(class_names)[y_pred]

array(['Bota', 'Jersey', 'Pantalones', 'Pantalones'], dtype='<U10')

y para ver las imágenes

plt.figure(figsize=(7.22.4))

for index, image in enumerate(X_new):

    plt.subplot(14, index + 1)

    plt.imshow(image, cmap="binary", interpolation="nearest")

    plt.axis('off')

    plt.title(class_names[y_test[index]], fontsize=12)

plt.subplots_adjust(wspace=0.2, hspace=0.5)

save_fig('imagenes_predichas', tight_layout=False)

plt.show()

Mostrar imágenes de un dataset con keras


 



1 comentario: