Las redes neuronales recurrentes son redes neuronales que dependen de los datos anteriores, es decir que tienen "memoria".
Por ejemplo, al predecir si una foto es un tipo de flor, no depende de lo que se haya predecido antes pero en una red neuronal si. Son redes que predicen secuencias de datos como por ejemplo series de temperatura, o cotizaciones de bolsa, etc:
Para hacer este tipo de redes se usan nuevas capas que son:
En Keras las 3 capas se definen así:
from tensorflow.keras.layers import RNN from tensorflow.keras.layers import LSTM from tensorflow.keras.layers import GRU
Por ahora no vamos a contar como son estas neuronas pero su esquema es este:
Las fórmulas matemáticas de cada tipo de neurona se puede ver en RNN, LSTM & GRU
Más información:
Vamos a hacer una red neuronal que dado 24 temperatura (una por cada hora) obtener la temperatura que hará 12 horas despues.
def get_serie_tiempo(datetime_start,num_dias=30,pendiente=0.005,amplitud=5,ruido_amplitud=1): np.random.seed(7) num_datos = num_dias*24 x = np.linspace(0, num_dias * 2 * np.pi, num_datos) # Eje x (progresión del tiempo) fechas = pd.date_range(start=datetime_start, periods=num_datos, freq="h") tendencia = np.linspace(0, pendiente * num_datos, num_datos) # Tendencia ascendente onda = amplitud * np.sin(x) # Onda sinusoidal ruido = np.random.normal(0, ruido_amplitud, num_datos) # Ruido aleatorio datos = tendencia + onda + ruido return fechas,datos fechas,temperaturas=get_serie_tiempo(datetime(2025, 1, 1, 10, 0, 0),num_dias=200,ruido_amplitud=0.5) figure=plt.figure(figsize=(20,10)) axes = figure.add_subplot(2,1,1) axes.plot(fechas,temperaturas) axes_configure_labels(axes,"Datos originales","Tiempo","Temperatura")
y
también es una matriz.
def get_datos(serie_datos,tamanyo_ventana=24,adelanto_prediccion=12): size=len(serie_datos) x=[] y=[] for i in range(size-tamanyo_ventana-adelanto_prediccion): x.append(serie_datos[i:i+tamanyo_ventana]) y.append(serie_datos[i+tamanyo_ventana+adelanto_prediccion]) x=np.array(x) y=np.array(y) size_entrenamiento=math.floor(x.shape[0]*0.8) x_entrenamiento=x[0:size_entrenamiento] x_validacion=x[size_entrenamiento:] y_entrenamiento=y[0:size_entrenamiento] y_validacion=y[size_entrenamiento:] return x_entrenamiento.reshape(-1,tamanyo_ventana,1), y_entrenamiento.reshape(-1,1), x_validacion.reshape(-1,tamanyo_ventana,1), y_validacion.reshape(-1,1) scaler = MinMaxScaler() temperaturas_scaled = scaler.fit_transform(temperaturas.reshape(-1,1)).reshape(temperaturas.shape) x_entrenamiento, y_entrenamiento, x_validacion, y_validacion=get_datos(temperaturas_scaled,tamanyo_ventana=24,adelanto_prediccion=12)
En nuestro ejemplo lo que hemos hecho es que para cada 24 temperaturas (tamanyo_ventana=24
) , obtener la temperatura que habrá 12 horas después (adelanto_prediccion=12
).
Tambien hemos escalado los datos, lo cual es importante para que la red funcione mejor. Por último fíjate que tanto la x
como la y
son matrices x_entrenamiento.reshape(-1,tamanyo_ventana,1)
y y_entrenamiento.reshape(-1,1)
def get_model(shape): model=Sequential() model.add(Input(shape=shape)) model.add(GRU(24, activation='swish', return_sequences=True)) model.add(Dropout(0.1)) model.add(GRU(50, activation='swish', return_sequences=True )) model.add(Dropout(0.1)) model.add(GRU(24, activation='swish', return_sequences=False)) model.add(Dropout(0.1)) model.add(Dense(1, activation='linear')) model.compile(loss='mean_squared_error',optimizer="adam") return model def fit(model,x_entrenamiento, y_entrenamiento, x_validacion, y_validacion,epochs): history=model.fit(x_entrenamiento,y_entrenamiento,validation_data=(x_validacion,y_validacion),epochs=epochs,verbose=False) return history model=get_model(shape=x_entrenamiento.shape[1:]) history=fit(model,x_entrenamiento, y_entrenamiento, x_validacion, y_validacion,30)Fijarse que en las capas
GRU
hay que indicar return_sequences=True
excepto en la última que debe ser return_sequences=False
figure=plt.figure(figsize=(6,4)) axes = figure.add_subplot(1,1,1) axes.plot(history.history['loss'],label=f"Loss:{history.history['loss'][-1]:.3f}") axes.plot(history.history['val_loss'],label=f"Val Loss:{history.history['val_loss'][-1]:.3f}") axes_configure_labels(axes,"Loss por época","Épocas","MSE")
y_pred_entrenamiento=model.predict(x_entrenamiento) y_entrenamiento_inverse_transform=scaler.inverse_transform(y_entrenamiento) y_pred_entrenamiento_inverse_transform=scaler.inverse_transform(y_pred_entrenamiento) y_pred_validacion=model.predict(x_validacion) y_validacion_inverse_transform=scaler.inverse_transform(y_validacion) y_pred_validacion_inverse_transform=scaler.inverse_transform(y_pred_validacion) figure=plt.figure(figsize=(20,25)) axes = figure.add_subplot(4,1,1) axes.plot(y_entrenamiento_inverse_transform,label="Real") axes.plot(y_pred_entrenamiento_inverse_transform,label="Predicha") axes_configure_labels(axes,"Todos Entrenamiento","Tiempo","Temperatura") axes.set_xlim(xmin=0,xmax=y_entrenamiento_inverse_transform.shape[0]) axes.set_ylim(ymin=-6,ymax=16) axes = figure.add_subplot(4,1,2) axes.plot(y_validacion_inverse_transform,label="Real") axes.plot(y_pred_validacion_inverse_transform,label="Predicha") axes_configure_labels(axes,"Todos Validacion","Tiempo","Temperatura") axes.set_xlim(xmin=0,xmax=y_entrenamiento_inverse_transform.shape[0]) axes.set_ylim(ymin=-6,ymax=16) axes = figure.add_subplot(4,1,3) axes.plot(y_entrenamiento_inverse_transform,label="Real") axes.plot(y_pred_entrenamiento_inverse_transform,label="Predicha") axes_configure_labels(axes,"Últimos Entrenamiento","Tiempo","Temperatura") axes.set_xlim(xmin=y_entrenamiento_inverse_transform.shape[0]-500,xmax=y_entrenamiento_inverse_transform.shape[0]) axes.set_ylim(ymin=-6,ymax=16) axes = figure.add_subplot(4,1,4) axes.plot(y_validacion_inverse_transform,label="Real") axes.plot(y_pred_validacion_inverse_transform,label="Predicha") axes_configure_labels(axes,"Últimos Validacion","Tiempo","Temperatura") axes.set_xlim(xmin=y_validacion_inverse_transform.shape[0]-500,xmax=y_validacion_inverse_transform.shape[0]) axes.set_ylim(ymin=-6,ymax=16)