【问题标题】:Keras: Wrong Input Shape in LSTM Neural NetworkKeras:LSTM 神经网络中的错误输入形状
【发布时间】:2018-03-21 16:09:23
【问题描述】:

我正在尝试训练一个 LSTM 循环神经网络,用于序列分类。

我的数据格式如下:

Input: [1,5,2,3,6,2, ...] -> Output: 1
Input: [2,10,4,6,12,4, ...] -> Output: 1
Input: [4,1,7,1,9,2, ...] -> Output: 2
Input: [1,3,5,9,10,20, ...] -> Output: 3
.
.
.

所以基本上我想提供一个序列作为输入并获得一个整数作为输出。

每个输入序列的长度 = 2000 个浮点数,我有大约 1485 个样本用于训练

输出只是一个从 1 到 10 的整数

这是我尝试做的:

# Get the training numpy 2D array for the input (1485X 2000). 
# Each element is an input sequence of length 2000
# eg: [ [1,2,3...], [4,5,6...], ... ]
x_train = get_training_x() 

# Get the training numpy 2D array for the outputs (1485 X 1). 
# Each element is an integer output for the corresponding input from x_train
# eg: [ 1, 2, 3, ...]
y_train = get_training_y()

# Create the model
model = Sequential()
model.add(LSTM(100, input_shape=(x_train.shape)))
model.add(Dense(1, activation='sigmoid'))
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
print(model.summary())
model.fit(x_train, y_train, nb_epoch=3, batch_size=64)

我收到以下错误:

Error when checking input: expected lstm_1_input to have 3 dimensions, but got array with shape (1485, 2000)

我尝试改用这个:

model.add(LSTM(100, input_shape=(1485, 1, 2000)))

但这次又报错了:

ValueError: Input 0 is incompatible with layer lstm_1: expected ndim=3, found ndim=4

谁能解释我的输入形状是什么?我做错了什么?

谢谢

