尝试从 Keras 运行顺序模型时出现 ValueError

Posted

技术标签:

【中文标题】尝试从 Keras 运行顺序模型时出现 ValueError【英文标题】:ValueError while trying to run the Sequential Model from Keras 【发布时间】:2020-11-30 09:22:16 【问题描述】:

我正在尝试使用 Keras 构建一个 NARX NN。我仍然不能 100% 确定在 LSTM 神经元中使用参数 return_sequence=True 但是,在我可以检查之前,我需要让代码工作。当我尝试运行它时,我收到以下消息:

ValueError: Error when checking input: expected lstm_84_input to have 3 dimensions, but got array with shape (6686, 3)

请参阅下面的代码。运行 model.fit 命令时出现错误。我的数据数据的形状为 40101 个时间步长 x 6 个特征(3 个外生输入,3 个系统响应)。

import numpy as np
import pandas as pd
from sklearn.model_selection import TimeSeriesSplit
import tensorflow as tf
from tensorflow.keras import initializers

# --- main
data = pd.read_excel('example.xlsx',usecols=['wave','wind','current','X','Y','RZ'])
data.plot(subplots=True, figsize=[15,10])

x_data = np.array(data.loc[:,['wave','wind','current']])
y_data = np.array(data.loc[:,['X','Y','RZ']])

timeSeriesCrossValidation = TimeSeriesSplit(n_splits=5)
for train, validation in timeSeriesCrossValidation.split(x_data, y_data):  

    # create model
    model = tf.keras.models.Sequential()
    
    # input layer
    model.add(tf.keras.layers.LSTM(units=50,
                                   input_shape=(40101,3),
                                   dropout=0.01,
                                   recurrent_dropout=0.2,
                                   kernel_initializer=initializers.RandomNormal(mean=0,stddev=.5),
                                   bias_initializer=initializers.Zeros(),
                                   return_sequences = True))
    
    # 1st hidden layer
    model.add(tf.keras.layers.LSTM(units=50,
                                   dropout=0.01,
                                   recurrent_dropout=0.2,
                                   kernel_initializer=initializers.RandomNormal(mean=0,stddev=.5),
                                   bias_initializer=initializers.Zeros(),
                                   return_sequences = True))
    
    # 2nd hidder layer
    model.add(tf.keras.layers.LSTM(units=50,
                                   dropout=0.01,
                                   recurrent_dropout=0.2,
                                   kernel_initializer=initializers.RandomNormal(mean=0,stddev=.5),
                                   bias_initializer=initializers.Zeros(),
                                   return_sequences = False))
    
    # output layer
    model.add(tf.keras.layers.Dense(3))
    
    model.compile(loss='mse',optimizer='nadam',metrics=['accuracy'])

    model.fit(x_data[train], y_data[train],
              verbose=2,
              batch_size=None,
              epochs=10,
              validation_data=(x_data[validation], y_data[validation])
              #callbacks=early_stop
              )
    
    prediction = model.predict(x_data[validation])
    y_validation = y_data[validation]

【问题讨论】:

【参考方案1】:

LSTM 层需要 3 个维度的输入:

(n_samples, time_steps, features)

您使用这种格式传递数据:

(n_samples, features)

由于您没有创建时间步长的功能,最简单的解决方案是将输入更改为形状:

(40101, 1, 3)

虚假数据:

x_data = np.random.rand(40101, 1, 3)
y_data = np.random.rand(40101, 3)

此外,您不应在 Keras 层的 input_shape 参数中传递样本数。就用这个吧:

input_shape=(1, 3)

所以这里是更正的代码(带有虚假数据):

import numpy as np
from sklearn.model_selection import TimeSeriesSplit
import tensorflow as tf
from tensorflow.keras import initializers
from tensorflow.keras.layers import *

x_data = np.random.rand(40101, 1, 3)
y_data = np.random.rand(40101, 3)

timeSeriesCrossValidation = TimeSeriesSplit(n_splits=5)
for train, validation in timeSeriesCrossValidation.split(x_data, y_data):
    # create model
    model = tf.keras.models.Sequential()

    # input layer
    model.add(LSTM(units=5,
                   input_shape=(1, 3),
                   dropout=0.01,
                   recurrent_dropout=0.2,
                   kernel_initializer=initializers.RandomNormal(mean=0, stddev=.5),
                   bias_initializer=initializers.Zeros(),
                   return_sequences=True))

    # 1st hidden layer
    model.add(LSTM(units=5,
                   dropout=0.01,
                   recurrent_dropout=0.2,
                   kernel_initializer=initializers.RandomNormal(mean=0, stddev=.5),
                   bias_initializer=initializers.Zeros(),
                   return_sequences=True))

    # 2nd hidder layer
    model.add(LSTM(units=50,
                   dropout=0.01,
                   recurrent_dropout=0.2,
                   kernel_initializer=initializers.RandomNormal(mean=0, stddev=.5),
                   bias_initializer=initializers.Zeros(),
                   return_sequences=False))

    # output layer
    model.add(tf.keras.layers.Dense(3))

    model.compile(loss='mse', optimizer='nadam', metrics=['accuracy'])

    model.fit(x_data[train], y_data[train],
              verbose=2,
              batch_size=None,
              epochs=1,
              validation_data=(x_data[validation], y_data[validation])
              # callbacks=early_stop
              )

    prediction = model.predict(x_data[validation])
    y_validation = y_data[validation]

如果你想要一个函数来创建时间步,使用这个:

def multivariate_data(dataset, target, start_index, end_index, history_size,
                      target_size, step, single_step=False):
  data = []
  labels = []

  start_index = start_index + history_size
  if end_index is None:
    end_index = len(dataset) - target_size

  for i in range(start_index, end_index):
    indices = range(i-history_size, i, step)
    data.append(dataset[indices])

    if single_step:
      labels.append(target[i+target_size])
    else:
      labels.append(target[i:i+target_size])

  return np.array(data), np.array(labels)

它会给你正确的形状,例如:

multivariate_data(dataset=np.random.rand(40101, 3), 
                  target=np.random.rand(40101, 3), 
                  0, len(x_data), 5, 0, 1, True)[0].shape
(40096, 5, 3)

您丢失了 5 个数据点,因为一开始您无法回顾过去 5 步。

【讨论】:

Nicolas Gervais,非常感谢您的反馈。它已经在运行,尽管我仍然不能 100% 确定这是 NARX NN 的正确实现。还有一件事我想问:你说 LSTM 层需要 3 维输入,它对 Dense 层也有效吗? Nicolas Gervais,您能否确认您回复中的最后一段代码?您使用 x_data 两次作为 multivariate_data 函数的输入。那正确吗?我问是因为在函数的定义中,您将第一个输入标识为“数据集”,第二个输入标识为“目标”。 密集层可以采用 2D 输入。你对datasettarget 是对的,尽管这并不重要,因为它是随机数据。我改了。

以上是关于尝试从 Keras 运行顺序模型时出现 ValueError的主要内容,如果未能解决你的问题,请参考以下文章

在 Python 中运行 keras 模型时出现 ValueError

在 Keras 中拟合模型时出现维度错误

Keras ConvLSTM2D:保存模型时出现ValueError

使用自定义损失函数编译 Keras 模型时出现 TypeError

在 Keras 中训练对象检测模型时出现不兼容张量形状的问题

尝试在 Keras 中创建 BLSTM 网络时出现 TypeError