【问题标题】:How to train a LSTM model with different N-dimensions labels?如何训练具有不同 N 维标签的 LSTM 模型?
【发布时间】:2017-08-24 04:05:37
【问题描述】:

我正在使用 keras(带有 TensorFlow 后端的 2.0.6 版)来构建一个简单的神经网络:

model = Sequential()
model.add(LSTM(32, return_sequences=True, input_shape=(100, 5)))
model.add(LSTM(32, return_sequences=True)) 
model.add(TimeDistributed(Dense(5)))
model.add(Activation('softmax'))
model.compile(loss='categorical_crossentropy',
              optimizer='rmsprop',
              metrics=['accuracy'])

这只是对我的测试,我正在使用以下虚拟数据“训练”模型。

x_train = np.array([
    [[0,0,0,0,1], [0,0,0,1,0], [0,0,1,0,0]],
    [[1,0,0,0,0], [0,1,0,0,0], [0,0,1,0,0]],
    [[0,1,0,0,0], [0,0,1,0,0], [0,0,0,1,0]],
    [[0,0,1,0,0], [1,0,0,0,0], [1,0,0,0,0]],
    [[0,0,0,1,0], [0,0,0,0,1], [0,1,0,0,0]],
    [[0,0,0,0,1], [0,0,0,0,1], [0,0,0,0,1]]
])

y_train = np.array([
    [[0,0,0,0,1], [0,0,0,1,0], [0,0,1,0,0]],
    [[1,0,0,0,0], [0,1,0,0,0], [0,0,1,0,0]],
    [[0,1,0,0,0], [0,0,1,0,0], [0,0,0,1,0]],
    [[1,0,0,0,0], [1,0,0,0,0], [1,0,0,0,0]],
    [[1,0,0,0,0], [0,0,0,0,1], [0,1,0,0,0]],
    [[1,0,0,0,0], [0,0,0,0,1], [0,0,0,0,1]]
])

然后我做:

model.fit(x_train, y_train, batch_size=2, epochs=50, shuffle=False)

print(model.predict(x_train))

结果是:

[[[ 0.11855114  0.13603994  0.21069065  0.28492314  0.24979511]
  [ 0.03013871  0.04114409  0.16499813  0.41659597  0.34712321]
  [ 0.00194826  0.00351031  0.06993906  0.52274817  0.40185428]]

 [[ 0.17915446  0.19629011  0.21316603  0.22450975  0.18687972]
  [ 0.17935558  0.1994358   0.22070852  0.2309722   0.16952793]
  [ 0.18571526  0.20774922  0.22724937  0.23079531  0.14849086]]

 [[ 0.11163659  0.13263632  0.20109797  0.28029731  0.27433187]
  [ 0.02216373  0.03424517  0.13683401  0.38068131  0.42607573]
  [ 0.00105937  0.0023865   0.0521594   0.43946937  0.50492537]]

 [[ 0.13276921  0.15531689  0.21852671  0.25823513  0.23515201]
  [ 0.05750636  0.08210614  0.22636817  0.3303588   0.30366054]
  [ 0.01128351  0.02332032  0.210263    0.3951444   0.35998878]]

 [[ 0.15303896  0.18197381  0.21823004  0.23647803  0.21027911]
  [ 0.10842207  0.15755147  0.23791778  0.26479205  0.23131666]
  [ 0.06472684  0.12843341  0.26680911  0.28923658  0.25079405]]

 [[ 0.19560908  0.20663913  0.21954383  0.21920268  0.15900527]
  [ 0.22829761  0.22907974  0.22933882  0.20822221  0.10506159]
  [ 0.27179539  0.25587022  0.22594844  0.18308094  0.063305  ]]]

好的,它有效,但这只是一个测试,我真的不关心准确性等。我想了解如何处理不同大小的输出。

例如:传递一个序列(numpy.array),如:

[[0,0,0,0,1], [0,0,0,1,0], [0,0,1,0,0]]

我想得到 4 维输出作为预测:

