Tutorial de RNN (red neuronal recurrente): ejemplo de TensorFlow

¿Por qué necesitamos una red neuronal recurrente (RNN)?

La red neuronal recurrente (RNN) le permite modelar unidades de memoria para conservar datos y modelar dependencias a corto plazo. También se utiliza en pronósticos de series de tiempo para la identificación de correlaciones y patrones de datos. También ayuda a producir resultados predictivos para datos secuenciales al ofrecer un comportamiento similar al del cerebro humano.

La estructura de una red neuronal artificial es relativamente simple y se trata principalmente de multiplicación de matrices. Durante el primer paso, las entradas se multiplican por pesos inicialmente aleatorios y el sesgo se transforma con una función de activación y los valores de salida se utilizan para hacer una predicción. Este paso da una idea de qué tan lejos está la red de la realidad.

La métrica aplicada es la pérdida. Cuanto mayor sea la función de pérdida, más tonto será el modelo. Para mejorar el conocimiento de la red, se requiere cierta optimización ajustando los pesos de la red. El descenso de gradiente estocástico es el método que se empleayed para cambiar los valores de los pesos en la dirección correcta. Una vez realizado el ajuste, la red puede utilizar otro lote de datos para probar sus nuevos conocimientos.

Afortunadamente, el error es menor que antes, aunque no lo suficientemente pequeño. El paso de optimización se realiza de forma iterativa hasta que se minimiza el error, es decir, no se puede extraer más información.

El problema de este tipo de modelo es que no tiene memoria. Significa que la entrada y la salida son independientes. En otras palabras, al modelo no le importa lo que vino antes. Plantea algunas dudas cuando es necesario predecir series de tiempo o oraciones porque la red necesita tener información sobre datos históricos o palabras pasadas.

Para superar este problema, un nuevo tipo de archiSe ha desarrollado una tecnología: Red neuronal recurrente (RNN en adelante)

¿Qué es una red neuronal recurrente (RNN)?

A Red neuronal recurrente (RNN) es una clase de Red neuronal artificial en el que la conexión entre diferentes nodos forma un gráfico dirigido para dar un comportamiento dinámico temporal. Ayuda a modelar datos secuenciales que se derivan de redes de alimentación directa. Funciona de manera similar al cerebro humano para ofrecer resultados predictivos.

Una red neuronal recurrente se parece bastante a una red neuronal tradicional, excepto que se agrega un estado de memoria a las neuronas. El cálculo para incluir una memoria es sencillo.

Imagine un modelo simple con una sola neurona alimentada por un lote de datos. En una red neuronal tradicional, el modelo produce la salida multiplicando la entrada por el peso y la función de activación. Con un RNN, esta salida se envía a sí misma varias veces. Llamamos hora de caminar la cantidad de tiempo que la salida se convierte en la entrada de la siguiente multiplicación de matrices.

Por ejemplo, en la imagen siguiente, puede ver que la red está compuesta por una neurona. La red calcula la multiplicación de matrices entre la entrada y el peso y agrega no linealidad con la función de activación. Se convierte en la salida en t-1. Esta salida es la entrada de la segunda multiplicación de matrices.

Red neuronal recurrente (RNN)
Red neuronal recurrente (RNN)

A continuación, codificamos un RNN simple en TensorFlow para comprender el paso y también la forma de la salida.

La red está compuesta por:

  • Cuatro entradas
  • Seis neuronas
  • pasos de 2 veces

La red procederá como se muestra en la siguiente imagen.

Red neuronal recurrente (RNN)

La red se llama 'recurrente' porque realiza lo mismo operación en cada casilla activada. La red calculó los pesos de las entradas y la salida anterior antes de utilizar una función de activación.

import numpy as np
import tensorflow as tf
n_inputs = 4
n_neurons = 6
n_timesteps = 2
The data is a sequence of a number from 0 to 9 and divided into three batches of data.
## Data 
X_batch = np.array([
        [[0, 1, 2, 5], [9, 8, 7, 4]], # Batch 1
        [[3, 4, 5, 2], [0, 0, 0, 0]], # Batch 2
        [[6, 7, 8, 5], [6, 5, 4, 2]], # Batch 3
    ])

Podemos construir la red con un marcador de posición para los datos, la etapa recurrente y la salida.

  1. Definir el marcador de posición para los datos.
X = tf.placeholder(tf.float32, [None, n_timesteps, n_inputs])

