sql >> Base de Datos >  >> RDS >> MariaDB

Parte 2:Clasificación de imágenes con MariaDB Server y TensorFlow:un tutorial

Dando formato a los datos para TensorFlow

La Parte 1 de esta serie de blogs demostró las ventajas de usar una base de datos relacional para almacenar y realizar la exploración de datos de imágenes usando declaraciones SQL simples. En este tutorial, parte 2, se accederá a los datos utilizados en la parte uno desde una base de datos del servidor MariaDB y se convertirán en las estructuras de datos que necesita TensorFlow. Los resultados de aplicar el modelo para clasificar nuevas imágenes se almacenarán en una tabla relacional para su posterior análisis.

Este es un tutorial rápido de un programa TensorFlow con los detalles descritos a medida que avanzamos. Si no está familiarizado con los conceptos básicos, un buen lugar para comenzar es este tutorial de TensorFlow, "Clasificación básica:clasificar imágenes de ropa". Aquí se utilizan algunos de los ejemplos y el código del tutorial.

Se necesitan paquetes adicionales

Se necesitan algunos paquetes adicionales para construir y entrenar el modelo de clasificación de imágenes:

  1. Pepinillo implementa protocolos binarios para serializar y deserializar una estructura de objeto de Python.
  2. NumPy proporciona soporte para arreglos y matrices grandes y multidimensionales, junto con funciones matemáticas de alto nivel para operar en estos arreglos.
  3. TensorFlow es una biblioteca de Python para computación numérica rápida. Es una biblioteca base que se puede usar para crear modelos de aprendizaje profundo directamente o mediante el uso de bibliotecas contenedoras que simplifican el proceso construido sobre TensorFlow.
  4. Keras es una biblioteca de redes neuronales de código abierto escrita en Python.
import pickle
import numpy as np
import tensorflow as tf

from tensorflow import keras
print('Tensorflow version: ', tf.__version__)
print('Numpy version: ', np.__version__)
Tensorflow version: 2.0.0
Numpy version: 1.16.2

Recuperar imágenes

Una vez que se han importado los paquetes, el siguiente paso es recuperar las imágenes de entrenamiento de la base de datos y dividir los datos en dos numpy arreglos Primero, necesitamos inicializar las matrices de imágenes de entrenamiento (train_images) y etiquetas de entrenamiento (train_labels). Dado que ya hemos vectorizado las imágenes, podemos usar el atributo img_vector para completar la matriz train_images con la declaración SQL a continuación.

# Initialize the numpy arrays
train_images = np.empty((60000,28,28), dtype='uint8')
train_labels = np.empty((60000), dtype='uint8')

# Retrieve the training images from the database
sql="SELECT img_label, img_vector, img_idx \
FROM tf_images INNER JOIN img_use ON img_use = use_id \
WHERE use_name = 'Training'"
cur.execute(sql)
result = cur.fetchall()

# Populate the numpy arrays. row[2] contains the image index
for row in result:
nparray = pickle.loads(row[1])
train_images[row[2]] = nparray
train_labels[row[2]] = row[0]

De manera similar, las imágenes para la prueba se pueden recuperar de la base de datos. El entumecido las matrices utilizadas en este caso son test_images y test_labels. En este caso, los datos de prueba son 10 000 imágenes con una resolución de 28 × 28 píxeles.

# Initialize the numpy arrays
test_images = np.empty((10000,28,28), dtype='uint8')
test_labels = np.empty((10000), dtype='uint8')

# Retrieve the testing images from the database
sql="SELECT img_label, img_vector, img_idx \
FROM tf_images INNER JOIN img_use ON img_use = use_id \
WHERE use_name = 'Testing'"
cur.execute(sql)
result = cur.fetchall()

# Populate the numpy arrays. row[2] contains the image index
for row in result:
nparray = pickle.loads(row[1])
test_images[row[2]] = nparray
test_labels[row[2]] = row[0]

Finalmente, cada imagen se asigna a una sola etiqueta. Los nombres de las etiquetas se almacenan en la tabla de categorías y se cargan en la matriz class_names:

sql="SELECT class_name FROM categories"
cur.execute(sql)
class_names = cur.fetchall()

Preprocesar los datos

Los datos deben preprocesarse antes de entrenar la red. Si inspecciona la primera imagen en el conjunto de entrenamiento, verá que los valores de píxel se encuentran en el rango de 0 a 255:

plt.figure()
plt.imshow(train_images[0])
plt.colorbar()
plt.grid(False)
plt.show()


arriba:imagen del conjunto de datos fashion_mnist

