Código Texto Copiar en Drive
Cuaderno

Gemini
Copyright 2018 The TensorFlow Authors.

Gemini
Mostrar código

Gemini
Mostrar código

Gemini

Regresión básica: predicción de la eficiencia del combustible


Gemini

Gemini

En un problema de regresión, la meta es predecir la salida de un valor continuo, como un precio o una probabilidad. Comparemos esto con un problema de clasificación, donde la meta es seleccionar una clase de una lista de clases (por ejemplo, donde una imagen contiene una manzana o una naranja, reconocer qué fruta se muestra en la imagen).

Este tutorial usa el clásico conjunto de datos Auto MPG y demuestra cómo generar modelos para predecir la eficiencia del combustible de los automóviles de fines de 1970 y principios de 1980. Para ello, deberá brindarles a los modelos una descripción de muchos automóviles de ese período. Esta descripción incluye atributos como cilindros, desplazamiento, potencia y peso.

En este ejemplo se usa la API de Keras. (Visite los tutoriales y las guías de Keras para obtener más información).


Gemini
# Use seaborn for pairplot.
!pip install -q seaborn

Gemini
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns

# Make NumPy printouts easier to read.
np.set_printoptions(precision=3, suppress=True)

Gemini
import tensorflow as tf

from tensorflow import keras
from tensorflow.keras import layers

print(tf.__version__)

Gemini

El conjunto de datos Auto MPG

El conjunto de datos está disponible desde el repositorio UCI Machine Learning.


Gemini

Obtener los datos

Para empezar, use pandas para descargar e importar el conjunto de datos:


Gemini
url = 'http://archive.ics.uci.edu/ml/machine-learning-databases/auto-mpg/auto-mpg.data'
column_names = ['MPG''Cylinders''Displacement''Horsepower''Weight',
                'Acceleration''Model Year''Origin']

raw_dataset = pd.read_csv(url, names=column_names,
                          na_values='?', comment='\t',
                          sep=' ', skipinitialspace=True)

Gemini
dataset = raw_dataset.copy()
dataset.tail()

Gemini

Limpiar los datos

El conjunto de datos contiene algunos valores desconocidos:


Gemini
dataset.isna().sum()

Gemini

Descarte esas filas para simplificar este tutorial inicial:


Gemini
dataset = dataset.dropna()

Gemini

La columna "Origin" corresponde a una categoría, no es numérica. Entonces, el siguiente paso es aplicar la codificación en un solo paso de los valores en la columna con pd.get_dummies.

Nota: Puede configurar tf.keras.Model para que realice este tipo de transformación por usted, pero eso está fuera del alcance de este tutorial. Consulte los tutoriales Clasificar datos estructurados con las capas de preprocesamiento de Keras o Cargar datos CSV para ver ejemplos.


Gemini
dataset['Origin'] = dataset['Origin'].map({1'USA'2'Europe'3'Japan'})

Gemini
dataset = pd.get_dummies(dataset, columns=['Origin'], prefix='', prefix_sep='')
dataset.tail()

Gemini

Dividir los datos en conjuntos de entrenamiento y prueba

Ahora, divida los conjuntos de datos en un conjunto de entrenamiento y un conjunto de prueba. Usará el conjunto de prueba para la evaluación final de sus modelos.


Gemini
train_dataset = dataset.sample(frac=0.8, random_state=0)
test_dataset = dataset.drop(train_dataset.index)

Gemini

Inspeccionar los datos

Revise la distribución conjunta de algunos pares de columnas del conjunto de entrenamiento.

La fila superior sugiere que la eficiencia del combustible (MPG) es una función conjunta de todos los demás parámetros. Las otras filas indican que son funciones entre sí.


Gemini
sns.pairplot(train_dataset[['MPG''Cylinders''Displacement''Weight']], diag_kind='kde')

Gemini

Comprobemos también las estadísticas generales. Observe cómo cada característica cubre un rango muy distinto:


Gemini
train_dataset.describe().transpose()

Gemini

Separar las características de las etiquetas

Separe el valor de destino, la "etiqueta", de las características. Esta etiqueta es el valor que deberá predecir el modelo entrenado.


Gemini
train_features = train_dataset.copy()
test_features = test_dataset.copy()

train_labels = train_features.pop('MPG')
test_labels = test_features.pop('MPG')

Gemini

Normalización

En la tabla de estadísticas se puede ver con claridad lo distintos que son los rangos de cada característica:


Gemini
train_dataset.describe().transpose()[['mean''std']]

Gemini