Aquí:

  • Ninguno: Desconocido y tomará el tamaño del lote.
  • n_timesteps: número de veces que la red enviará la salida a la neurona
  • n_inputs: número de entradas por lote
  1. Definir la red recurrente

Como se menciona en la imagen de arriba, la red está compuesta por 6 neuronas. La red calculará dos productos escalares:

  • Ingrese datos con el primer conjunto de pesos (es decir, 6: igual al número de neuronas)
  • Salida anterior con un segundo conjunto de pesos (es decir, 6: correspondiente al número de salida)

Tenga en cuenta que, durante el primer avance, los valores de la salida anterior son iguales a ceros porque no tenemos ningún valor disponible.

El objeto para construir un RNN es tf.contrib.rnn.BasicRNNCell con el argumento num_units para definir el número de entradas

basic_cell = tf.contrib.rnn.BasicRNNCell(num_units=n_neurons)

Ahora que la red está definida, puede calcular las salidas y los estados.

outputs, states = tf.nn.dynamic_rnn(basic_cell, X, dtype=tf.float32)

Este objeto utiliza un bucle interno para multiplicar las matrices el número apropiado de veces.

Tenga en cuenta que la neurona recurrente es una función de todas las entradas de los pasos de tiempo anteriores. Así es como la red construye su propia memoria. La información del tiempo anterior puede propagarse en el futuro. Esta es la magia de la red neuronal recurrente

## Define the shape of the tensor
X = tf.placeholder(tf.float32, [None, n_timesteps, n_inputs])
## Define the network
basic_cell = tf.contrib.rnn.BasicRNNCell(num_units=n_neurons)
outputs, states = tf.nn.dynamic_rnn(basic_cell, X, dtype=tf.float32)
init = tf.global_variables_initializer()
init = tf.global_variables_initializer()
with tf.Session() as sess:
    init.run()
    outputs_val = outputs.eval(feed_dict={X: X_batch})
print(states.eval(feed_dict={X: X_batch}))
[[ 0.38941205 -0.9980438   0.99750966  0.7892596   0.9978241   0.9999997 ]
 [ 0.61096436  0.7255889   0.82977575 -0.88226104  0.29261455 -0.15597084]
 [ 0.62091285 -0.87023467  0.99729395 -0.58261937  0.9811445   0.99969864]]

Para fines explicativos, se imprimen los valores del estado anterior. El resultado impreso arriba muestra el resultado del último estado. Ahora imprima todos los resultados, puede notar que los estados son los resultados anteriores de cada lote. Es decir, la salida anterior contiene la información sobre toda la secuencia.

print(outputs_val)    
print(outputs_val.shape)    
[[[-0.75934666 -0.99537754  0.9735819  -0.9722234  -0.14234993
   -0.9984044 ]
  [ 0.99975264 -0.9983206   0.9999993  -1.         -0.9997506
   -1.        ]]

 [[ 0.97486496 -0.98773265  0.9969686  -0.99950117 -0.7092863
   -0.99998885]
  [ 0.9326837   0.2673438   0.2808514  -0.7535883  -0.43337247
    0.5700631 ]]

 [[ 0.99628735 -0.9998728   0.99999213 -0.99999976 -0.9884324
   -1.        ]
  [ 0.99962527 -0.9467421   0.9997403  -0.99999714 -0.99929446
   -0.9999795 ]]]
(3, 2, 6)

Red neuronal recurrente (RNN)

La salida tiene la forma de (3, 2, 6):

  • 3: Número de lotes
  • 2: Número del paso de tiempo
  • 6: Número de neuronas

La optimización de una red neuronal recurrente es idéntica a la de una red neuronal tradicional. Verá con más detalle cómo optimizar el código en la siguiente parte de este tutorial de Red neuronal recurrente.

Aplicaciones de RNN

RNN tiene múltiples usos, especialmente cuando se trata de predecir el futuro. En la industria financiera, RNN puede resultar útil para predecir los precios de las acciones o el signo de la dirección del mercado de valores (es decir, positivo o negativo).

RNN es útil para un coche autónomo ya que puede evitar un accidente automovilístico anticipando la trayectoria del vehículo.

RNN se utiliza ampliamente en análisis de texto, subtítulos de imágenes, análisis de sentimientos y traducción automática. Por ejemplo, se puede utilizar una reseña de una película para comprender el sentimiento que percibió el espectador después de ver la película. Automatizar esta tarea es muy útil cuando la productora cinematográfica no tiene tiempo suficiente para revisar, etiquetar, consolidar y analizar las reseñas. La máquina puede hacer el trabajo con un mayor nivel de precisión.