Antes de enviar las imágenes al modelo de red neuronal, los valores deben escalarse a un rango de 0 a 1. Para hacerlo, divida los valores entre 255. Es importante que el conjunto de entrenamiento y el conjunto de prueba se procesen previamente de la misma manera. .

Puedes usar matplotlib para mostrar las primeras 25 imágenes para verificar que los datos estén en el formato correcto y listos para construir y entrenar la red:

train_images = train_images / 255.0
test_images = test_images / 255.0

plt.figure(figsize=(10,10))
for i in range(25):
plt.subplot(5,5,i+1)
plt.xticks([])
plt.yticks([])
plt.grid(False)
plt.imshow(train_images[i], cmap=plt.cm.binary)
plt.xlabel(class_names[train_labels[i]])
plt.show()


arriba:imágenes del conjunto de datos fashion_mnist

Construyendo el modelo

Una vez que los datos se hayan preprocesado en dos subconjuntos, puede continuar con un entrenamiento del modelo. Este proceso implica “alimentar” el algoritmo con datos de entrenamiento. El algoritmo procesará los datos y generará un modelo que puede encontrar un valor objetivo (atributo) en nuevos datos, es decir, clasificar la imagen presentada a la red neuronal.

La mayoría de las redes neuronales de aprendizaje profundo se producen encadenando capas simples.

La primera capa de la red transforma el formato de la imagen de una matriz bidimensional (de 28 por 28 píxeles) a una matriz unidimensional (de 28 * 28 =784 píxeles). Esta capa no tiene parámetros para aprender; solo reformatea los datos.

Después de aplanar los píxeles, la red consta de dos capas completamente conectadas que deben activarse. En una red neuronal, la función de activación es responsable de transformar la entrada ponderada sumada del nodo en la activación del nodo o salida para esa entrada.

La primera capa densa tiene 128 nodos (o neuronas) y utiliza un método de activación de Unidad lineal rectificada (ReLU). La función de activación lineal rectificada es una función lineal por partes que generará la entrada directamente si es positiva; de lo contrario, generará cero.

La segunda (y última) capa es una capa softmax de 10 nodos. Una función softmax genera un vector que representa las distribuciones de probabilidad de una lista de posibles resultados. Devuelve una matriz de 10 puntuaciones de probabilidad que suman 1. Cada nodo contiene una puntuación que indica la probabilidad de que la imagen actual pertenezca a una de las 10 clases.

La mayoría de las capas, como tf.keras.layers.Dense, tienen parámetros que se aprenden durante el entrenamiento.

model = keras.Sequential([
keras.layers.Flatten(input_shape=(28, 28)),
keras.layers.Dense(128, activation='relu'),
keras.layers.Dense(10, activation='softmax')
])

Compilación del modelo

El paso de compilación del modelo se usa para agregar algunas configuraciones más antes de que esté listo para el entrenamiento. En este caso, las siguientes configuraciones están habilitadas.

  1. Optimizador:actualiza el modelo en función de los datos que ve y su función de pérdida (consulte a continuación).
  2. Función de pérdida:mide la precisión del modelo durante el entrenamiento. Desea minimizar esta función para "dirigir" el modelo en la dirección correcta.
  3. Métricas:supervise los pasos de capacitación y prueba. El siguiente ejemplo utiliza la precisión, la fracción de las imágenes que se clasifican correctamente.
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])

Entrenando al modelo

Entrenar el modelo de red neuronal requiere los siguientes pasos.

  1. Envíe los datos de entrenamiento al modelo.
  2. El modelo aprende a asociar imágenes y etiquetas.
  3. Hacer predicciones sobre un conjunto de prueba.
  4. Verifique que las predicciones coincidan con las etiquetas de la matriz test_labels.

Para comenzar a entrenar, llame al método model.fit, llamado así porque "ajusta" el modelo a los datos de entrenamiento:

model.fit(train_images, train_labels, epochs=10)
Train on 60000 samples
Epoch 1/10
60000/60000 [==============================] - 5s 83us/sample - loss: 0.4964 - accuracy: 0.8236
Epoch 2/10
60000/60000 [==============================] - 4s 65us/sample - loss: 0.3735 - accuracy: 0.8642
Epoch 3/10
60000/60000 [==============================] - 3s 55us/sample - loss: 0.3347 - accuracy: 0.8773
Epoch 4/10
60000/60000 [==============================] - 3s 56us/sample - loss: 0.3106 - accuracy: 0.8861
Epoch 5/10
60000/60000 [==============================] - 3s 58us/sample - loss: 0.2921 - accuracy: 0.8924s - loss: 0.2928 - accura - ETA: 0s - loss: 0.2925 - accuracy
Epoch 6/10
60000/60000 [==============================] - 3s 57us/sample - loss: 0.2796 - accuracy: 0.8969s
Epoch 7/10
60000/60000 [==============================] - 4s 70us/sample - loss: 0.2659 - accuracy: 0.9007
Epoch 8/10
60000/60000 [==============================] - 4s 61us/sample - loss: 0.2548 - accuracy: 0.9042
Epoch 9/10
60000/60000 [==============================] - 4s 61us/sample - loss: 0.2449 - accuracy: 0.9084
Epoch 10/10
60000/60000 [==============================] - 5s 76us/sample - loss: 0.2358 - accuracy: 0.9118

