angle-uparrow-clockwisearrow-counterclockwisearrow-down-uparrow-leftatcalendarcard-listchatcheckenvelopefolderhouseinfo-circlepencilpeoplepersonperson-fillperson-plusphoneplusquestion-circlesearchtagtrashx

Predicción de valores con Deep Learning y Keras

Usando Keras podemos crear una caja negra Deep Learning que pueda predecir valores futuros

28 enero 2022
post main image

Tengo un conjunto de datos, muchas filas con N entradas y 1 salida, y quiero predecir el valor de salida para cualquier nueva combinación de valores de entrada. También soy un novato en ciencia de datos, pero las historias en Internet sobre Deep Learning sugieren que podemos crear fácilmente algún tipo de caja negra con algunas neuronas, nodos, en ella, y luego utilizar el conjunto de datos para entrenar la caja negra. Después de esto podemos alimentar cualquier entrada y nuestra caja negra nos da valores de salida con cierto margen de error. ¿Suena demasiado bien para ser verdad? ¿Es realmente tan fácil?

Empieza con KISS (Keep It Simple Stupid)

Cuando se busca en Internet "predicción de datos en python" se obtienen muchos resultados, por supuesto. Hay muchos ejemplos que me gustan, pero la mayoría son demasiado complejos para un novato. Predecir los precios de las acciones usando series de tiempo, demasiado complejo. Predecir el precio de la vivienda, mucho mejor. También hay un conjunto de datos sobre la calidad del vino. Me gusta el vino. Puede ser bueno, tal vez en otro momento.

En este post trato de resolver un problema trivial. Reemplazo la función

y = x0 + 2*x1

por:

  • un modelo de Regresión Lineal, y,
  • un Deep Learning, de hecho una red neuronal, una caja negra

Una gran ventaja es que puedo generar yo mismo el conjunto de datos. Esto también significa que puedo comparar las predicciones con los valores esperados.

Machine Learning: Regresión frente a clasificación

Para elegir el algoritmo adecuado, es importante entender primero si la tarea Machine Learning es un problema de regresión o de clasificación. La regresión y la clasificación son dos tipos de algoritmos Supervised Machine Learning . Supervised Machine Learning utiliza el concepto de utilizar conjuntos de datos con valores de salida conocidos para hacer predicciones.

La regresión es un algoritmo que puede ser entrenado con un conjunto de datos para predecir salidas que son valores numéricos, números. La Classificación es un algoritmo que se puede entrenar con un conjunto de datos para predecir salidas que son etiquetas, categorías, normalmente 0 y 1.

Ejemplo de regresión

Tenemos un conjunto de datos formado por filas con 2 entradas y una salida de 1, el valor de salida es un número que puede tener "cualquier" valor. Consideremos un conjunto de datos sobre viviendas en el que las entradas son el número de personas que pueden vivir en la casa y el número de habitaciones, y la salida es el precio.

 persons | rooms | price
---------+-------+--------
  5      |  4    | 20.000
  3      |  2    | 24.000

Si tenemos un conjunto de datos lo suficientemente grande, podemos utilizar un algoritmo de regresión para predecir el precio para cualquier combinación de personas y habitaciones. El resultado será 22.500, 18.100, etc.

Class Ejemplo de clasificación

Tenemos un conjunto de datos formado por filas con 3 entradas y una salida de 1, el valor de salida es un número que es 0 o 1. Consideremos un conjunto de datos sobre viviendas en el que las entradas son el número de personas que pueden vivir en la casa, el número de habitaciones, el precio, y la salida es 0 o 1 en función de si la casa es favorecida, o no, por las personas que buscan una casa en una página web.

 persons | rooms | price   | liked
---------+-------+---------+--------
  5      |  4    | 20.000  | 0
  3      |  2    | 24.000  | 1

Si tenemos un conjunto de datos lo suficientemente grande, podemos utilizar un algoritmo de clasificación para predecir si una casa gusta para cualquier combinación de personas, habitaciones y precio. El resultado será 0 (no gusta) o 1 (gusta).

Infraajuste y sobreajuste

Nuestro conjunto de datos se divide en un conjunto de datos de entrenamiento y un conjunto de datos de prueba. A partir de ellos podemos determinar si nuestro modelo o algoritmo funciona bien o mal.

Un ajuste insuficiente significa que el modelo no ha sido capaz de determinar las relaciones relevantes entre los datos. Probablemente el modelo es demasiado simple. Un ejemplo es intentar representar relaciones no lineales con un modelo lineal.