Limitaciones de RNN

En teoría, se supone que RNN transporta la información varias veces. Sin embargo, es bastante difícil propagar toda esta información cuando el paso de tiempo es demasiado largo. Cuando una red tiene demasiadas capas profundas, se vuelve imposible de entrenar. Este problema se llama: problema de gradiente de fuga. Si recuerdas, la red neuronal actualiza el peso mediante el algoritmo de descenso de gradiente. Los gradientes se hacen más pequeños a medida que la red avanza hacia capas inferiores.

En conclusión, los gradientes se mantienen constantes, lo que significa que no hay margen de mejora. El modelo aprende de un cambio en el gradiente; este cambio afecta la salida de la red. Sin embargo, si la diferencia en el gradiente es demasiado pequeña (es decir, los pesos cambian un poco), la red no puede aprender nada y, por lo tanto, la salida. Por lo tanto, una red que enfrenta un problema de gradiente evanescente no puede converger hacia una buena solución.

Mejora LSTM

Para superar el posible problema del gradiente de desaparición que enfrenta RNN, tres investigadores, Hochreiter, Schmidhuber y Bengio, mejoraron el RNN con un architectura llamada memoria larga a corto plazo (LSTM). En resumen, LSMT proporciona a la red información del pasado relevante a tiempos más recientes. La máquina utiliza una mejor architecnología para seleccionar y transportar información a later en las transacciones.

LSTM archiLa tecnología está disponible en TensorFlow, tf.contrib.rnn.LSTMCell. LSTM está fuera del alcance del tutorial. Puedes consultar el funcionario. documentación para mayor información

RNN en series de tiempo

En este tutorial de TensorFlow RNN, utilizará un RNN con datos de series de tiempo. Las series de tiempo dependen del tiempo anterior, lo que significa que los valores pasados ​​incluyen información relevante de la que la red puede aprender. La idea detrás de la predicción de series temporales es estimar el valor futuro de una serie, digamos, el precio de las acciones, la temperatura, el PIB, etc.

La preparación de datos para Keras RNN y series temporales puede ser un poco complicada. En primer lugar, el objetivo es predecir el siguiente valor de la serie, es decir, utilizará la información pasada para estimar el valor en t + 1. La etiqueta es igual a la secuencia de entrada y shifted un período por delante. En segundo lugar, el número de entradas se establece en 1, es decir, una observación por vez. Por último, el paso de tiempo es igual a la secuencia del valor numérico. Por ejemplo, si establece el paso de tiempo en 10, la secuencia de entrada regresará diez veces consecutivas.

Mire el gráfico a continuación, hemos representado los datos de la serie temporal a la izquierda y una secuencia de entrada ficticia a la derecha. Crea una función para devolver un conjunto de datos con valor aleatorio para cada día desde enero de 2001 hasta diciembre de 2016.

# To plot pretty figures
%matplotlib inline
import matplotlib
import matplotlib.pyplot as plt
import pandas as pd
def create_ts(start = '2001', n = 201, freq = 'M'):
    rng = pd.date_range(start=start, periods=n, freq=freq)
    ts = pd.Series(np.random.uniform(-18, 18, size=len(rng)), rng).cumsum()
    return ts
ts= create_ts(start = '2001', n = 192, freq = 'M')
ts.tail(5)

Salida

2016-08-31    -93.459631
2016-09-30    -95.264791
2016-10-31    -95.551935
2016-11-30   -105.879611
2016-12-31   -123.729319
Freq: M, dtype: float64
ts = create_ts(start = '2001', n = 222)

# Left
plt.figure(figsize=(11,4))
plt.subplot(121)
plt.plot(ts.index, ts)
plt.plot(ts.index[90:100], ts[90:100], "b-", linewidth=3, label="A training instance")
plt.title("A time series (generated)", fontsize=14)

# Right
plt.subplot(122)
plt.title("A training instance", fontsize=14)
plt.plot(ts.index[90:100], ts[90:100], "b-", markersize=8, label="instance")
plt.plot(ts.index[91:101], ts[91:101], "bo", markersize=10, label="target", markerfacecolor='red')
plt.legend(loc="upper left")
plt.xlabel("Time")

plt.show()

RNN en series temporales