Al final de cada época, la red neuronal se evalúa frente al conjunto de validación. Esto es a lo que se refieren la pérdida y la precisión.

Evaluar la precisión y predecir

Para estimar la precisión general del modelo, calcule el promedio de las diez ocurrencias del valor de precisión, en este caso 88%.

Luego ejecute model.evaluate en el conjunto de prueba para obtener la precisión predictiva de la red neuronal entrenada en datos nunca antes vistos.

test_loss, test_acc = model.evaluate(test_images, test_labels, verbose=2)
10000/1 - 0s - loss: 0.2766 - accuracy: 0.8740

El conjunto de datos de prueba es menos preciso que el conjunto de datos de entrenamiento. En este caso, esta brecha entre la precisión del entrenamiento y la precisión de la prueba representa un sobreajuste. Lo contrario es infravaloración. Si desea obtener más información sobre este tema, le recomiendo Overfitting vs. Underfitting:A Conceptual Explanation by Will Koehrsen.

En este punto, podemos hacer algunas predicciones sobre las imágenes en nuestro conjunto de datos de entrenamiento.

predictions = model.predict(test_images)
predictions[0]
array([1.90860412e-08, 8.05085235e-11, 1.56402713e-08, 1.66699390e-10,
7.86950158e-11, 4.33062996e-06, 2.49049066e-08, 1.20656565e-02,
3.80084719e-09, 9.87929940e-01], dtype=float32)

La salida de model.predict es una matriz de 10 números con la probabilidad de que una instancia pertenezca a cada clase. Conservar los resultados en la base de datos MariaDB para su posterior análisis e informes es una buena idea. A continuación se muestra un ejemplo de cómo iterar en la matriz de predicciones para crear una tupla y luego insertarla en prediction_results mesa.

sql = "INSERT INTO prediction_results (
img_idx
, img_use
, T_shirt_Top
, Trouser
, Pullover
, Dress
, Coat
, Sandal
, Shirt
, Sneaker
, Bag
, Ankle_boot
, label)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s);"
i = 0
for row in predictions:
insert_tuple = (str(i), str(2)
, str(row[0]), str(row[1]), str(row[2]), str(row[3]), str(row[4])
, str(row[5]), str(row[6]), str(row[7]), str(row[8]), str(row[9])
, str(test_labels[i]))
cur.execute(sql, insert_tuple)
conn.commit()
i += 1

Una vez más, se puede usar una instrucción SQL simple para verificar que se hayan cargado los datos.

sql = "SELECT T_shirt_Top
, Trouser
, Pullover
, Dress
, Coat
, Sandal
, Shirt
, Sneaker
, Bag
, Ankle_boot
, class_name as 'Test Label'
FROM prediction_results JOIN categories ON label = class_idx WHERE img_idx = 1"
display( pd.read_sql(sql,conn) )

T_shirt_Top Pantalones Jersey Vestido Abrigo Sandalia Camisa Zapatillas Bolsa Botines Etiqueta de prueba
0.00001 0.0 0,997912 0.0 0,001267 0.0 0,00081 0.0 0.0 0.0 Jersey

Trazar predicciones

A continuación se definen un par de funciones gráficas para mostrar las predicciones (funciones gráficas).

Recuperemos una nueva imagen del conjunto de prueba y mostremos la clasificación de la red neuronal según la probabilidad de predicción.

sql = "SELECT img_idx, label FROM prediction_results WHERE img_idx = 1"
cur.execute(sql)
result = cur.fetchone()
plt.figure(figsize=(6,3))
plt.subplot(1,2,1)
plot_image(result[0], predictions[result[0]], test_labels, test_images)
plt.subplot(1,2,2)
plot_value_array(result[0], predictions[result[0]], test_labels)
plt.show()


arriba:imagen del conjunto de datos fashion_mnist

En este caso, el modelo pudo clasificar la imagen correctamente con un 100% de precisión. A continuación, ejecutemos una consulta para recuperar las primeras 15 imágenes del conjunto de prueba y clasificarlas.

