Tensorflow 2.0: resolución de problemas de clasificación y regresión

Tensorflow 2.0 introdujo algunas características nuevas e importantes. Entre ellos, ahora utiliza la API de Keras de forma predeterminada para la clasificación y la regresión. En este artículo, abordaremos estas tareas clásicas de ML con Tensorflow 2.0.

Después de mucha publicidad, Google finalmente lanzó TensorFlow 2.0, que es la última versión de la plataforma de aprendizaje profundo insignia de Google. Se han introducido muchas funciones esperadas desde hace mucho tiempo en TensorFlow 2.0. Este artículo cubre muy brevemente cómo puede desarrollar modelos simples de clasificación y regresión usando TensorFlow 2.0.

Clasificación con Tensorflow 2.0

Si alguna vez ha trabajado con la biblioteca de Keras, le espera una sorpresa. TensorFlow 2.0 ahora usa Keras API como su biblioteca predeterminada para entrenar modelos de clasificación y regresión. Antes de TensorFlow 2.0, una de las principales críticas a las que se enfrentaron las versiones anteriores de TensorFlow procedía de la complejidad de la creación de modelos. Anteriormente, debe unir gráficos, sesiones y marcadores de posición para crear incluso un modelo de regresión logística simple. Con TensorFlow 2.0, crear modelos de clasificación y regresión se ha vuelto pan comido.

Entonces, sin más preámbulos, desarrollemos un modelo de clasificación con TensorFlow.

El conjunto de datos