[[..first..], [..second..], [..third..], [..four..]]

这可能吗?大小可能会有所不同,我会使用具有不同 N 维度的不同标签来训练模型。

谢谢

【问题讨论】:

  • 你真的想要四维输出还是你的意思是具有四个时间步长的三维输出?
  • 此外,您应该提供可运行的代码。上面的代码会失败,因为你的 input_shape(100, 5)x_train 中的每个样本都有(3, 5) 的形状。
  • 我错了...我的意思是四个时间步长!
  • 好的,你是说单个y_train 可以有可变数量的时间步?
  • 完全是@NicoleWhite

标签: python tensorflow keras


【解决方案1】:

此答案适用于非可变尺寸,但对于可变尺寸,Giuseppe 的答案中的 padding 想法似乎是可行的方法,也许在 Keras 文档中提出的 "Masking" 的帮助下。 p>


Keras 中的输出形状完全取决于您放入最后一层的“单元/神经元/细胞”的数量,当然也取决于层的类型。

我可以看到您的数据与您的问题中的代码不匹配,这是不可能的,但是,假设您的代码是正确的并且暂时忘记了数据。

LSTM 层中的输入形状为 (100,5) 表示形状为 (None, 100, 5) 的张量,即

  • None 是批量大小。您数据的第一个维度保留给您拥有的示例数。 (X 和 Y 必须具有相同数量的示例)。
  • 每个示例都是一个sequence with 100 time steps
  • 每个时间步都是一个5-dimension vector

