A entrada da camada sequencial é incompatível com a camada: erro de formas em LSTM
Eu sou novo em redes neurais e quero usá-las para comparar com outros métodos de aprendizado de máquina. Tenho dados de série temporal multivariada com um intervalo de aproximadamente dois anos. Eu quero prever 'y' para os próximos dias com base nas outras variáveis usando LSTM. O último dia de meus dados é 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 treinar o modelo LSTM, também divido os dados em dados de treinamento e teste.
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 estou trabalhando com LSTM, é necessário algum dimensionamento:
scaler = MinMaxScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)
Agora, na parte difícil: o 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)
No entanto, recebo o seguinte erro:
ValueError: Input 0 of layer sequential_11 is incompatible with the layer: expected ndim=3, found
ndim=2. Full shape received: [None, 5]
Não entendo como escolhemos os parâmetros ou a forma da entrada. Eu vi alguns vídeos e li algumas páginas do Github e todo mundo parece rodar LSTM de uma maneira diferente, o que torna ainda mais difícil de implementar. O erro anterior provavelmente está vindo da forma, mas fora isso, está tudo certo? E como posso consertar isso para funcionar? Obrigado
EDIT: Esta questão semelhante não resolve o meu problema .. Tentei a solução a partir daí
x_train = X_train_scaled.reshape(-1, 1, 5)
x_test = X_test_scaled.reshape(-1, 1, 5)
(Meu X_test e y_test têm apenas uma coluna). E a solução também parece não funcionar. Eu recebo este erro agora:
ValueError: Input 0 is incompatible with layer sequential_22: expected shape=
(None, None, 1), found shape=[None, 1, 5]
Respostas
ENTRADA:
O problema é que você modela espera uma entrada 3D de forma, (batch, sequence, features)
mas X_train
na verdade você é uma fatia do quadro de dados, então uma matriz 2D:
X1=df_train[['day_of_month','day_of_week','month','quarter','holidays']]
X_train, y_train =X1, y1
Suponho que suas colunas sejam seus recursos, então o que você normalmente faria é "empilhar fatias" de seu df para que você se X_train
pareça com isso:
Aqui está um conjunto de dados 2D fictício 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.]])
Você pode remodelá-lo para adicionar uma dimensão de lote, por exemplo (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.]]])
Mesmos dados, mas apresentados de forma diferente. Agora, neste exemplo, batch = 15
e sequence = 1
, não sei qual é o comprimento da sequência no seu caso, mas pode ser qualquer coisa.
MODELO :
Agora em seu modelo, keras
input_shape
espere (batch, sequence, features)
, quando você passar isso:
input_shape=(X_train.shape[1], 1)
Isso é o que seu modelo vê: (None, Sequence = X_train.shape[1] , num_features = 1)
None
é para a dimensão do lote. Não acho que é isso que você está tentando fazer, então, depois de remodelar, você também deve corrigir input_shape
para corresponder à nova matriz.
É um problema de regressão multivariada que você está resolvendo usando LSTM. Antes de entrar no código, vamos realmente ver o que isso significa
Declaração do problema:
- Você tem
5
recursoholidays, day_of_month, day_of_week,month,quarter
por dia pork
dias - Para qualquer dia n, dadas as características de, digamos, últimos 'm' dias, você deseja prever o
y
don
dia
Criando conjunto de dados da janela:
- Nós primeiro precisamos decidir o número de dias que queremos alimentar para nosso modelo. Isso é chamado de comprimento de sequência (vamos fixá-lo em 3 para este exemplo).
- Temos que dividir os dias de duração da sequência para criar o trem e o conjunto de dados de teste. Isso é feito usando uma janela deslizante onde o tamanho da janela é o comprimento da sequência.
- Como você pode ver, não há previsões disponíveis pelos últimos
p
registros ondep
é o comprimento da sequência. - Faremos as criações do dataset da janela usando o
timeseries_dataset_from_array
método. - Para informações mais avançadas, siga os documentos oficiais do tf .
Modelo LSTM
Portanto, o que queremos alcançar é mostrado abaixo:

Para cada desdobramento de célula LSTM, passamos as 5 características do dia e desdobramos no m
tempo, onde m
é o comprimento da sequência. Estamos prevendo o fim y
do último dia.
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)
Resultado:
(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>