La entrada de la capa secuencial es incompatible con la capa: error de formas en LSTM
Soy nuevo en las redes neuronales y quiero usarlas para compararlas con otros métodos de aprendizaje automático. Tengo datos de series de tiempo multivariantes con un rango de aproximadamente dos años. Quiero predecir 'y' para los próximos días en función de las otras variables usando LSTM. El último día de mis datos es 2020-07-31.
df.tail()
y holidays day_of_month day_of_week month quarter
Date
2020-07-27 32500 0 27 0 7 3
2020-07-28 33280 0 28 1 7 3
2020-07-29 31110 0 29 2 7 3
2020-07-30 37720 0 30 3 7 3
2020-07-31 32240 0 31 4 7 3
Para entrenar el modelo LSTM, también divido los datos en datos de prueba y de tren.
from sklearn.model_selection import train_test_split
split_date = '2020-07-27' #to predict the next 4 days
df_train = df.loc[df.index <= split_date].copy()
df_test = df.loc[df.index > split_date].copy()
X1=df_train[['day_of_month','day_of_week','month','quarter','holidays']]
y1=df_train['y']
X2=df_test[['day_of_month','day_of_week','month','quarter','holidays']]
y2=df_test['y']
X_train, y_train =X1, y1
X_test, y_test = X2,y2
Como estoy trabajando con LSTM, se necesita algo de escala:
scaler = MinMaxScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)
Ahora, en la parte difícil: el modelo.
num_units=50
activation_function = 'sigmoid'
optimizer = 'adam'
loss_function = 'mean_squared_error'
batch_size = 10
num_epochs = 100
# Initialize the RNN
regressor = Sequential()
# Adding the input layer and the LSTM layer
regressor.add(LSTM(units = num_units, return_sequences=True ,activation = activation_function,
input_shape=(X_train.shape[1], 1)))
# Adding the output layer
regressor.add(Dense(units = 1))
# Compiling the RNN
regressor.compile(optimizer = optimizer, loss = loss_function)
# Using the training set to train the model
regressor.fit(X_train_scaled, y_train, batch_size = batch_size, epochs = num_epochs)
Sin embargo, recibo el siguiente error:
ValueError: Input 0 of layer sequential_11 is incompatible with the layer: expected ndim=3, found
ndim=2. Full shape received: [None, 5]
No entiendo cómo elegimos los parámetros o la forma de la entrada. He visto algunos videos y leído algunas páginas de Github y todos parecen ejecutar LSTM de una manera diferente, lo que hace que sea aún más difícil de implementar. El error anterior probablemente proviene de la forma, pero aparte de eso, ¿todo lo demás está bien? ¿Y cómo puedo arreglar esto para que funcione? Gracias
EDITAR: Esta pregunta similar no resuelve mi problema ... Probé la solución desde allí
x_train = X_train_scaled.reshape(-1, 1, 5)
x_test = X_test_scaled.reshape(-1, 1, 5)
(Mi X_test y y_test solo tienen una columna). Y la solución tampoco parece funcionar. Recibo este error ahora:
ValueError: Input 0 is incompatible with layer sequential_22: expected shape=
(None, None, 1), found shape=[None, 1, 5]
Respuestas
APORTE:
El problema es que el modelo espera una entrada de forma 3D, (batch, sequence, features)
pero en X_train
realidad es una porción de marco de datos, por lo que una matriz 2D:
X1=df_train[['day_of_month','day_of_week','month','quarter','holidays']]
X_train, y_train =X1, y1
Supongo que se supone que sus columnas son sus características, por lo que lo que normalmente haría es "apilar porciones" de su df para que se X_train
vea así:
Aquí hay un conjunto de datos ficticio 2D de forma (15,5)
:
data = np.zeros((15,5))
array([[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.]])
Puede remodelarlo para agregar una dimensión de lote, por ejemplo (15,1,5)
:
data = data[:,np.newaxis,:]
array([[[0., 0., 0., 0., 0.]],
[[0., 0., 0., 0., 0.]],
[[0., 0., 0., 0., 0.]],
[[0., 0., 0., 0., 0.]],
[[0., 0., 0., 0., 0.]],
[[0., 0., 0., 0., 0.]],
[[0., 0., 0., 0., 0.]],
[[0., 0., 0., 0., 0.]],
[[0., 0., 0., 0., 0.]],
[[0., 0., 0., 0., 0.]],
[[0., 0., 0., 0., 0.]],
[[0., 0., 0., 0., 0.]],
[[0., 0., 0., 0., 0.]],
[[0., 0., 0., 0., 0.]],
[[0., 0., 0., 0., 0.]]])
Mismos datos, pero presentados de forma diferente. Ahora, en este ejemplo, batch = 15
y sequence = 1
no sé cuál es la longitud de la secuencia en su caso, pero puede ser cualquier cosa.
MODELO:
Ahora en su modelo, keras
input_shape
espere (batch, sequence, features)
, cuando pase esto:
input_shape=(X_train.shape[1], 1)
Esto es lo que ve su modelo: (None, Sequence = X_train.shape[1] , num_features = 1)
None
es para la dimensión de lote. No creo que eso sea lo que está tratando de hacer, así que una vez que haya remodelado, también debe corregir input_shape
para que coincida con la nueva matriz.
Es un problema de regresión multivariante que está resolviendo usando LSTM. Antes de saltar al código, veamos realmente lo que significa
Planteamiento del problema:
- Tienes
5
funciónholidays, day_of_month, day_of_week,month,quarter
por día durantek
días - Para cualquier día n, dadas las características de la voz últimos días 'm' que desea predecir el
y
deln
cuarto día
Creando dataset de ventana:
- Primero tenemos que decidir la cantidad de días que queremos alimentar a nuestro modelo. Esto se llama longitud de secuencia (fijémoslo en 3 para este ejemplo).
- Tenemos que dividir los días de duración de la secuencia para crear el tren y el conjunto de datos de prueba. Esto se hace usando una ventana deslizante donde el tamaño de la ventana es la longitud de la secuencia.
- Como puede ver, no hay predicciones disponibles por los últimos
p
registros dondep
está la longitud de la secuencia. - Haremos las creaciones del dataset de la ventana usando el
timeseries_dataset_from_array
método. - Para obtener más información avanzada, siga los documentos oficiales de tf .
Modelo LSTM
Así que pictóricamente lo que queremos lograr se muestra a continuación:

