Keras:如何将 2 个张量与动态形状连接起来?

Keras: How to concatenate 2 tensors with dynamic shapes?

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

我已经使用 RepeatVector 在对 3D 张量进行 "merge" 操作之前重复 2D 张量的值。

但是,在我的例子中,"merge" 操作会引发错误(错误详情如下)。我在下面分享了我要实现的操作的代表性代码以及错误。

我怀疑这里的问题是动态形状的 RepeatVector。或者,我错过了更基本的东西吗?有什么方法可以让我正确地做到这一点?

我正在使用 Keras v2.1.6 和 Tensorflow 后端 v1.8.0。

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')

以上代码针对 "merge" 操作抛出以下错误:

ValueError: "concat" mode can only merge layers with matching output shapes except for the concat axis. Layer shapes: [(None, None, 100), (None, , 100)]

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

我该如何解决这个问题?

编辑:

重新看了一遍问题和我的回答,我觉得我贴的解决方案不正确。我认为你的意思是沿着特征轴连接,而不是时间轴,而且我不确定像 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)

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

您需要指定要沿 "time" 轴串联(而不是默认值,即最后一个)。你可以这样做:

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)