Ввод последовательности слоев несовместим с ошибкой слоя: формы в LSTM
Я новичок в нейронных сетях и хочу использовать их для сравнения с другими методами машинного обучения. У меня есть данные многомерного временного ряда с диапазоном примерно двух лет. Я хочу предсказать «y» на следующие несколько дней на основе других переменных, используя LSTM. Последний день моих данных - 31.07.2020.
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
Чтобы обучить модель LSTM, я также разделил данные на обучающие и тестовые данные.
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
Поскольку я работаю с LSTM, необходимо некоторое масштабирование:
scaler = MinMaxScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)
Теперь о сложной части: модели.
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)
Однако я получаю следующую ошибку:
ValueError: Input 0 of layer sequential_11 is incompatible with the layer: expected ndim=3, found
ndim=2. Full shape received: [None, 5]
Я не понимаю, как мы выбираем параметры или форму ввода. Я видел несколько видеороликов и читал некоторые страницы Github, и, похоже, каждый запускает LSTM по-своему, что еще больше затрудняет его реализацию. Предыдущая ошибка, вероятно, связана с формой, но все остальное правильно? И как это исправить, чтобы работало? Спасибо
РЕДАКТИРОВАТЬ: этот аналогичный вопрос не решает мою проблему .. Я пробовал решение оттуда
x_train = X_train_scaled.reshape(-1, 1, 5)
x_test = X_test_scaled.reshape(-1, 1, 5)
(Мои X_test и y_test имеют только один столбец). И решение тоже, похоже, не работает. Теперь я получаю эту ошибку:
ValueError: Input 0 is incompatible with layer sequential_22: expected shape=
(None, None, 1), found shape=[None, 1, 5]
Ответы
ВХОД:
Проблема в том, что вы ожидаете 3D-ввод формы, (batch, sequence, features)
но на X_train
самом деле это часть фрейма данных, поэтому 2D-массив:
X1=df_train[['day_of_month','day_of_week','month','quarter','holidays']]
X_train, y_train =X1, y1
Я предполагаю, что ваши столбцы должны быть вашими функциями, поэтому вы обычно будете «складывать фрагменты» вашего df, чтобы вы X_train
выглядели примерно так:
Вот фиктивный набор 2D-данных формы (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.]])
Вы можете изменить его форму, чтобы добавить размер партии, например (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.]]])
Те же данные, но представлены в другом виде. Теперь в этом примере, batch = 15
и sequence = 1
я не знаю, какова длина последовательности в вашем случае, но это может быть что угодно.
МОДЕЛЬ:
Теперь в вашей модели keras
input_shape
ожидайте (batch, sequence, features)
, когда вы передадите это:
input_shape=(X_train.shape[1], 1)
Это то, что вы видите в модели: (None, Sequence = X_train.shape[1] , num_features = 1)
None
размер партии. Я не думаю, что это то, что вы пытаетесь сделать, поэтому после того, как вы изменили форму, вам также следует исправить, input_shape
чтобы он соответствовал новому массиву.
Это задача многомерной регрессии, которую вы решаете с помощью LSTM. Прежде чем переходить к коду, давайте посмотрим, что это значит
Постановка задачи:
- У вас есть
5
функцияholidays, day_of_month, day_of_week,month,quarter
в день в течениеk
нескольких дней - В любой день п, учитывая особенность говорят последние «м» дней вы хотите , чтобы предсказать
y
вn
й день
Создание набора данных окна:
- Сначала нам нужно решить, сколько дней мы хотим скормить нашей модели. Это называется длиной последовательности (в этом примере зафиксируем ее равной 3).
- Мы должны разделить дни длины последовательности, чтобы создать набор данных для поезда и тестирования. Это делается с помощью скользящего окна, где размер окна - это длина последовательности.
- Как видите, нет доступных прогнозов по последним
p
записям, гдеp
- длина последовательности. - Мы будем создавать оконные наборы данных, используя
timeseries_dataset_from_array
метод. - Для получения дополнительных сведений следуйте официальным документам tf .
Модель LSTM
Итак, наглядное изображение того, чего мы хотим достичь, показано ниже:

Для каждого развертывания ячейки LSTM мы передаем 5 функций дня и развертываем во m
времени, где m
- длина последовательности. Мы предсказываем y
последний день.
Код:
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)
Выход:
(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>