Resulta muy práctico normalizar características que usan diferentes escalas y rangos.

Uno de los motivos por los que esto resulta importante es que las características se multiplican por los pesos del modelo. Por lo tanto, la escala de las salidas y la escala de los gradientes se ve afectada por la escala de las entradas.

Si bien un modelo podría converger sin implementar la normalización de las características, dicha normalización le aporta más estabilidad al entrenamiento.

Nota: Normalizar las características de codificación en un solo paso no presenta ninguna ventaja, solo se hace aquí para simplificar. Si desea obtener más información sobre cómo se usan las capas de preprocesamiento, consulte la guía Trabajar con capas de preprocesamiento y el tutorial Clasificar datos estructurados con las capas de preprocesamiento de Keras.


Gemini

La capa de normalización

tf.keras.layers.Normalization presenta un método simple y directo de agregar normalización de características a su modelo.

El primer paso consiste en crear la capa:


Gemini
normalizer = tf.keras.layers.Normalization(axis=-1)

Gemini

Luego, debe llamar Normalization.adapt para ajustar el estado de la capa de preprocesamiento a los datos:


Gemini
normalizer.adapt(np.array(train_features))

Gemini

Calcule la media y la desviación, y almacénelas en la capa:


Gemini
print(normalizer.mean.numpy())

Gemini

Cuando se llama a la capa, esta devuelve los datos de entrada, con cada característica normalizada de forma independiente:


Gemini
first = np.array(train_features[:1])

with np.printoptions(precision=2, suppress=True):
  print('First example:', first)
  print()
  print('Normalized:', normalizer(first).numpy())

Gemini

Regresión lineal

Antes de generar un modelo de red neuronal profunda, comience con la regresión lineal y use una y varias variables.


Gemini

Regresión lineal con una variable

Comience por aplicar una regresión lineal de una sola variable para predecir 'MPG' a partir de 'Horsepower'.

Al entrenar un modelo con tf.keras generalmente se comienza por definir la arquitectura del modelo. Use un modelo tf.keras.Sequential, que representa una secuencia de pasos.

Un modelo de regresión lineal de una variable consta de dos pasos:

  • Normalice las características de la entrada 'Horsepower' mediante el uso de la capa de preprocesamiento tf.keras.layers.Normalization.
  • Aplique una transformación lineal ($y = mx+b$) para producir 1 salida mediante el uso de una capa lineal (tf.keras.layers.Dense).

La cantidad de entradas se pueden establecer tanto mediante el argumento input_shape como de forma automática cuando el modelo se ejecute por primera vez.


Gemini

En primer lugar, cree un arreglo NumPy compuesto por las características de 'Horsepower'. Luego, cree instancias de tf.keras.layers.Normalization y ajuste su estado a los datos de horsepower:


Gemini
horsepower = np.array(train_features['Horsepower'])

horsepower_normalizer = layers.Normalization(input_shape=[1,], axis=None)
horsepower_normalizer.adapt(horsepower)

Gemini

Generar el modelo secuencial de Keras:


Gemini
horsepower_model = tf.keras.Sequential([
    horsepower_normalizer,
    layers.Dense(units=1)
])

horsepower_model.summary()

Gemini

Este modelo puede predecir 'MPG' a partir de 'Horsepower'.

Ejecute el modelo sin entrenar en los primeros 10 valores de 'Horsepower'. La salida no será buena, pero observe que tiene la forma esperada de (10, 1):


Gemini
horsepower_model.predict(horsepower[:10])

Gemini

Una vez que se haya generado el modelo, configure el procedimiento de entrenamiento a través del método Model.compile de Keras. Los argumentos más importantes para compilar son loss y optimizer, ya que estos definen qué se optimizará (mean_absolute_error) y cómo (mediante el uso de tf.keras.optimizers.Adam).


Gemini
horsepower_model.compile(
    optimizer=tf.keras.optimizers.Adam(learning_rate=0.1),
    loss='mean_absolute_error')

Gemini

Use Model.fit de Keras para ejecutar el entrenamiento durante 100 épocas:


Gemini
%%time
history = horsepower_model.fit(
    train_features['Horsepower'],
    train_labels,
    epochs=100,
    # Suppress logging.
    verbose=0,
    # Calculate validation results on 20% of the training data.
    validation_split = 0.2)

Gemini

Visualice el progreso del entrenamiento del modelo con ayuda de las estadísticas almacenadas en el objeto history:


Gemini
hist = pd.DataFrame(history.history)
hist['epoch'] = history.epoch
hist.tail()