El conjunto de datos para el ejemplo de clasificación se puede descargar gratuitamente desde este enlace. Descarga el archivo en formato CSV. Si abre el archivo CSV descargado, verá que el archivo no contiene ningún encabezado. El detalle de las columnas está disponible en [Repositorio de aprendizaje automático UCI](https://archive.ics.uci.edu/ml/datasets/car+e Evaluation). Le recomendaré que lea la información del conjunto de datos en detalle desde el enlace de descarga. Resumiré brevemente el conjunto de datos en esta sección.

El conjunto de datos consta básicamente de 7 columnas:

  1. precio (el precio de compra del automóvil)
  2. maint (el costo de mantenimiento)
  3. puertas (número de puertas)
  4. personas (la capacidad de asientos)
  5. lug_capacity (la capacidad del equipaje)
  6. seguridad (qué tan seguro es el auto)
  7. salida (el estado del coche)

Dadas las primeras 6 columnas, la tarea es predecir el valor de la séptima columna, es decir, la salida. La columna de salida puede tener uno de los tres valores, es decir, "unacc" (inaceptable), "acc" (aceptable), bueno y muy bueno.

Importación de bibliotecas

Antes de importar el conjunto de datos a nuestra aplicación, debemos importar las bibliotecas requeridas.

1
2
3
4
5
6
7
8
9
import pandas as pd
import numpy as np
import tensorflow as tf

import matplotlib.pyplot as plt
%matplotlib inline

import seaborn as sns
sns.set(style="darkgrid")

Antes de continuar, quiero que se asegure de tener la última versión de TensorFlow, es decir, TensorFlow 2.0. Puede verificar su versión de TensorFlow con el siguiente comando:

1
print(tf.__version__)

Si no tiene instalado TensorFlow 2.0, puede actualizar a la última versión mediante el siguiente comando:

1
$ pip install --upgrade tensorflow

Importación del conjunto de datos

El siguiente script importa el conjunto de datos. Cambie la ruta a su archivo de datos CSV según corresponda.

1
2
cols = ['price', 'maint', 'doors', 'persons', 'lug_capacity', 'safety','output']
cars = pd.read_csv(r'/content/drive/My Drive/datasets/car_dataset.csv', names=cols, header=None)

Dado que el archivo CSV no contiene encabezados de columna de manera predeterminada, pasamos una lista de encabezados de columna al método pd.read_csv().

Veamos ahora las primeras 5 filas del conjunto de datos a través del método head().

1
cars.head()

Producción:

primeras 5 filas del conjunto de datos

Puede ver las 7 columnas en el conjunto de datos.

Análisis y preprocesamiento de datos {#análisis y preprocesamiento de datos}

Analicemos brevemente el conjunto de datos trazando un gráfico circular que muestre la distribución de la salida. La siguiente secuencia de comandos aumenta el tamaño de trazado predeterminado.

1
2
3
4
plot_size = plt.rcParams["figure.figsize"]
plot_size [0] = 8
plot_size [1] = 6
plt.rcParams["figure.figsize"] = plot_size

Y el siguiente script traza el gráfico circular que muestra la distribución de salida.

1
cars.output.value_counts().plot(kind='pie', autopct='%0.05f%%', colors=['lightblue', 'lightgreen', 'orange', 'pink'], explode=(0.05, 0.05, 0.05,0.05))

Producción:

gráfico circular de análisis de datos

El resultado muestra que la mayoría de los automóviles (70 %) se encuentran en condiciones inaceptables, mientras que el 20 % de los automóviles se encuentran en condiciones aceptables. La proporción de autos en buen y muy buen estado es muy baja.

Todas las columnas de nuestro conjunto de datos son categóricas. El aprendizaje profundo se basa en algoritmos estadísticos y los algoritmos estadísticos funcionan con números. Por lo tanto, necesitamos convertir la información categórica en columnas numéricas. Hay varios enfoques para hacerlo, pero uno de los más comunes es codificación one-hot. En la codificación one-hot, para cada valor único en la columna categórica, se crea una nueva columna. Para las filas de la columna real donde existía el valor único, se agrega un 1 a la fila correspondiente de la columna creada para ese valor en particular. Esto puede sonar complejo, pero el siguiente ejemplo lo aclarará.

El siguiente script convierte columnas categóricas en columnas numéricas:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
price = pd.get_dummies(cars.price, prefix='price')
maint = pd.get_dummies(cars.maint, prefix='maint')

doors = pd.get_dummies(cars.doors, prefix='doors')
persons = pd.get_dummies(cars.persons, prefix='persons')

lug_capacity = pd.get_dummies(cars.lug_capacity, prefix='lug_capacity')
safety = pd.get_dummies(cars.safety, prefix='safety')

labels = pd.get_dummies(cars.output, prefix='condition')

Para crear nuestro conjunto de características, podemos fusionar las primeras seis columnas horizontalmente:

1
X = pd.concat([price, maint, doors, persons, lug_capacity, safety] , axis=1)

Veamos cómo se ve ahora nuestra columna de etiquetas:

1
labels.head()

Producción:

columnas del conjunto de datos

La columna de etiqueta es básicamente una versión codificada en caliente de la columna de salida que teníamos en nuestro conjunto de datos. La columna de salida tenía cuatro valores únicos: unacc, acc, good y very good. En el conjunto de datos de etiquetas codificadas en caliente, puede ver cuatro columnas, una para cada uno de los valores únicos en la columna de salida. Puede ver 1 en la columna para el valor único que existía originalmente en esa fila. Por ejemplo, en las primeras cinco filas de la columna de salida, el valor de la columna era unacc. En la columna de etiquetas, puede ver 1 en las primeras cinco filas de la columna condition_unacc.

Ahora, convirtamos nuestras etiquetas en una matriz numpy, ya que los modelos de aprendizaje profundo en TensorFlow aceptan una matriz numpy como entrada.

1
y = labels.values

El paso final antes de que podamos entrenar nuestro modelo de clasificación TensorFlow 2.0 es dividir el conjunto de datos en conjuntos de entrenamiento y prueba:

1
2
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.20, random_state=42)

Capacitación de modelos

Para entrenar el modelo, importemos las clases de TensorFlow 2.0. Ejecute el siguiente script:

1
2
from tensorflow.keras.layers import Input, Dense, Activation,Dropout
from tensorflow.keras.models import Model

Como dije antes, TensorFlow 2.0 usa la API de Keras para entrenar el modelo. En el script anterior, básicamente importamos las clases Input, Dense, Activation y Dropout del módulo tensorflow.keras.layers. Del mismo modo, también ‘importamos’ la clase ‘Modelo’ del módulo ’tensorflow.keras.models’.

El siguiente paso es crear nuestro modelo de clasificación:

1
2
3
4
5
6
7
input_layer = Input(shape=(X.shape[1],))
dense_layer_1 = Dense(15, activation='relu')(input_layer)
dense_layer_2 = Dense(10, activation='relu')(dense_layer_1)
output = Dense(y.shape[1], activation='softmax')(dense_layer_2)

model = Model(inputs=input_layer, outputs=output)
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['acc'])