La parte derecha del gráfico muestra todas las series. Comenzó en 2001 y finaliza en 2019. No tiene sentido alimentar todos los datos en la red; en cambio, es necesario crear un lote de datos con una longitud igual al paso de tiempo. Este lote será la variable X. La variable Y es la misma que X pero shifted por un período (es decir, desea pronosticar t+1).

Ambos vectores tienen la misma longitud. Puedes verlo en la parte derecha del gráfico anterior. La línea representa los diez valores de la entrada X, mientras que los puntos rojos son los diez valores de la etiqueta, Y. Tenga en cuenta que la etiqueta comienza un período antes de X y termina un período después.

Cree un RNN para predecir series temporales en TensorFlow

Ahora, en este entrenamiento de RNN, es el momento de crear su primer RNN para predecir la serie anterior. Debe especificar algunos hiperparámetros (los parámetros del modelo, es decir, el número de neuronas, etc.) para el modelo:

  • Número de entrada: 1
  • Hora de caminar (windows en series de tiempo): 10
  • Número de neuronas: 120
  • Número de salida: 1

Su red aprenderá en una secuencia de 10 días y contendrá 120 neuronas recurrentes. Alimenta el modelo con una entrada, es decir, un día. Siéntase libre de cambiar los valores para ver si el modelo mejoró.

Antes de construir el modelo, es necesario dividir el conjunto de datos en un conjunto de entrenamiento y un conjunto de prueba. El conjunto de datos completo tiene 222 puntos de datos; Utilizará los primeros 201 puntos para entrenar el modelo y los últimos 21 puntos para probar su modelo.

Después de definir un tren y un conjunto de prueba, debe crear un objeto que contenga los lotes. En estos lotes, tiene valores X e Y. Recuerde que los valores de X tienen un retraso de un período. Por lo tanto, utiliza las primeras 200 observaciones y el paso de tiempo es igual a 10. El objeto X_batches debe contener 20 lotes de tamaño 10*1. Los y_batches tienen la misma forma que el objeto X_batches pero con un punto por delante.

Paso 1) Crea el tren y prueba.

En primer lugar, conviertes la serie en una numpy formación; entonces defines el windows (es decir, la cantidad de tiempo del que aprenderá la red), la cantidad de entradas, salidas y el tamaño del conjunto de trenes como se muestra en el ejemplo de TensorFlow RNN a continuación.

series = np.array(ts)
n_windows = 20   
n_input =  1
n_output = 1
size_train = 201

Después de eso, simplemente divide la matriz en dos conjuntos de datos.

## Split data
train = series[:size_train]
test = series[size_train:]
print(train.shape, test.shape)
(201,) (21,)

Paso 2) Cree la función para devolver X_batches e y_batches

Para hacerlo más fácil, puede crear una función que devuelva dos matrices diferentes, una para X_batches y otra para y_batches.

Escribamos una función RNN TensorFlow para construir los lotes.

Tenga en cuenta que los lotes X están retrasados ​​por un período (tomamos el valor t-1). La salida de la función debe tener tres dimensiones. Las primeras dimensiones equivalen al número de lotes, la segunda al tamaño del windows y el último el número de entrada.

La parte complicada es seleccionar los puntos de datos correctamente. Para los puntos de datos X, elige las observaciones de t = 1 a t =200, mientras que para el punto de datos Y, devuelve las observaciones de t = 2 a 201. Una vez que tenga los puntos de datos correctos, es sencillo remodelar las series.

Para construir el objeto con los lotes, debe dividir el conjunto de datos en diez lotes de igual longitud (es decir, 20). Puede utilizar el método de remodelación y pasar -1 para que la serie sea similar al tamaño del lote. El valor 20 es el número de observaciones por lote y 1 es el número de entradas.

Debes hacer el mismo paso pero para la etiqueta.

Tenga en cuenta que es necesario shift los datos al número de veces que desea pronosticar. Por ejemplo, si desea predecir con antelación, entonces shift la serie en 1. Si desea pronosticar dos días, entonces shift los datos por 2.

x_data = train[:size_train-1]: Select all the training instance minus one day
X_batches = x_data.reshape(-1, windows, input): create the right shape for the batch e.g (10, 20, 1)
def create_batches(df, windows, input, output):
    ## Create X         
        x_data = train[:size_train-1] # Select the data
        X_batches = x_data.reshape(-1, windows, input)  # Reshape the data 
    ## Create y
        y_data = train[n_output:size_train]
        y_batches = y_data.reshape(-1, windows, output)
        return X_batches, y_batches