而同一 LSTM 层中的 32 个细胞 意味着生成的向量将从 5 维向量变为 32 维向量。使用return_sequences=True,所有 100 个时间步都会出现在结果中。所以第一层的结果形状是(None, 100, 32)

  • 相同数量的示例(这在模型中永远不会改变)
  • 每个示例仍有 100 个时间步长(因为 return_sequences=True
  • 每个时间步长都是一个 32 维向量(因为有 32 个细胞)

现在第二个 LSTM 层做了完全相同的事情。保持100个时间步长,又因为它也有32个cell,所以保持32维向量,所以输出也是(None, 100, 32)

最后,时间分布的 Dense 层也将保持 100 个时间步长(因为 TimeDistributed),并再次将你的向量更改为 5 维向量(因为 5 units),结果在(None, 100, 5)


如您所见,您无法直接使用循环层更改时间步数,您需要使用其他层来更改这些维度。而如何做到这一点完全取决于你,有无数种方法可以做到这一点。

但在所有这些中,您需要摆脱时间步长并用另一种形状重建数据。


建议

我的建议(这只是一种可能性)是重塑您的结果,并应用另一个密集层来实现最终的形状。

假设你想要一个像(None, 4, 5) 这样的结果(永远不要忘记,你的数据的第一个维度是examples的数量,它可以是任何数字,但你必须考虑到当你组织您的数据)。我们可以通过将数据重塑为在第二维中包含 4 的形状来实现这一点:

#after the Dense layer:

model.add(Reshape((4,125)) #the batch size doesn't appear here, 
   #just make sure you have 500 elements, which is 100*5 = 4*125

model.add(TimeDistributed(Dense(5))
#this layer could also be model.add(LSTM(5,return_sequences=True)), for instance

#continue to the "Activation" layer

这将为您提供 4 个时间步长(因为 Reshape 之后的维度是:(None, 4, 125),每个步骤都是一个 5 维向量(因为 Dense(5))。

使用model.summary()命令查看每一层输出的形状。

【讨论】:

  • 谢谢!但是我对时间步长有疑问,我听从了你的建议,我已经测试了工作正常的 Reshape() 层,请看一下:gist.github.com/anonymous/4c8c04ad25ef349be5e9ebaec4c5830c 你可以看到摘要看起来很有希望,它显示不同的形状。但是,当我尝试 fit() 数据(第 33 行)时,问题就来了。它正在等待与输入相同数量的时间步,所以我真的不能使用 Reshape。我忘记了什么?
  • 我现在看不到您的代码,但它正在等待相同数量的“示例”。如果错误消息显示“目标”,则问题在“Y”中,如果显示“输入”,则问题在“X”中。 ---- 首先,“X”和“Y”应该有相同数量的“examples/samples”(第一个维度)。 X 中的每个示例都应始终在 Y 中给出一个结果。第二个维度,即时间步长,仅与 X 的“input_dimension”和 Y 的最后一层输出有关。
  • 假设你的input_shape=(100,5),并且你有6000个训练样本,X的形状必须像(6000, 100, 5)。如果你只有一个例子,X 必须像(1,100,5)。现在,假设您的输出形状为(None, 4, 5),Y 的形状必须类似于(6000,4,5),遵守:规则 1 - 与 X 中的示例数量相同;规则 2 - 最后一层的输出形状。 (每个例子都是一个完整的序列)。
【解决方案2】:

我不了解 Keras,但从实践和理论的角度来看,这绝对是可能的。

这个想法是你有一个输入序列和一个输出序列。通常,每个序列的开始和结束都由一些特殊符号分隔(例如,字符序列“cat”被翻译成“^cat#”,开始符号“^”和结束符号“#”)。然后用另一个特殊符号填充序列,直到 最大序列长度(例如,“^cat#$$$$$$” 和填充符号“$”)。

如果填充符号对应于零向量,则不会对您的训练产生影响。

您的输出序列现在可以假设任何长度,直到最大长度,因为实际长度是从开始到结束符号位置的长度。

换句话说,您将始终具有相同的输入和输出序列长度(即最大长度),但实际长度是开始符号和结束符号之间的长度。

(显然,在输出序列中,结束符号之后的任何内容都不应在损失函数中考虑)

【讨论】:

  • 您使用的是什么 DL 库?是的,我可以使用分隔符来理解序列的开始和结束,但我无法在 Keras 中复制它。我发现用零填充序列但总长度是固定的示例,所以我认为我应该设置一个最大长度并在句子较短时填充它。
  • 我使用 tensorflow,但通常我发现在将其提供给 tensorflow 之前直接在 python 中进行此预处理步骤(填充等)更容易(但是,有一些 tensorflow 函数可以自动完成)跨度>
  • 是的,听起来更好...我也使用 tensorflow 作为后端,但你如何填充序列?因为如果你填充句子,这意味着你使用相同的(固定)向量长度,短序列为零。
  • Giuseppe 问题是使用 seq2seq 方法输入(问题)应该很短,答案很长(我不知道长度)所以我该如何填充它?
  • 在小批量方法中,无法避免长填充:只需将所有内容填充到您的答案几乎无法克服的最大长度。通过上述问题的状态保护程序截断的 BPTT(通过时间反向传播)向您解释了如何处理长输入。对于长输出,由于您不知道答案的长度,因此您不能使用类似的方法。在在线场景中,您只需检查您的答案是否显示停止符号。如果不提供新的空白输入并恢复 RNN 的最后状态。
【解决方案3】:

您正在描述,似乎有两种方法可以执行序列到序列的方法。第一个直接使用keras使用this example(代码如下)

from keras.layers import Input, LSTM, RepeatVector
from keras.models import Model

inputs = Input(shape=(timesteps, input_dim))
encoded = LSTM(latent_dim)(inputs)

decoded = RepeatVector(timesteps)(encoded)
decoded = LSTM(input_dim, return_sequences=True)(decoded)

sequence_autoencoder = Model(inputs, decoded)
encoder = Model(inputs, encoded)

其中重复向量重复初始时间序列 n 次以匹配输出向量的时间戳数。这仍然意味着您在输出向量中需要固定数量的时间步长,但是,可能有一种方法可以填充时间戳少于最大时间步长的向量。

或者你可以使用seq2seq 模块,它建立在 keras 之上。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-28
    • 2021-07-18
    • 1970-01-01
    • 2021-07-12
    相关资源
    最近更新 更多