Gemini
def plot_loss(history):
  plt.plot(history.history['loss'], label='loss')
  plt.plot(history.history['val_loss'], label='val_loss')
  plt.ylim([010])
  plt.xlabel('Epoch')
  plt.ylabel('Error [MPG]')
  plt.legend()
  plt.grid(True)

Gemini
plot_loss(history)

Gemini

Recopile los resultados del conjunto de prueba para después:


Gemini
test_results = {}

test_results['horsepower_model'] = horsepower_model.evaluate(
    test_features['Horsepower'],
    test_labels, verbose=0)

Gemini

Como se trata de una regresión lineal con una sola variable, es fácil ver las predicciones del modelo como una función de la entrada:


Gemini
x = tf.linspace(0.0250251)
y = horsepower_model.predict(x)

Gemini
def plot_horsepower(xy):
  plt.scatter(train_features['Horsepower'], train_labels, label='Data')
  plt.plot(x, y, color='k', label='Predictions')
  plt.xlabel('Horsepower')
  plt.ylabel('MPG')
  plt.legend()

Gemini
plot_horsepower(x, y)

Gemini

Regresión lineal con múltiples entradas


Gemini

Puede usar una configuración prácticamente idéntica para hacer predicciones basadas en múltiples entradas. Este modelo hace lo mismo que $y = mx+b$$y = mx+b$ con la diferencia de que $m$$m$ es una matriz y $x$$x$ es un vector.

Cree un modelo secuencial de Keras nuevamente donde la primera capa sea normalizer (tf.keras.layers.Normalization(axis=-1)) que anteriormente ya definió y adaptó a todo el conjunto de datos:


Gemini
linear_model = tf.keras.Sequential([
    normalizer,
    layers.Dense(units=1)
])

Gemini

Cuando llama Model.predict en un lote de entradas, produce salidas units=1 para cada ejemplo:


Gemini
linear_model.predict(train_features[:10])

Gemini

Cuando llama el modelo, sus matrices de peso se generarán; compruebe que los pesos kernel (the $m$$m$ in $y=mx+b$$y=mx+b$) tengan la misma forma que (9, 1):


Gemini
linear_model.layers[1].kernel

Gemini

Configure el modelo con Keras Model.compile y entrénelo con Model.fit durante 100 épocas:


Gemini
linear_model.compile(
    optimizer=tf.keras.optimizers.Adam(learning_rate=0.1),
    loss='mean_absolute_error')

Gemini
%%time
history = linear_model.fit(
    train_features,
    train_labels,
    epochs=100,
    # Suppress logging.
    verbose=0,
    # Calculate validation results on 20% of the training data.
    validation_split = 0.2)

Gemini

Usar todas las entradas en este modelo de regresión consigue un error de entrenamiento y validación mucho más bajo que horsepower_model, que tenía una sola entrada:


Gemini
plot_loss(history)

Gemini

Recopile los resultados del conjunto de prueba para después:


Gemini
test_results['linear_model'] = linear_model.evaluate(
    test_features, test_labels, verbose=0)

Gemini

Regresión con una red neuronal profunda (DNN)


Gemini

En la sección anterior, implementó dos modelos lineales tanto con una entrada como con múltiples entradas.

Aquí, implementará modelos de DNN de una sola entrada y de múltiples entradas.

El código es básicamente el mismo, con la diferencia de que el modelo se amplió para incluir algunas capas no lineales "ocultas". Con el término "ocultas" nos referimos a que no están directamente conectadas con las entradas y las salidas.


Gemini

Estos modelos contendrán algunas capas más que el modelo lineal:

  • La capa de normalización, de la misma forma que sucedió anteriormente (con horsepower_normalizer para un modelo de una sola entrada y normalizer para un modelo con múltiples entradas).
  • Dos capas Dense ocultas, no lineales con la función de activación no lineal ReLU (relu).
  • Una capa Dense lineal de una sola salida.

Ambos modelos usarán el mismo procedimiento de entrenamiento, por lo que el método compile se incluye en la función build_and_compile_model a continuación.


Gemini
def build_and_compile_model(norm):
  model = keras.Sequential([
      norm,
      layers.Dense(64, activation='relu'),
      layers.Dense(64, activation='relu'),
      layers.Dense(1)
  ])

  model.compile(loss='mean_absolute_error',
                optimizer=tf.keras.optimizers.Adam(0.001))
  return model

Gemini

Regresión usando una DNN y una sola entrada


Gemini