Ahora que la función está definida, puede llamarla para crear los lotes como se muestra en el siguiente ejemplo de RNN.

X_batches, y_batches = create_batches(df = train,
                                      windows = n_windows,
                                      input = n_input,
                                      output = n_output)

Puede imprimir la forma para asegurarse de que las dimensiones sean correctas.

print(X_batches.shape, y_batches.shape)
(10, 20, 1) (10, 20, 1)

Debe crear el conjunto de prueba con solo un lote de datos y 20 observaciones.

Tenga en cuenta que, si pronostica días tras días, significa que el segundo valor previsto se basará en el valor real del primer día (t+1) del conjunto de datos de prueba. De hecho, se conocerá el verdadero valor.

Si desea pronosticar t+2 (es decir, con dos días de antelación), debe utilizar el valor previsto t+1; Si va a predecir t+3 (con tres días de anticipación), debe usar el valor predicho t+1 y t+2. Tiene sentido que sea difícil predecir con precisión t+n días de antelación.

X_test, y_test = create_batches(df = test, windows = 20,input = 1, output = 1)
print(X_test.shape, y_test.shape)
(10, 20, 1) (10, 20, 1)

Muy bien, el tamaño de tu lote está listo, puedes construir el RNN architectura. Recuerda, tienes 120 neuronas recurrentes.

Paso 3) Construye el modelo

Para crear el modelo, es necesario definir tres partes:

  1. La variable con los tensores.
  2. el RNN
  3. La pérdida y la optimización.

Paso 3.1) Variables

Debe especificar las variables X e y con la forma adecuada. Este paso es trivial. El tensor tiene la misma dimensión que los objetos X_batches e y_batches.

Por ejemplo, el tensor X es un marcador de posición (consulte el tutorial sobre Introducción a Flujo tensor para refrescar su mente sobre la declaración de variables) tiene tres dimensiones:

  • Nota: tamaño del lote
  • n_windows: Longitud del windows. es decir, el número de veces que el modelo mira hacia atrás
  • n_input: número de entrada

El resultado es:

tf.placeholder(tf.float32, [None, n_windows, n_input])
## 1. Construct the tensors
X = tf.placeholder(tf.float32, [None, n_windows, n_input])   
y = tf.placeholder(tf.float32, [None, n_windows, n_output])

Paso 3.2) Crear el RNN

En la segunda parte de este ejemplo de RNN TensorFlow, debe definir el architectura de la red. Como antes, utiliza el objeto BasicRNNCell ydynamic_rnn del estimador TensorFlow.

## 2. create the model
basic_cell = tf.contrib.rnn.BasicRNNCell(num_units=r_neuron, activation=tf.nn.relu)   
rnn_output, states = tf.nn.dynamic_rnn(basic_cell, X, dtype=tf.float32)   

La siguiente parte es un poco más complicada pero permite un cálculo más rápido. Debe transformar la salida de la ejecución en una capa densa y luego convertirla nuevamente para que tenga la misma dimensión que la entrada.

stacked_rnn_output = tf.reshape(rnn_output, [-1, r_neuron])          
stacked_outputs = tf.layers.dense(stacked_rnn_output, n_output)       
outputs = tf.reshape(stacked_outputs, [-1, n_windows, n_output])  

Paso 3.3) Crear la pérdida y optimización.

La optimización del modelo depende de la tarea que esté realizando. En el tutorial anterior sobre CNN, su objetivo era clasificar imágenes; en este tutorial de RNN, el objetivo es ligeramente diferente. Se le pide que haga una predicción sobre una variable continua en comparación con una clase.

Esta diferencia es importante porque cambiará el problema de optimización. El problema de optimización para una variable continua es minimizar el error cuadrático medio. Para construir estas métricas en TF, puede utilizar:

  • tf.reduce_sum(tf.square(salidas – y))

El resto del código RNN es el mismo que antes; utiliza un optimizador Adam para reducir la pérdida (es decir, MSE):

  • tf.train.AdamOptimizer(tasa_de_aprendizaje=tasa_de_aprendizaje)
  • optimizador.minimizar (pérdida)

Eso es todo, puedes empacar todo junto y tu modelo estará listo para entrenar.

tf.reset_default_graph()
r_neuron = 120    

## 1. Construct the tensors
X = tf.placeholder(tf.float32, [None, n_windows, n_input])   
y = tf.placeholder(tf.float32, [None, n_windows, n_output])