Infraajuste:

  • Funciona mal con los datos de entrenamiento
  • Funciona mal con los datos de prueba

La sobreadaptación significa que el modelo también determina las relaciones entre los datos y las fluctuaciones aleatorias. Probablemente el modelo es demasiado complejo, aprende demasiado bien.

Sobreajuste:

  • Funciona bien con los datos de entrenamiento
  • Funciona mal con los datos de prueba

Ambos casos pueden darse también cuando no hay suficientes datos en nuestro conjunto de datos.

Regresión lineal

Te sugiero que leas los ejemplos del estupendo tutorial 'Linear Regression in Python', ver enlaces más abajo. A continuación muestro mi versión con dos entradas, datos de entrenamiento y de prueba y la predicción de un valor. Como estamos modelando con Regresión Lineal, no es sorprendente que el coeficiente de determinación sea 1.0, y que sólo necesitemos una cantidad muy pequeña de datos de entrenamiento.

# Linear regression: y = x0 + 2*x1
import numpy as np
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split

# generate dataset
X_items = []
y_items = []
for x0 in range(0, 3):
    for x1 in range(3, 5):
        y = x0 + 2*x1
        X_items.append([x0, x1])
        y_items.append(y)

X = np.array(X_items).reshape((-1, 2))
y = np.array(y_items)
print('X = {}'.format(X))
print('y = {}'.format(y))

# split dataset in training and test data
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=1)
print('X_train = {}'.format(X_train))
print('y_train = {}'.format(y_train))
print('X_test = {}'.format(X_test))
print('y_test = {}'.format(y_test))

# create model
model = LinearRegression()

# mess up a training value
#X_train[0][0] += 2

# calculate optimal values of weights b0 and b1
model.fit(X_train, y_train)

# show results, mess up test data
print('model result:')
print('- intercept (b0) = {}'.format(model.intercept_))
print('- slope (b1) = {}'.format(model.coef_))
print('- coefficient of determination for training data = {}'.
    format(model.score(X_train, y_train)))
print('- coefficient of determination for test data = {}'.
    format(model.score(X_test, y_test)))

x = np.array([8, 9]).reshape((-1, 2))
y_pred = model.predict(x)
print('predicted response for x = {}: {}'.format(x, y_pred))

El script da la siguiente salida:

X = [[0 3]
 [0 4]
 [1 3]
 [1 4]
 [2 3]
 [2 4]]
y = [ 6  8  7  9  8 10]
X_train = [[2 3]
 [0 3]
 [1 4]
 [2 4]]
y_train = [ 8  6  9 10]
X_test = [[1 3]
 [0 4]]
y_test = [7 8]
model result:
- intercept (b0) = -3.552713678800501e-15
- slope (b1) = [1. 2.]
- coefficient of determination for training data = 1.0
- coefficient of determination for test data = 1.0
predicted response for x = [[8 9]]: [26.]

Para crear un poco de problemas he cambiado un valor de entrenamiento, ver arriba. Esto da el resultado:

model result:
- intercept (b0) = -2.3529411764705817
- slope (b1) = [0.52941176 2.76470588]
- coefficient of determination for training data = 0.9865546218487395
- coefficient of determination for test data = -0.5570934256055304
predicted response for x = [[8 9]]: [26.76470588]

Añadiendo más datos de entrenamiento obtenemos un mejor ajuste.

Deep Learning con Keras

Esto debería ser más como el enfoque de la caja negra. Simplemente añado algunas neuronas y capas y eso debería ser todo. Pero, ¿es realmente así? Aquí uso Keras porque parece ser muy popular. El siguiente ejemplo fue muy útil: 'Keras 101: A simple (and interpretable) Neural Network model for House Pricing regression', ver enlaces abajo. El trazado de la pérdida y el error medio tiene mucho sentido.

Haremos los siguientes pasos:

  • Cargar los datos
  • Definir el modelo
  • Compilar el modelo
  • Entrenar (ajustar) el modelo
  • Evaluar el modelo
  • Hacer predicciones

Cargar los datos Aquí generamos los datos nosotros mismos, ver también arriba.

Definir el modelo La primera capa densa necesita el conjunto de parámetros input_shape . Empecé con 100 neuronas en la primera capa, 50 en la segunda y 25 en la tercera. ¿Por qué? No tengo ni idea, no he investigado esto todavía.