Como se puede ver en el guión, el modelo contiene tres capas densas. Las dos primeras capas densas contienen 15 y 10 nodos, respectivamente, con la función de activación relu. La capa densa final contiene 4 nodos (y.shape[1] == 4) y la función de activación softmax ya que esta es una tarea de clasificación. El modelo se entrena utilizando la función de pérdida categorical_crossentropy y el optimizador adam. La métrica de evaluación es la precisión.

El siguiente script muestra el resumen del modelo:

1
print(model.summary())

Producción:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
Model: "model"
_________________________________________________________________
Layer (type)                 Output Shape              Param #
=================================================================
input_1 (InputLayer)         [(None, 21)]              0
_________________________________________________________________
dense (Dense)                (None, 15)                330
_________________________________________________________________
dense_1 (Dense)              (None, 10)                160
_________________________________________________________________
dense_2 (Dense)              (None, 4)                 44
=================================================================
Total params: 534
Trainable params: 534
Non-trainable params: 0
_________________________________________________________________
None

Finalmente, para entrenar el modelo ejecuta el siguiente script:

1
history = model.fit(X_train, y_train, batch_size=8, epochs=50, verbose=1, validation_split=0.2)

El modelo se entrenará durante 50 épocas, pero aquí, por razones de espacio, solo se muestra el resultado de las últimas 5 épocas:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
Epoch 45/50
1105/1105 [==============================] - 0s 219us/sample - loss: 0.0114 - acc: 1.0000 - val_loss: 0.0606 - val_acc: 0.9856
Epoch 46/50
1105/1105 [==============================] - 0s 212us/sample - loss: 0.0113 - acc: 1.0000 - val_loss: 0.0497 - val_acc: 0.9856
Epoch 47/50
1105/1105 [==============================] - 0s 219us/sample - loss: 0.0102 - acc: 1.0000 - val_loss: 0.0517 - val_acc: 0.9856
Epoch 48/50
1105/1105 [==============================] - 0s 218us/sample - loss: 0.0091 - acc: 1.0000 - val_loss: 0.0536 - val_acc: 0.9856
Epoch 49/50
1105/1105 [==============================] - 0s 213us/sample - loss: 0.0095 - acc: 1.0000 - val_loss: 0.0513 - val_acc: 0.9819
Epoch 50/50
1105/1105 [==============================] - 0s 209us/sample - loss: 0.0080 - acc: 1.0000 - val_loss: 0.0536 - val_acc: 0.9856

Al final de la época 50, tenemos una precisión de entrenamiento del 100 %, mientras que una precisión de validación del 98,56 %, lo cual es impresionante.

Finalmente, evalúemos el rendimiento de nuestro modelo de clasificación en el conjunto de prueba:

1
2
3
4
score = model.evaluate(X_test, y_test, verbose=1)

print("Test Score:", score[0])
print("Test Accuracy:", score[1])

Aquí está la salida:

1
2
3
4
WARNING:tensorflow:Falling back from v2 loop because of error: Failed to find data adapter that can handle input: <class 'pandas.core.frame.DataFrame'>, <class 'NoneType'>
346/346 [==============================] - 0s 55us/sample - loss: 0.0605 - acc: 0.9740
Test Score: 0.06045335989359314
Test Accuracy: 0.9739884

Nuestro modelo logra una precisión del 97,39 % en el conjunto de prueba. Aunque es un poco menos que la precisión de entrenamiento del 100 %, sigue siendo muy bueno dado el hecho de que elegimos aleatoriamente el número de capas y los nodos. Puede agregar más capas al modelo con más nodos y ver si puede obtener mejores resultados en los conjuntos de validación y prueba.

Regresión con TensorFlow 2.0

En un problema de regresión, el objetivo es predecir un valor continuo. En esta sección, verá cómo resolver un problema de regresión con TensorFlow 2.0

El conjunto de datos

El conjunto de datos para este problema se puede descargar libremente desde este enlace. Descarga el archivo CSV.

El siguiente script importa el conjunto de datos. No olvide cambiar la ruta a su propio archivo de datos CSV.

1
petrol_cons = pd.read_csv(r'/content/drive/My Drive/datasets/petrol_consumption.csv')

Imprimamos las primeras cinco filas del conjunto de datos mediante la función head():

1
petrol_cons.head()

Producción:

filas del conjunto de datos

Puede ver que hay cinco columnas en el conjunto de datos. El modelo de regresión se entrenará en las primeras cuatro columnas, es decir, Impuesto_gasolina, Ingreso_promedio, Carreteras_pavimentadas y Licencia_de_conducir_población(%). Se pronosticará el valor de la última columna, es decir, Consumo_gasolina. Como puede ver, no hay un valor discreto para la columna de salida, sino que el valor pronosticado puede ser cualquier valor continuo.

Preprocesamiento de datos {#preprocesamiento de datos}

En el paso de preprocesamiento de datos, simplemente dividiremos los datos en características y etiquetas, y luego dividiremos los datos en conjuntos de prueba y entrenamiento. Finalmente se normalizarán los datos. Para problemas de regresión en general y para problemas de regresión con aprendizaje profundo, se recomienda enfáticamente que normalice su conjunto de datos. Finalmente, dado que todas las columnas son numéricas, aquí no es necesario realizar una codificación one-hot de las columnas.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
X = petrol_cons.iloc[:, 0:4].values
y = petrol_cons.iloc[:, 4].values

from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)

from sklearn.preprocessing import StandardScaler

sc = StandardScaler()
X_train = sc.fit_transform(X_train)
X_test = sc.transform(X_test)

En el script anterior, en el conjunto de características X, se incluyen las primeras cuatro columnas del conjunto de datos. En el conjunto de etiquetas y, solo se incluye la quinta columna. A continuación, el conjunto de datos se divide en tamaño de prueba y entrenamiento a través del método train_test_split del módulo sklearn.model_selection. El valor del atributo test_size es 0,2, lo que significa que el conjunto de prueba contendrá el 20 % de los datos originales y el conjunto de entrenamiento constará del 80 % restante del conjunto de datos original. Finalmente, la clase StandardScaler del módulo sklearn.preprocessing se utiliza para escalar el conjunto de datos.

Capacitación de modelos

El siguiente paso es entrenar nuestro modelo. Este proceso es bastante similar al entrenamiento de la clasificación. El único cambio será en la función de pérdida y el número de nodos en la capa densa de salida. Dado que ahora estamos prediciendo un solo valor continuo, la capa de salida solo tendrá 1 nodo.

1
2
3
4
5
6
7
8
input_layer = Input(shape=(X.shape[1],))
dense_layer_1 = Dense(100, activation='relu')(input_layer)
dense_layer_2 = Dense(50, activation='relu')(dense_layer_1)
dense_layer_3 = Dense(25, activation='relu')(dense_layer_2)
output = Dense(1)(dense_layer_3)

