sábado, 30 de enero de 2021

Construyendo una red neuronal de regresión utilizando la API Sequential de Keras

Vamos a utilizar la API Sequential de Keras para crear una red neuronal, secuencial, entrenarla y evaluarla. Podemos utilizar esta red neuronal de regresión para hacer predicciones. Para poder trabajar tendremos que importar las librerías de tensorflow, numpy y keras.

import tensorflow as tf

import numpy as np

from tensorflow import keras

Antes de nada para tener un dataset de ejemplo sobre el que trabajar vamos a descargar un dataset de Scikit-Learn llamado fetch_california_housing() con datos numéricos de inmuebles de California.

from sklearn.datasets import fetch_california_housing

from sklearn.model_selection import train_test_split

from sklearn.preprocessing import StandardScaler

 

housing = fetch_california_housing()

 

X_train_full, X_test, y_train_full, y_test = train_test_split(housing.data, housing.target, random_state=42)

X_train, X_valid, y_train, y_valid = train_test_split(X_train_full, y_train_full, random_state=42)

 

scaler = StandardScaler()

X_train = scaler.fit_transform(X_train)

X_valid = scaler.transform(X_valid)

X_test = scaler.transform(X_test)

 

np.random.seed(42)

tf.random.set_seed(42)

Hacer predicciones con regresión es bastante similar a hacerlo con clasificación, una de las diferencias,  es el hecho de que la capa de salida es una única neurona (si sólo deseamos predecir un único valor), otra que  utilizamos la función de activación relu, y finalmente que la función de pérdida es el error cuadrático medio. Para este caso, como el dataset tiene bastante ruido, utilizaremos una capa oculta para evitar el sobreentrenamiento.

A continuación la creación de la red neuronal con la API de Keras.

model = keras.models.Sequential([

    keras.layers.Dense(30, activation="relu", input_shape=X_train.shape[1:]),

    keras.layers.Dense(1)

])

model.compile(loss="mean_squared_error", optimizer=keras.optimizers.SGD(lr=1e-3))

history = model.fit(X_train, y_train, epochs=20, validation_data=(X_valid, y_valid))

mse_test = model.evaluate(X_test, y_test)

X_new = X_test[:3]

y_pred = model.predict(X_new)

Como podemos ver, la API Sequential es bastante fácil de utilizar, pero si queremos crear redes neuronales con topologías más complejas que la secuencial, podemos utilizar la API Functional.

Construyendo redes neuronales complejas utilizando la API Functional de Keras

En este caso construiremos una red neuronal con capas ocultas y un atajo de este estilo.

Construyendo una red neuronal de regresión utilizando la API Sequential de Keras

El código con la API de keras  será como este.

entrada = keras.layers.Input(shape=X_train.shape[1:])

oculta1 = keras.layers.Dense(30, activation="relu")(entrada)

oculta2 = keras.layers.Dense(30, activation="relu")(oculta1)

concat = keras.layers.concatenate([entrada, oculta2])

salida = keras.layers.Dense(1)(concat)

model = keras.models.Model(inputs=[entrada], outputs=[salida])

Podemos ver un esquema de la red neuronal creada

model.summary()

 

esquema de la red neuronal creada  model.summary

Veamos lo que significan las líneas de código

En primer lugar necesitamos crear un objeto entrada, lo creamos especificando el tipo de modelo que queremos, incluyendo su forma y su tipo.

Después creamos una capa oculta densa con 30 neuronas utilizando la activación ReLU y le pasamos su entrada como si fuera una función, en nuestro caso (entrada).

Creamos una segunda capa oculta y la usamos de nuevo como si fuera una función, pasandole la salida de la primera capa oculta.

Después creamos la capa concatenada y una vez más la usamos como si fuera una función, concatenando la entrada y la salida de la segunda capa oculta en los parámetros de la función.

Creamos la capa de salida con una única neurona y sin función de activación y la usamos como una función pasandole como parámetro la salida de la capa de concatenación.

Finalmente creamos el modelo Keras, especificando cuales son sus entradas y sus salidas.

Una vez creado el modelo procedemos como siempre, compilándolo,  evaluándolo y utilizándolo para hacer predicciones.

model.compile(loss="mean_squared_error", optimizer=keras.optimizers.SGD(lr=1e-3))

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

                    validation_data=(X_valid, y_valid))

mse_test = model.evaluate(X_test, y_test)

y_pred = model.predict(X_new)

Pero ¿Que sucede si lo que queremos es enviar un subset de datos por el atajo y el otro por el camino habitual? Tal y como se muestra en el esquema.

Red neuronal Keras con dos entradas

entrada_A = keras.layers.Input(shape=[5], name="atajo")

entrada_B = keras.layers.Input(shape=[6], name="profunda")

oculta1 = keras.layers.Dense(30, activation="relu")(entrada_B)

oculta2 = keras.layers.Dense(30, activation="relu")(oculta1)

concat = keras.layers.concatenate([entrada_A, oculta2])

salida = keras.layers.Dense(1, name="salida")(concat)

model = keras.models.Model(inputs=[entrada_A, entrada_B], outputs=[salida])

El código es muy similar al anterior, sólo  que ahora en las entradas hemos añadido entrada_A y entrada_B ahora vamos a compilarlo, pero en vez de pasarle una sola matriz de entrada X_train le pasaremos dos matrices, X_train_A y X_train_B, igual deberemos hacer con X_valid para la evaluación y X_text para la predcción.


model.compile(loss="mse", optimizer=keras.optimizers.SGD(lr=1e-3))

 

X_train_A, X_train_B = X_train[:, :5], X_train[:, 2:]

X_valid_A, X_valid_B = X_valid[:, :5], X_valid[:, 2:]

X_test_A, X_test_B = X_test[:, :5], X_test[:, 2:]

X_new_A, X_new_B = X_test_A[:3], X_test_B[:3]

 

history = model.fit((X_train_A, X_train_B), y_train, epochs=20,

                    validation_data=((X_valid_A, X_valid_B), y_valid))

mse_test = model.evaluate((X_test_A, X_test_B), y_test)

y_pred = model.predict((X_new_A, X_new_B))

 


No hay comentarios:

Publicar un comentario