Керас: Как объединить 2 тензора с динамическими фигурами?

У меня есть случай использования, когда мне нужно объединить 2D-тензор с 3D-тензором в Keras. Размеры трехмерного тензора являются динамическими (например, трехмерный тензор может быть выходом слоя LSTM с формой [batch_size, num_timesteps, num_features],, где batch_size и num_timesteps являются динамическими).

Я использовал RepeatVector, чтобы повторить значения 2D-тензора перед операцией «слияния» с 3D-тензором.

Но в моем случае операция «слияния» выдает ошибку (подробности об ошибке см. Ниже). Ниже я поделился типичным кодом операций, которые я пытаюсь выполнить, вместе с ошибкой.

Я подозреваю, что проблема здесь в 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')

Приведенный выше код вызывает ошибку при операции «слияния»:

ValueError: в режиме «concat» можно объединять только слои с соответствующими выходными формами, за исключением оси concat. Формы слоя: [(Нет, Нет, 100), (Нет,, 100)]

Я вижу, что второе измерение в input_3D это None, но второе измерение в input_2D_repeat это tf.Tensor 'strided_slice:0' shape=() dtype=int32.

Как я могу это исправить?


person Vinay    schedule 15.01.2019    source источник


Ответы (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)
person jdehesa    schedule 15.01.2019
comment
Спасибо. После прочтения решения я понимаю, что упустил фундаментальную вещь, то есть указание оси для concat. Это решает мою проблему. - person Vinay; 15.01.2019
comment
Я пробовал несколько вариантов приведенного выше кода и снова обнаружил ошибку. Я попытался поиграть со значением оси, но безуспешно. По сути, если я изменю форму input_2D на (50,), то приведенный выше код снова не сработает. Я пытаюсь изменить input_2D = Input (shape = (50,), dtype = 'int32', name = 'input_2D'). Вы можете помочь? - person Vinay; 18.01.2019
comment
@Vinay Я думаю, что мой ответ был неправильным, см. Обновленный ответ. - person jdehesa; 18.01.2019
comment
Спасибо. Я вижу, что это работает. Не могли бы вы объяснить строку K.tile (K.expand_dims (input_2D, 1), [1, K.shape (input_3D) [1], 1]). Спасибо еще раз! - person Vinay; 19.01.2019
comment
@Vinay Да, это почти то же самое, что и RepeatVector, он добавляет одно измерение, чтобы иметь ось времени, а затем плитки (повторяет его) поверх него. Он разбивается только на временную ось, поэтому две другие оси (пакет и функции) получают 1 в аргументе tile. - person jdehesa; 20.01.2019