model = Model(inputs=input_layer, outputs=output)
model.compile(loss="mean_squared_error" , optimizer="adam", metrics=["mean_squared_error"])

Nuestro modelo consta de cuatro capas densas con 100, 50, 25 y 1 nodo, respectivamente. Para problemas de regresión, una de las funciones de pérdida más utilizadas es mean_squared_error. El siguiente script imprime el resumen del modelo:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
Model: "model_2"
_________________________________________________________________
Layer (type)                 Output Shape              Param #
=================================================================
input_4 (InputLayer)         [(None, 4)]               0
_________________________________________________________________
dense_10 (Dense)             (None, 100)               500
_________________________________________________________________
dense_11 (Dense)             (None, 50)                5050
_________________________________________________________________
dense_12 (Dense)             (None, 25)                1275
_________________________________________________________________
dense_13 (Dense)             (None, 1)                 26
=================================================================
Total params: 6,851
Trainable params: 6,851
Non-trainable params: 0

Finalmente, podemos entrenar el modelo con el siguiente script:

1
history = model.fit(X_train, y_train, batch_size=2, epochs=100, verbose=1, validation_split=0.2)

Aquí está el resultado de las últimas 5 épocas de entrenamiento:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
Epoch 96/100
30/30 [==============================] - 0s 2ms/sample - loss: 510.3316 - mean_squared_error: 510.3317 - val_loss: 10383.5234 - val_mean_squared_error: 10383.5234
Epoch 97/100
30/30 [==============================] - 0s 2ms/sample - loss: 523.3454 - mean_squared_error: 523.3453 - val_loss: 10488.3036 - val_mean_squared_error: 10488.3037
Epoch 98/100
30/30 [==============================] - 0s 2ms/sample - loss: 514.8281 - mean_squared_error: 514.8281 - val_loss: 10379.5087 - val_mean_squared_error: 10379.5088
Epoch 99/100
30/30 [==============================] - 0s 2ms/sample - loss: 504.0919 - mean_squared_error: 504.0919 - val_loss: 10301.3304 - val_mean_squared_error: 10301.3311
Epoch 100/100
30/30 [==============================] - 0s 2ms/sample - loss: 532.7809 - mean_squared_error: 532.7809 - val_loss: 10325.1699 - val_mean_squared_error: 10325.1709

Para evaluar el rendimiento de un modelo de regresión en un conjunto de pruebas, una de las métricas más utilizadas es el error cuadrático medio. Podemos encontrar el error cuadrático medio entre los valores predichos y reales a través de la clase mean_squared_error del módulo sklearn.metrics. Entonces podemos sacar la raíz cuadrada del error cuadrático medio resultante. Mira el siguiente guión:

1
2
3
4
5
6
7
8
from sklearn.metrics import mean_squared_error
from math import sqrt

pred_train = model.predict(X_train)
print(np.sqrt(mean_squared_error(y_train,pred_train)))

pred = model.predict(X_test)
print(np.sqrt(mean_squared_error(y_test,pred)))

El resultado muestra el error cuadrático medio para los conjuntos de entrenamiento y prueba. Los resultados muestran que el rendimiento del modelo es mejor en el conjunto de entrenamiento ya que el valor del error cuadrático medio para el conjunto de entrenamiento es menor. Nuestro modelo está sobreajustado. La razón es obvia, solo teníamos 48 registros en el conjunto de datos. Intente entrenar modelos de regresión con un conjunto de datos más grande para obtener mejores resultados.

1
2
50.43599665058207
84.31961060849562

Conclusión

TensorFlow 2.0 es la última versión de la biblioteca TensorFlow de Google para el aprendizaje profundo. Este artículo cubre brevemente cómo crear modelos de clasificación y regresión con TensorFlow 2.0. Para tener una experiencia práctica, le sugiero que practique los ejemplos proporcionados en este artículo e intente crear modelos simples de regresión y clasificación con TensorFlow 2.0 usando otros conjuntos de datos.