【问题讨论】:

    标签: python neural-network keras lstm rnn


    【解决方案1】:

    尝试将您的训练数据重塑为:

    x_train=x_train.reshape(x_train.shape[0], 1, x_train.shape[1])
    

    【讨论】:

    • 我得到了我后来得到的同样的错误:ValueError: Input 0 is incompatible with layer lstm_1: expected ndim=3, found ndim=4。这个还在用model.add(LSTM(100, input_shape=x_train.shape))谢谢
    • 也改变你的 input_shape
    【解决方案2】:

    input_shape=(None, x_train.shape[1], 1),其中None 是批量大小,x_train.shape[1] 是每个特征序列的长度,1 是每个特征长度。 (不确定Sequential 模型是否需要批量大小)。

    然后将您的数据重塑为x_train = x_train.reshape(-1, x_train.shape[1], 1)

    【讨论】:

    • 您好,我现在收到此错误:ValueError: Input 0 is incompatible with layer lstm_1: expected ndim=3, found ndim=4 谢谢
    • 我完全按照你的描述做了:input_shape = (None, x_train.shape[1], 1)x_train = x_train.reshape(-1, x_train.shape[1], 1) 然后更改 LSTM 层以采用该输入形状 model.add(LSTM(100, input_shape=input_shape))
    • @Youssef 尝试从 input_shape 中删除 None
    【解决方案3】:

    鉴于您输入和输出的格式,您可以使用官方Keras examples 之一所采用的部分方法。更具体地说,由于您不是创建二进制分类器,而是预测一个整数,因此您可以使用 one-hot 编码使用 to_categorical()y_train 进行编码。

    # Number of elements in each sample
    num_vals = x_train.shape[1]
    
    # Convert all samples in y_train to one-hot encoding
    y_train = to_categorical(y_train)
    
    # Get number of possible values for model inputs and outputs
    num_x_tokens = np.amax(x_train) + 1
    num_y_tokens = y_train.shape[1]
    
    model = Sequential()
    model.add(Embedding(num_x_tokens, 100))
    model.add(LSTM(100))
    model.add(Dense(num_y_tokens, activation='sigmoid'))
    
    model.compile(loss='binary_crossentropy',
                  optimizer='adam',
                  metrics=['accuracy'])
    
    model.fit(x_train, y_train,
                  batch_size=64,
                  epochs=3)
    

    上面代码中的num_x_tokens 将是您的一个输入样本中元素的最大大小(例如,如果您有两个样本[1, 7, 2][3, 5, 4],则num_x_tokens7)。如果您使用numpy,您可以使用np.amax(x_train) 找到它。同样,num_y_tokens 是您在y_train 中拥有的类别数。

    训练后,您可以使用以下代码运行预测。在此配置中使用 np.argmax 可以有效地反转 to_categorical

    model_out = model.predict(x_test)
    model_out = np.argmax(model_out, axis=1)
    

    您可以使用from keras.utils import to_categorical 导入to_categorical,使用from keras.layers import Embedding 导入Embedding,使用import numpy as np 导入numpy。

    另外,您不必执行print(model.summary())model.summary() 足以打印出摘要。

    编辑

    如果输入的格式为[[0.12, 0.31, ...], [0.22, 0.95, ...], ...](例如,使用x_train = np.random.rand(num_samples, num_vals) 生成),那么您可以使用x_train = np.reshape(x_train, (num_samples, num_vals, 1)) 更改数组的形状以将其输入到LSTM 层。在这种情况下训练模型的代码是:

    num_samples = x_train.shape[0]
    num_vals    = x_train.shape[1] # Number of elements in each sample
    
    # Reshape for what LSTM expects
    x_train = np.reshape(x_train, (num_samples, num_vals, 1))
    y_train = to_categorical(y_train)
    
    # Get number of possible values for model outputs
    num_y_tokens = y_train.shape[1]
    
    model = Sequential()
    model.add(LSTM(100, input_shape=(num_vals, 1)))
    model.add(Dense(num_y_tokens, activation='sigmoid'))
    
    model.compile(loss='binary_crossentropy',
                  optimizer='adam',
                  metrics=['accuracy'])
    
    model.fit(x_train, y_train,
                  batch_size=64,
                  epochs=3)
    

    num_valsx_train 中每个样本数组的长度。 np.reshape(x_train, (num_samples, num_vals, 1)) 将每个样本从 [0.12, 0.31, ...] 形式更改为 [[0.12], [0.31], ...] 形式,这是 LSTM 然后采用的形状 (input_shape=(num_vals, 1))。在这种情况下,额外的1 似乎很奇怪,但有必要为 LSTM 的输入添加一个额外的维度,因为它希望每个样本至少有两个维度,通常称为(timesteps, data_dim),或者在这种情况下称为@987654358 @。

    要了解如何在 Keras 中使用 LSTM,您可以参考:

    Keras Sequential model guide(有几个 LSTM 示例)

    Keras examples(查找名称中带有lstm*.py 文件)

    【讨论】:

    • 添加嵌入层解决了我输入形状的问题,但是我还有另一个问题。我不知道 num_x_tokens。我不能取最大值,因为那里的值都是浮点数和 0 到 1 之间的值(问题中的示例可能具有误导性,对此感到抱歉)。而且我不知道输入令牌的数量。知道如何在不知道令牌编号的情况下使用嵌入层吗? (我认为可能有数百万个不同的输入,考虑到它是 0 到 1 之间的随机浮点数)。谢谢
    • 在这种情况下,假设您定义了x_train = np.random.rand(num_samples, num_vals)。这将采用[[0.12, 0.31, ...], [0.22, 0.95, ...], ...] 的形式。您可以使用x_train = np.reshape(x_train, (num_samples, num_vals, 1)) 来改变数组的形状,然后用model.add(LSTM(100, input_shape=(num_vals, 1))) 将其输入到LSTM 层(也可以删除Embedding 层)。 @Youssef 我是否正确解释了您的输入格式?
    • 太棒了!效果很好。您介意将您的评论添加到您的答案中吗,我会接受。如果您能解释“1”在“reshape”和“input_shape”中代表什么,那就太好了。这是输入的维度吗? [num_vals x 1]?
    猜你喜欢
    • 1970-01-01
    • 2017-12-05
    • 2020-03-16
    • 2020-12-28
    • 1970-01-01
    • 2017-07-30
    • 2017-08-31
    • 2020-05-26
    • 2019-09-09
    相关资源
    最近更新 更多