如何在 Keras 中组合两个具有不同输入大小的 LSTM 层?

Posted

技术标签:

【中文标题】如何在 Keras 中组合两个具有不同输入大小的 LSTM 层?【英文标题】:How to combine two LSTM layers with different input sizes in Keras? 【发布时间】:2020-06-26 00:19:36 【问题描述】:

我有两种类型的输入序列,其中input1 包含 50 个值,input2 包含 25 个值。我尝试在功能 API 中使用 LSTM 模型组合这两种序列类型。但是,由于我的两个输入序列的长度不同,我想知道我目前正在做的是否是正确的方法。我的代码如下:

input1 = Input(shape=(50,1))
x1 = LSTM(100)(input1)
input2 = Input(shape=(25,1))
x2 = LSTM(50)(input2)

x = concatenate([x1,x2])
x = Dense(200)(x)
output = Dense(1, activation='sigmoid')(x)

model = Model(inputs=[input1,input2], outputs=output)

更具体地说,我想知道如何组合两个具有不同输入长度的 LSTM 层(在我的例子中是 50 和 25)。如果需要,我很乐意提供更多详细信息。

【问题讨论】:

你能澄清一下你想要合并两个 lstm 层的意思吗?你现在这样做的方式是连接输出,即将两个 LSTM 层的输出放入下一个密集层。那个 imo 似乎没有什么问题。 @JohannesAck 谢谢你的评论。我的意思是我的输入序列的长度是不同的(即 50 和 25)。此外,我的 LSTM 层中的节点数也不同。我想澄清它们是否会对concatenate 功能产生任何影响。期待您的来信:) @EmJ 由于您使用的是每个 LSTM 层的最后一个输出(即return_sequences=False),因此连接将正常工作:它得到两个形状为(?, 100)(?, 50) 的输入并输出一个形状张量(?, 150)。换句话说,有了这个设置,两个输入序列的长度不会影响连接函数。 【参考方案1】:

实际上,您的问题在 NLP 之类的任务中很正常,因为您有不同的序列长度。在您的评论中,您使用 return_sequences=False 丢弃所有先前的输出,这在我们的实践中并不常见,通常会导致模型性能低下。

注意:神经网络架构设计没有终极解决方案

这是我的建议。

方法 1(无需自定义层)

您可以在两个 LSTM 中使用相同的潜在维度并将它们堆叠在二维中,并将它们视为一个大的隐藏层张量。

input1 = Input(shape=(50,1))
x1 = LSTM(100, return_sequences=True)(input1)
input2 = Input(shape=(25,1))
x2 = LSTM(100, return_sequences=True)(input2)
x = concatenate([x1,x2], axis=1)

# output dimension = (None, 75, 100)

如果你不想拥有相同的潜在维度,其他人所做的就是增加 1 个部分,我们通常称之为映射层,由密集层堆叠而成。这种方法有更多的变量,这意味着模型更难训练。

input1 = Input(shape=(50,1))
x1 = LSTM(100, return_sequences=True)(input1)
input2 = Input(shape=(25,1))
x2 = LSTM(50, return_sequences=True)(input2)

# normally we have more than 1 hidden layer
Map_x1 = Dense(75)(x1)
Map_x2 = Dense(75)(x2)
x = concatenate([Map_x1 ,Map_x2 ], axis=1)

# output dimension = (None, 75, 75)

或者扁平化输出(两者都)

input1 = Input(shape=(50,1))
x1 = LSTM(100, return_sequences=True)(input1)
input2 = Input(shape=(25,1))
x2 = LSTM(50, return_sequences=True)(input2)

# normally we have more than 1 hidden layer
flat_x1 = Flatten()(x1)
flat_x2 = Flatten()(x2)
x = concatenate([flat_x1 ,flat_x2 ], axis=1)

# output (None, 2650)

方法 2(需要自定义层)

创建您的自定义层并使用产生注意力向量的注意力机制,并将该注意力向量用作 LSTM 输出张量的表示。其他人所做并获得更好性能的是使用 LSTM 的最后隐藏状态(您仅在模型中使用)和注意力向量作为表示。

注意:根据研究,不同类型的注意力提供几乎相同的性能,所以我推荐“Scaled Dot-Product Attention”,因为它计算速度更快。

input1 = Input(shape=(50,1))
x1 = LSTM(100, return_sequences=True)(input1)
input2 = Input(shape=(25,1))
x2 = LSTM(50, return_sequences=True)(input2)

rep_x1 = custom_layer()(x1)
rep_x2 = custom_layer()(x2)
x = concatenate([rep_x1 ,rep_x2], axis=1)

# output (None, (length rep_x1+length rep_x2))

【讨论】:

哇,非常感谢您的出色回答。我对您对自定义层的想法很感兴趣。但是,在它的代码中x = concatenate([flat_x1 ,flat_x2 ], axis=1) 应该是x = concatenate([rep_x1 ,rep_x2 ], axis=1) 对吧?我们需要自己写custom_layer()还是我需要导入?请让我知道你的想法。谢谢你:) 是的,你是对的,感谢指出错误,通常我们所做的是创建自己的函数,你可以导入那些自定义层(如果你找到了),你有更高的机会必须自己创建。 很抱歉我在我的电脑中找不到我的代码。您可以在此链接keras.io/layers/writing-your-own-keras-layers 中学习如何编写 keras 自定义层 如果你希望你的输出只有 (batch, 2) 用于二进制分类并且你不想实现自定义功能,我建议你可以使用 flatten 输出然后使用密集层输出 = Dense (1, activation='sigmoid')(x) 可以正常工作。 是的,你说得对,输出是 3D,这可能不适合你的任务。现在,我想你现在知道 keras 层是相当有限的,大多数时候我们需要在研究时创建自定义层。祝你好运!!

以上是关于如何在 Keras 中组合两个具有不同输入大小的 LSTM 层?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Keras 中训练网络以适应不同的输出大小

SNPE - 如何预测具有两个(或更多)输入的模型?

如何组合两个 keras 生成器功能

QtDesigner - 两个具有不同大小的相同组合框

如何在 keras 中提供可变大小的图像作为输入

在 Keras 中添加 vs 连接层