sql = "SELECT img_idx, label FROM prediction_results LIMIT 15"
num_rows = 5
num_cols = 3
plt.figure(figsize=(2*2*num_cols, 2*num_rows))
cur.execute(sql)
result = cur.fetchall()
for row in result:
plt.subplot(num_rows, 2*num_cols, 2*row[0]+1)
plot_image(row[0], predictions[row[0]], test_labels, test_images)
plt.subplot(num_rows, 2*num_cols, 2*row[0]+2)
plot_value_array(row[0], predictions[row[0]], test_labels)
plt.tight_layout()
plt.show()


arriba:imágenes del conjunto de datos fashion_mnist

Como puede ver, habrá instancias en las que el modelo puede ser incorrecto, como se muestra en la última fila, columna izquierda. En este caso, una zapatilla se clasificó como una sandalia (en rojo).

En Resumen

Aunque la integración entre TensorFlow y MariaDB Server es fácil, los beneficios de esta integración son sustanciales:

  • El uso de datos relacionales dentro del aprendizaje automático puede reducir la complejidad de la implementación. Tanto los científicos como los ingenieros de datos pueden usar un lenguaje común para realizar tareas de exploración y disputa de datos.
  • La eficiencia obtenida al acceder, actualizar, insertar, manipular y modificar datos puede acelerar el tiempo de comercialización.
  • La capacidad de almacenar los resultados del modelo en la base de datos permite a los usuarios finales y analistas ejecutar consultas e informes utilizando herramientas de generación de informes amigables como Tableau.

Licencia MIT

El conjunto de datos de Fashion MNIST (fashion_mnist) aprovechado por este blog tiene licencia MIT, Copyright © 2017 Zalando SE, https://tech.zalando.com

El código fuente aprovechado por este blog está adaptado del tutorial "Clasificación básica:Clasificar imágenes de ropa" que tiene la licencia MIT, Copyright (c) 2017 François Chollet.

Por la presente se otorga permiso, sin cargo, a cualquier persona que obtenga una copia de este software y los archivos de documentación asociados (el "Software"), para operar con el Software sin restricciones, incluidos, entre otros, los derechos de uso, copia, modificación, fusión , publicar, distribuir, otorgar sublicencias y/o vender copias del Software, y permitir que las personas a las que se les proporcione el Software lo hagan, sujeto a las siguientes condiciones:

El aviso de derechos de autor anterior y este aviso de permiso se incluirán en todas las copias o partes sustanciales del Software.

EL SOFTWARE SE PROPORCIONA "TAL CUAL", SIN GARANTÍA DE NINGÚN TIPO, EXPRESA O IMPLÍCITA, INCLUYENDO, ENTRE OTRAS, LAS GARANTÍAS DE COMERCIABILIDAD, IDONEIDAD PARA UN FIN DETERMINADO Y NO VIOLACIÓN. EN NINGÚN CASO LOS AUTORES O LOS TITULARES DE LOS DERECHOS DE AUTOR SERÁN RESPONSABLES DE CUALQUIER RECLAMACIÓN, DAÑOS U OTRA RESPONSABILIDAD, YA SEA EN UNA ACCIÓN DE CONTRATO, AGRAVIO O DE OTRO TIPO, QUE SURJA DE, FUERA DE O EN RELACIÓN CON EL SOFTWARE O EL USO U OTROS TRATOS EN EL SOFTWARE.

Referencias

Convierta su propia imagen en la imagen de MNIST
matplotlib:Tutorial de imágenes
5 formas en que la IA está transformando la experiencia del cliente
La digitalización está reinventando el negocio
¿Qué es la clasificación de imágenes?
Introducción a Python Biblioteca de aprendizaje profundo TensorFlow

Funciones gráficas

def plot_image(i, predictions_array, true_label, img):
predictions_array, true_label, img = predictions_array, true_label[i], img[i]
plt.grid(False)
plt.xticks([])
plt.yticks([])

plt.imshow(img, cmap=plt.cm.binary)

predicted_label = np.argmax(predictions_array)
if predicted_label == true_label:
color = 'blue'
else:
color = 'red'

plt.xlabel("{} {:2.0f}% ({})".format(class_names[predicted_label],
100*np.max(predictions_array),
class_names[true_label]),
color=color)

def plot_value_array(i, predictions_array, true_label):
predictions_array, true_label = predictions_array, true_label[i]
plt.grid(False)
plt.xticks(range(10))
plt.yticks([])
thisplot = plt.bar(range(10), predictions_array, color="#777777")
plt.ylim([0, 1])
predicted_label = np.argmax(predictions_array)

thisplot[predicted_label].set_color('red')
thisplot[true_label].set_color('blue')