Cree un modelo de DNN con solo 'Horsepower' como entrada y horsepower_normalizer (definido anteriormente) como capa de normalización:


Gemini
dnn_horsepower_model = build_and_compile_model(horsepower_normalizer)

Gemini

Este modelo tiene bastantes parámetros entrenables más que el modelo lineal:


Gemini
dnn_horsepower_model.summary()

Gemini

Entrene el modelo con Model.fit de Keras:


Gemini
%%time
history = dnn_horsepower_model.fit(
    train_features['Horsepower'],
    train_labels,
    validation_split=0.2,
    verbose=0, epochs=100)

Gemini

Este modelo tiene un rendimiento ligeramente superior al modelo lineal horsepower_model de una sola entrada:


Gemini
plot_loss(history)

Gemini

Si traza estas predicciones como una función de 'Horsepower', notará que este modelo aprovecha la falta de linealidad que le aportan las capas ocultas:


Gemini
x = tf.linspace(0.0250251)
y = dnn_horsepower_model.predict(x)

Gemini
plot_horsepower(x, y)

Gemini

Recopile los resultados del conjunto de prueba para después:


Gemini
test_results['dnn_horsepower_model'] = dnn_horsepower_model.evaluate(
    test_features['Horsepower'], test_labels,
    verbose=0)

Gemini

Regresión usando una DNN y múltiples entradas


Gemini

Repita el proceso anterior usando todas las entradas. El rendimiento del modelo mejora levemente con el conjunto de datos de validación.


Gemini
dnn_model = build_and_compile_model(normalizer)
dnn_model.summary()

Gemini
%%time
history = dnn_model.fit(
    train_features,
    train_labels,
    validation_split=0.2,
    verbose=0, epochs=100)

Gemini
plot_loss(history)

Gemini

Recopile los resultados del conjunto de prueba:


Gemini
test_results['dnn_model'] = dnn_model.evaluate(test_features, test_labels, verbose=0)

Gemini

Rendimiento


Gemini

Dado que ya ha entrenado todos los modelos, puede consultar el rendimiento del conjunto de prueba:


Gemini
pd.DataFrame(test_results, index=['Mean absolute error [MPG]']).T

Gemini

Estos resultados coinciden con el error de validación que se observó durante el entrenamiento.


Gemini

Hacer predicciones

Ahora puede hacer predicciones con dnn_model en el conjunto de prueba usando Keras Model.predict y revisar la pérdida:


Gemini
test_predictions = dnn_model.predict(test_features).flatten()

a = plt.axes(aspect='equal')
plt.scatter(test_labels, test_predictions)
plt.xlabel('True Values [MPG]')
plt.ylabel('Predictions [MPG]')
lims = [050]
plt.xlim(lims)
plt.ylim(lims)
_ = plt.plot(lims, lims)


Gemini

Al parecer, el modelo predice bastante bien.

Ahora, compruebe la distribución de los errores:


Gemini
error = test_predictions - test_labels
plt.hist(error, bins=25)
plt.xlabel('Prediction Error [MPG]')
_ = plt.ylabel('Count')

Gemini

Si está satisfecho con el modelo, guárdelo para usarlo más tarde con Model.save:


Gemini
dnn_model.save('dnn_model.keras')

Gemini

Si vuelve a cargar el modelo, le da una salida idéntica:


Gemini
reloaded = tf.keras.models.load_model('dnn_model.keras')

test_results['reloaded'] = reloaded.evaluate(
    test_features, test_labels, verbose=0)

Gemini
pd.DataFrame(test_results, index=['Mean absolute error [MPG]']).T

Gemini

Conclusión

Este bloc de notas introdujo algunas técnicas para hacer frente a un problema de regresión. Aquí encontrará algunos consejos más que pueden ayudarle:

  • El error cuadrático medio (MSE) (tf.keras.losses.MeanSquaredError) y el error absoluto medio (MAE) (tf.keras.losses.MeanAbsoluteError) son funciones de pérdida comunes que se usan para problemas de regresión. MAE es menos susceptible a los valores atípicos. Para los problemas de clasificación se usan otras funciones de pérdida.
  • Asimismo, las métricas de evaluación que se usan para la regresión son distintas de las que se usan para la clasificación.
  • Cuando las características de los datos de entradas numéricas tienen valores con diferentes rangos, se debe escalar por separado cada característica al mismo rango.
  • El sobreajuste es un problema común para los modelos de DNN, aunque no fue un problema para este tutorial. Visite el tutorial Sobreajuste y subajuste para obtener más ayuda al respecto.