【问题标题】:Keras: How to concatenate 2 tensors with dynamic shapes?Keras:如何将 2 个具有动态形状的张量连接起来?
【发布时间】:2019-01-15 17:39:34
【问题描述】:

我有一个用例,我需要在 Keras 中将 2D 张量连接到 3D 张量。 3D 张量的维度是动态的(例如,3D 张量可以是形状为[batch_size, num_timesteps, num_features], 的LSTM 层的输出,其中batch_sizenum_timesteps 是动态的)。

在与 3D 张量“合并”操作之前,我使用 RepeatVector 重复 2D 张量的值。

但是,就我而言,“合并”操作会引发错误(错误详情如下)。我在下面分享了我试图实现的操作的代表性代码以及错误。

我怀疑这里的问题是动态形状的 RepeatVector。或者,我是否遗漏了一些更基本的东西?有没有办法可以正确实现这一点?

我正在使用带有 Tensorflow 后端 v1.8.0 的 Keras v2.1.6。

import keras
from keras.layers import *
input_3D = Input(shape=(None,100,), dtype='int32', name='input_3D')
input_2D = Input(shape=(100,), dtype='int32', name='input_2D')
input_2D_repeat = RepeatVector(K.shape(input_3D)[1])(input_2D)
merged = merge([input_3D, input_2D_repeat], name="merged", mode='concat')

上述代码在“合并”操作中抛出以下错误:

ValueError:“concat”模式只能合并具有匹配输出的层 除 concat 轴外的形状。图层形状:[(无,无,100), (无, , 100)]

我可以看到input_3D 中的第二个维度是None,但input_2D_repeat 中的第二个维度是tf.Tensor 'strided_slice:0' shape=() dtype=int32

我该如何解决这个问题?

【问题讨论】:

    标签: python tensorflow keras keras-layer


    【解决方案1】:

    编辑:

    再次阅读问题和我的答案后,我认为我发布的解决方案不正确。我认为你的意思是沿着特征轴连接,而不是时间轴,而且我不确定像 K.shape(input_3D)[1] 这样的张量值是否可以用作像 RepeatVector 这样的层的参数。对于你的情况,我想我可能会求助于Lambda 层来完成整个事情:

    import keras
    from keras.layers import Input, Lambda
    import keras.backend as K
    
    def repeat_and_concatenate(inputs):
        input_3D, input_2D = inputs
        # Repeat 2D vectors
        input_2D_repeat = K.tile(K.expand_dims(input_2D, 1), [1, K.shape(input_3D)[1], 1])
        # Concatenate feature-wise
        return K.concatenate([input_3D, input_2D_repeat], axis=-1)
    
    input_3D = Input(shape=(None,100,), dtype='int32', name='input_3D')
    input_2D = Input(shape=(50,), dtype='int32', name='input_2D')
    merged = Lambda(repeat_and_concatenate)([input_3D, input_2D])
    print(merged)
    # Tensor("lambda_1/concat:0", shape=(?, ?, 150), dtype=int32)
    

    下面的前一个答案可能是错误的

    您需要指定要沿“时间”轴连接(而不是默认值,即最后一个)。你可以这样做:

    import keras
    from keras.layers import *
    
    input_3D = Input(shape=(None,100,), dtype='int32', name='input_3D')
    input_2D = Input(shape=(100,), dtype='int32', name='input_2D')
    input_2D_repeat = RepeatVector(K.shape(input_3D)[1])(input_2D)
    merged = Concatenate(axis=1)([input_3D, input_2D_repeat])
    

    或者这个:

    import keras
    from keras.layers import *
    
    input_3D = Input(shape=(None,100,), dtype='int32', name='input_3D')
    input_2D = Input(shape=(100,), dtype='int32', name='input_2D')
    input_2D_repeat = RepeatVector(K.shape(input_3D)[1])(input_2D)
    merged = concatenate([input_3D, input_2D_repeat], axis=1)
    

    【讨论】:

    • 谢谢。在阅读了解决方案后,我意识到我错过了一个基本的事情,即指定 concat 的轴。这解决了我的问题。
    • 我尝试了上述代码的一些变体,但我再次遇到错误。我尝试使用轴值但没有成功。基本上,如果我将 input_2D 的形状更改为 (50,),那么上面的代码将再次失败。我正在尝试的更改是“input_2D = Input(shape=(50,), dtype='int32', name='input_2D')”。你能帮忙吗?
    • @Vinay 我认为我的答案是错误的,请参阅更新后的答案。
    • 谢谢。我可以看到这有效。您能否解释一下“K.tile(K.expand_dims(input_2D, 1), [1, K.shape(input_3D)[1], 1])”这一行。再次感谢!
    • @Vinay 是的,这与RepeatVector 几乎相同,它添加了一个维度以具有“时间”轴,然后在其上“平铺”(重复它)。它仅沿时间轴平铺,因此其他两个轴(批次和特征)在tile 参数中获得1
    猜你喜欢
    • 1970-01-01
    • 2019-02-08
    • 2019-01-07
    • 2019-09-17
    • 2021-03-30
    • 1970-01-01
    • 2019-09-10
    • 2021-04-04
    • 1970-01-01
    相关资源
    最近更新 更多