Compilar el modelo No hay mucho que decir sobre esto.

Entrenar (ajustar) el modelo Estamos utilizando el parámetro validation_split, sin él no podemos trazar. Cuando se especifica validation_split parte de los datos de entrenamiento se utilizan para la validación. Los datos utilizados para la validación durante el ajuste pueden cambiar, probablemente es mejor utilizar datos fijos, de lo contrario obtendremos un ajuste diferente cada vez.

Evaluar el modelo Aquí utilizamos los datos de prueba.

Predicciones Simplemente use model.predict().

Por supuesto, aquí necesitamos más datos de entrenamiento. Pero tampoco es mucho más. También he añadido código para guardar y cargar el modelo. A continuación se muestra el código que he creado.

# Keras deep learning: y = x0 + 2*x1
from keras.models import Sequential, load_model
from keras.layers import Dense
import numpy as np
from plotly.subplots import make_subplots
import plotly.graph_objects as go
from sklearn.model_selection import train_test_split

use_saved_model = False
#use_saved_model = True

# create dataset
def fx(x0, x1):
    return x0 + 2*x1

X_items = []
y_items = []
for x0 in range(0, 18, 3):
    for x1 in range(2, 27, 3):
        y = fx(x0, x1)
        X_items.append([x0, x1])
        y_items.append(y)

X = np.array(X_items).reshape((-1, 2))
y = np.array(y_items)
print('X = {}'.format(X))
print('y = {}'.format(y))
X_data_shape = X.shape
print('X_data_shape = {}'.format(X_data_shape))

class DLM:
    
    def __init__(
        self,
        model_name='default_model',
    ):
        self.model_name = model_name
        self.dense_input_shape=(2, )
        self.dense_neurons = [100, 50, 25]
        self.fit_params = {
            'epochs': 100, 
            'validation_split': 0.1, 
            'verbose': 0,
        }

    def data_split_train_test(
        self,
        X,
        y,
    ):
        self.X_train, self.X_test, self.y_train, self.y_test = train_test_split(X, y, test_size=0.3, random_state=1)
        print('self.X_train = {}'.format(self.X_train))
        print('self.X_test = {}'.format(self.X_test))
        print('self.y_train = {}'.format(self.y_train))
        print('self.y_test = {}'.format(self.y_test))

        print('training data row count = {}'.format(len(self.y_train)))
        print('test data row count = {}'.format(len(self.y_test)))

        X_train_data_shape = self.X_train.shape
        print('X_train_data_shape = {}'.format(X_train_data_shape))

    def get_model(
        self,
    ):
        self.model = Sequential()
        self.model.add(Dense(self.dense_neurons[0], input_shape=self.dense_input_shape, activation='relu', name='dense_input'))
        for i, n in enumerate(self.dense_neurons[1:]):
            self.model.add(Dense(n, activation='relu', name='dense_hidden_' + str(i)))
        self.model.add(Dense(1, activation='linear', name='dense_output'))
        self.model.compile(optimizer='adam', loss='mse', metrics=['mean_absolute_error'])
        self.model_summary()
        return self.model

    def model_summary(
        self,
    ):
        self.model.summary()

    def train(
        self, 
        model,
        plot=False,
    ):
        history = model.fit(self.X_train, self.y_train, **self.fit_params)

        if plot:

            fig = go.Figure()
            fig.add_trace(go.Scattergl(y=history.history['loss'], name='Train'))
            fig.add_trace(go.Scattergl(y=history.history['val_loss'], name='Valid'))
            fig.update_layout(height=500, width=700, xaxis_title='Epoch', yaxis_title='Loss')
            fig.show()

            fig = go.Figure()
            fig.add_trace(go.Scattergl(y=history.history['mean_absolute_error'], name='Train'))
            fig.add_trace(go.Scattergl(y=history.history['val_mean_absolute_error'], name='Valid'))
            fig.update_layout(height=500, width=700, xaxis_title='Epoch', yaxis_title='Mean Absolute Error')
            fig.show() 

        return history

    def evaluate(
        self, 
        model,
    ):
        mse_nn, mae_nn = model.evaluate(self.X_test, self.y_test)
        print('Mean squared error on test data: ', mse_nn)
        print('Mean absolute error on test data: ', mae_nn)
        return mse_nn, mae_nn

    def predict(
        self,
        model,
        x0,
        x1,
        fx=None,
    ):
        x = np.array([[x0, x1]]).reshape((-1, 2))
        predictions = model.predict(x)
        expected = ''
        if fx is not None:
            expected = ', expected = {}'.format(fx(x0, x1))
        print('for x = {}, predictions = {}{}'.format(x, predictions, expected))
        return predictions

    def save_model(
        self,
        model,
    ):
        model.save(self.model_name)

    def load_saved_model(
        self,
    ):
        self.model = load_model(self.model_name)
        return self.model