## 2. create the model
basic_cell = tf.contrib.rnn.BasicRNNCell(num_units=r_neuron, activation=tf.nn.relu)   
rnn_output, states = tf.nn.dynamic_rnn(basic_cell, X, dtype=tf.float32)              

stacked_rnn_output = tf.reshape(rnn_output, [-1, r_neuron])          
stacked_outputs = tf.layers.dense(stacked_rnn_output, n_output)       
outputs = tf.reshape(stacked_outputs, [-1, n_windows, n_output])   

## 3. Loss + optimization
learning_rate = 0.001  
 
loss = tf.reduce_sum(tf.square(outputs - y))    
optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate)         
training_op = optimizer.minimize(loss)                                          

init = tf.global_variables_initializer() 

Entrenará el modelo utilizando 1500 épocas e imprimirá la pérdida cada 150 iteraciones. Una vez que se entrena el modelo, se evalúa el modelo en el conjunto de prueba y se crea un objeto que contiene las predicciones como se muestra en el siguiente ejemplo de Red neuronal recurrente.

iteration = 1500 

with tf.Session() as sess:
    init.run()
    for iters in range(iteration):
        sess.run(training_op, feed_dict={X: X_batches, y: y_batches})
        if iters % 150 == 0:
            mse = loss.eval(feed_dict={X: X_batches, y: y_batches})
            print(iters, "\tMSE:", mse)
    
    y_pred = sess.run(outputs, feed_dict={X: X_test})
0 	MSE: 502893.34
150 	MSE: 13839.129
300 	MSE: 3964.835
450 	MSE: 2619.885
600 	MSE: 2418.772
750 	MSE: 2110.5923
900 	MSE: 1887.9644
1050 	MSE: 1747.1377
1200 	MSE: 1556.3398
1350 	MSE: 1384.6113

Por fin, en este tutorial de aprendizaje profundo de RNN, puede trazar el valor real de la serie con el valor previsto. Si su modelo está corregido, los valores predichos deben colocarse encima de los valores reales.

Como puedes ver, el modelo tiene margen de mejora. Depende de usted cambiar los hiperparámetros como el windows, el tamaño del lote del número de neuronas recurrentes.

plt.title("Forecast vs Actual", fontsize=14)
plt.plot(pd.Series(np.ravel(y_test)), "bo", markersize=8, label="Actual", color='green')
plt.plot(pd.Series(np.ravel(y_pred)), "r.", markersize=8, label="Forecast", color='red')
plt.legend(loc="lower left")
plt.xlabel("Time")

plt.show()
Pronóstico versus real

Pronóstico versus real

Resumen

Una red neuronal recurrente es robusta. architectura para tratar series temporales o análisis de texto. La salida del estado anterior es retroalimentación para preservar la memoria de la red a lo largo del tiempo o secuencia de palabras.

En TensorFlow, puedes usar lo siguientewing Códigos para entrenar una red neuronal recurrente de TensorFlow para series temporales:

Parámetros del modelo.

n_windows = 20   
n_input =  1
n_output = 1
size_train = 201

Definir el modelo

X = tf.placeholder(tf.float32, [None, n_windows, n_input])   
y = tf.placeholder(tf.float32, [None, n_windows, n_output])

basic_cell = tf.contrib.rnn.BasicRNNCell(num_units=r_neuron, activation=tf.nn.relu)   
rnn_output, states = tf.nn.dynamic_rnn(basic_cell, X, dtype=tf.float32)              

stacked_rnn_output = tf.reshape(rnn_output, [-1, r_neuron])          
stacked_outputs = tf.layers.dense(stacked_rnn_output, n_output)       
outputs = tf.reshape(stacked_outputs, [-1, n_windows, n_output])

Construir la optimización

learning_rate = 0.001  
 
loss = tf.reduce_sum(tf.square(outputs - y))    
optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate)         
training_op = optimizer.minimize(loss)                                          

Entrenar a la modelo

init = tf.global_variables_initializer() 
iteration = 1500 

with tf.Session() as sess:
    init.run()
    for iters in range(iteration):
        sess.run(training_op, feed_dict={X: X_batches, y: y_batches})
        if iters % 150 == 0:
            mse = loss.eval(feed_dict={X: X_batches, y: y_batches})
            print(iters, "\tMSE:", mse)
    
    y_pred = sess.run(outputs, feed_dict={X: X_test})