Para cada desenrollado de celda LSTM, pasamos las 5 características del día y lo desenrollamos en el m
tiempo donde m
está la longitud de la secuencia. Estamos prediciendo el y
del último día.
Código:
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers, models
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
# Model
regressor = models.Sequential()
regressor.add(layers.LSTM(5, return_sequences=True))
regressor.add(layers.Dense(1))
regressor.compile(optimizer='sgd', loss='mse')
# Dummy data
n = 10000
df = pd.DataFrame(
{
'y': np.arange(n),
'holidays': np.random.randn(n),
'day_of_month': np.random.randn(n),
'day_of_week': np.random.randn(n),
'month': np.random.randn(n),
'quarter': np.random.randn(n),
}
)
# Train test split
train_df, test_df = train_test_split(df)
print (train_df.shape, test_df.shape)\
# Create y to be predicted
# given last n days predict todays y
# train data
sequence_length = 3
y_pred = train_df['y'][sequence_length-1:].values
train_df = train_df[:-2]
train_df['y_pred'] = y_pred
# Validataion data
y_pred = test_df['y'][sequence_length-1:].values
test_df = test_df[:-2]
test_df['y_pred'] = y_pred
# Create window datagenerators
# Train data generator
train_X = train_df[['holidays','day_of_month','day_of_week','month','month']]
train_y = train_df['y_pred']
train_dataset = tf.keras.preprocessing.timeseries_dataset_from_array(
train_X, train_y, sequence_length=sequence_length, shuffle=True, batch_size=4)
# Validation data generator
test_X = test_df[['holidays','day_of_month','day_of_week','month','month']]
test_y = test_df['y_pred']
test_dataset = tf.keras.preprocessing.timeseries_dataset_from_array(
test_X, test_y, sequence_length=sequence_length, shuffle=True, batch_size=4)
# Finally fit the model
regressor.fit(train_dataset, validation_data=test_dataset, epochs=3)
Producción:
(7500, 6) (2500, 6)
Epoch 1/3
1874/1874 [==============================] - 8s 3ms/step - loss: 9974697.3664 - val_loss: 8242597.5000
Epoch 2/3
1874/1874 [==============================] - 6s 3ms/step - loss: 8367530.7117 - val_loss: 8256667.0000
Epoch 3/3
1874/1874 [==============================] - 6s 3ms/step - loss: 8379048.3237 - val_loss: 8233981.5000
<tensorflow.python.keras.callbacks.History at 0x7f3e94bdd198>