# create & save or used saved
dlm = DLM()
if use_saved_model:
    model = dlm.load_saved_model()    
else:
    dlm.data_split_train_test(X, y)
    model = dlm.get_model()
    dlm.train(model, plot=True)
    dlm.evaluate(model)
    dlm.save_model(model)

# predict
dlm.predict(model, 4, 17, fx=fx)
dlm.predict(model, 23, 79, fx=fx)
dlm.predict(model, 40, 33, fx=fx)

El script da la siguiente salida, excluyendo los datos de entrada:

training data row count = 37
test data row count = 17
X_train_data_shape = (37, 2)
2022-01-28 16:00:30.598860: W tensorflow/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libcuda.so.1'; dlerror: libcuda.so.1: cannot open shared object file: No such file or directory
2022-01-28 16:00:30.598886: W tensorflow/stream_executor/cuda/cuda_driver.cc:269] failed call to cuInit: UNKNOWN ERROR (303)
2022-01-28 16:00:30.598911: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:156] kernel driver does not appear to be running on this host (myra): /proc/driver/nvidia/version does not exist
2022-01-28 16:00:30.599110: I tensorflow/core/platform/cpu_feature_guard.cc:151] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations:  AVX2 FMA
To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.
Model: "sequential"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 dense_input (Dense)         (None, 100)               300       
                                                                 
 dense_hidden_0 (Dense)      (None, 50)                5050      
                                                                 
 dense_hidden_1 (Dense)      (None, 25)                1275      
                                                                 
 dense_output (Dense)        (None, 1)                 26        
                                                                 
=================================================================
Total params: 6,651
Trainable params: 6,651
Non-trainable params: 0
_________________________________________________________________
1/1 [==============================] - 0s 25ms/step - loss: 0.1018 - mean_absolute_error: 0.2752
Mean squared error on test data:  0.10178931057453156
Mean absolute error on test data:  0.27519676089286804
2022-01-28 16:00:33.549267: W tensorflow/python/util/util.cc:368] Sets are not currently considered sequences, but this may change in the future, so consider avoiding using them.
for x = [[ 4 17]], predictions = [[38.0433]], expected = 38
for x = [[23 79]], predictions = [[177.94098]], expected = 181
for x = [[40 33]], predictions = [[103.54724]], expected = 106

Mejorar el rendimiento de Deep Learning

Mientras escribía este post cambié el número de neuronas, las capas densas, el parámetro validation_split. Todo ello dio lugar a algunos cambios, a veces buenos, a veces malos. La mayor mejora sin duda es añadir más datos de entrenamiento, pero ¿cuánto es suficiente?

Resumen

Lo más importante que he aprendido es que Deep Learning requiere un gran conjunto de datos, cuanto más grande mejor. ¿Me gusta la caja negra? Sí, y hasta ahora no he mirado realmente dentro. Ahora puedo utilizarlo como punto de partida para algunos proyectos del mundo real. También hay cosas como la normalización de las entradas, la adición de pesos a las entradas. Mucho más para leer ...

Enlaces / créditos

How to find the value for Keras input_shape/input_dim?
https://www.machinecurve.com/index.php/2020/04/05/how-to-find-the-value-for-keras-input_shape-input_dim

Keras 101: A simple (and interpretable) Neural Network model for House Pricing regression
https://towardsdatascience.com/keras-101-a-simple-and-interpretable-neural-network-model-for-house-pricing-regression-31b1a77f05ae

Keras examples
https://keras.io/examples

Linear Regression in Python
https://realpython.com/linear-regression-in-python

Predictive Analysis in Python
https://medium.com/my-data-camp-journey/predictive-analysis-in-python-97ca5b64e97f

Regression Tutorial with the Keras Deep Learning Library in Python
https://machinelearningmastery.com/regression-tutorial-keras-deep-learning-library-python

Deje un comentario

Comente de forma anónima o inicie sesión para comentar.

Comentarios

Deje una respuesta.

Responda de forma anónima o inicie sesión para responder.