Red de keras produciendo predicciones inversas.

Tengo un conjunto de datos de series temporales y estoy tratando de entrenar una red para que se adapte (obviamente, ese es solo el primer paso, luego lucharé contra el sobreajuste).

La red tiene dos capas: LSTM (32 neuronas) y Densa (1 neurona, sin activación)

Entrenamiento / modelo tiene estos parámetros: epochs: 20 , steps_per_epoch: 100 , loss: "mse" , optimizer: "rmsprop" .

TimeseriesGenerator produce la serie de entrada con: length: 1 sampling_rate: 1 , batch_size: 1 , batch_size: 1 .

Yo esperaría que la red simplemente memorizara un conjunto de datos tan pequeño (he intentado una red mucho más complicada en vano) y la pérdida en el conjunto de datos de entrenamiento sería prácticamente nula. No lo es y cuando visualizo los resultados en el conjunto de entrenamiento de esta manera:

 y_pred = model.predict_generator(gen) plot_points = 40 epochs = range(1, plot_points + 1) pred_points = numpy.resize(y_pred[:plot_points], (plot_points,)) target_points = gen.targets[:plot_points] plt.plot(epochs, pred_points, 'b', label='Predictions') plt.plot(epochs, target_points, 'r', label='Targets') plt.legend() plt.show() 

Yo obtengo:

tabla de predicciones y objetivos

Las predicciones tienen una amplitud algo menor, pero son precisamente inversas a los objectives. Por cierto esto no está memorizado, se invierten incluso para el conjunto de datos de prueba en el que el algoritmo no ha entrenado en absoluto. Parece que en lugar de memorizar el conjunto de datos, mi red acaba de aprender a negar el valor de entrada y reducirlo ligeramente. ¿Alguna idea de por qué esto está pasando? No parece ser la solución a la que debería haber convergido el optimizador (la pérdida es bastante grande).

EDITAR (algunas partes relevantes de mi código):

 train_gen = keras.preprocessing.sequence.TimeseriesGenerator( x, y, length=1, sampling_rate=1, batch_size=1, shuffle=False ) model = Sequential() model.add(LSTM(32, input_shape=(1, 1), return_sequences=False)) model.add(Dense(1, input_shape=(1, 1))) model.compile( loss="mse", optimizer="rmsprop", metrics=[keras.metrics.mean_squared_error] ) history = model.fit_generator( train_gen, epochs=20, steps_per_epoch=100 ) 

EDITAR (conjunto de datos diferente, generados aleatoriamente):

introduzca la descripción de la imagen aquí

Tuve que boost el número de neuronas LSTM a 256, con la configuración anterior (32 neuronas), la línea azul era bastante plana. Sin embargo, con el aumento surge el mismo patrón: predicciones inversas con una amplitud algo menor .

EDITAR (objectives cambiados por +1):

introduzca la descripción de la imagen aquí

Cambiar los objectives en uno en comparación con las predicciones no produce un ajuste mucho mejor. Observe las partes resaltadas donde la gráfica no solo se alterna, es más evidente allí.

EDITAR (aumento de la longitud a 2 … TimeseriesGenerator(length=2, ...) ):

introduzca la descripción de la imagen aquí

Con length=2 las predicciones dejan de rastrear los objectives tan de cerca, pero el patrón general de inversión sigue en pie.

Usted dice que su red “acaba de aprender a negar el valor de entrada y reducirlo ligeramente”. No lo creo. Es muy probable que todo lo que está viendo sea que la red tenga un rendimiento deficiente y solo esté prediciendo el valor anterior (pero a escala como usted dice). Este problema es algo que he visto una y otra vez. Aquí hay otro ejemplo , y otro , de este problema. Además, recuerde que es muy fácil engañarse cambiando los datos en uno. Es muy probable que simplemente esté cambiando la mala predicción en el tiempo y obteniendo una superposición.

EDITAR: Después de los comentarios del autor, no creo que esta sea la respuesta correcta, pero la mantendré publicada para la posteridad.

¡Gran pregunta y la respuesta se debe a cómo funciona Time_generator! Aparentemente, en lugar de agarrar los pares x, y con el mismo índice (por ejemplo, la entrada x[0] para dar salida al objective y[0] ) toma el objective con el desplazamiento 1 (por lo tanto, x[0] a y[1] ).

Por lo tanto, al trazar y con el desplazamiento 1 se producirá el ajuste deseado.

Código para simular:

 import keras import matplotlib.pyplot as plt x=np.random.uniform(0,10,size=41).reshape(-1,1) x[::2]*=-1 y=x[1:] x=x[:-1] train_gen = keras.preprocessing.sequence.TimeseriesGenerator( x, y, length=1, sampling_rate=1, batch_size=1, shuffle=False ) model = keras.models.Sequential() model.add(keras.layers.LSTM(100, input_shape=(1, 1), return_sequences=False)) model.add(keras.layers.Dense(1)) model.compile( loss="mse", optimizer="rmsprop", metrics=[keras.metrics.mean_squared_error] ) model.optimizer.lr/=.1 history = model.fit_generator( train_gen, epochs=20, steps_per_epoch=100 ) 

Trazar correctamente:

 y_pred = model.predict_generator(train_gen) plot_points = 39 epochs = range(1, plot_points + 1) pred_points = np.resize(y_pred[:plot_points], (plot_points,)) target_points = train_gen.targets[1:plot_points+1] #NOTICE DIFFERENT INDEXING HERE plt.plot(epochs, pred_points, 'b', label='Predictions') plt.plot(epochs, target_points, 'r', label='Targets') plt.legend() plt.show() 

Salida, observe cómo el ajuste ya no está invertido y en su mayoría es muy preciso:

Con el desplazamiento adecuado en <code/> target_points “> </p>
<p>  Así es como se ve cuando el desplazamiento es incorrecto: </p>
<p> <img src=