将输入张量与多个1个负张量串联

时间:2019-09-29 19:44:44

标签: keras tf.keras

相似的帖子:首先,这两个帖子是相似的,即使不相同。我试图白白实现这些。所以我想念某些东西可能是因为我对Keras缺乏经验。 similar 1similar 2

问题: 我有一个数据生成器,可将数据输入各种模型中以评估模型性能并学习Keras。

model.fit_generator(generator=img_gen.next_train(), ....

此生成器产生的输入之一是形状= [batch_size,num_letters]的张量“标签”。张量是

的第一个输入
K.ctc_batch_cost(labels, .... 

类似于image_ocr.py 369行。

上面的“ keras示例”创建了一个RNN / GRU,其中RNN的每个输出步骤是ctc的一个输入,其中RNN中有num_letters个步骤,并且标签的形状为(?,num_letters)。到目前为止,我测试的前6个模型都可以正常工作。

我正在测试一个新模型,其中RNN / GRU输出的每一步都是ctc的“ 1到n”输入,并将其训练以优化每一步的输出。因此,我的ctc首先需要输入shape =(?, num_letters * n)的张量,但是数据生成器会生成shape =(?, num_letters)。

侧面说明:我的模型中的RNN实际上产生为一个整体=(?, n,num_letters)。我知道如何将其转换为(?,n * num_letters)。

解决方案1 ​​是一个hack,请更改生成器,以使其对于正在测试的模型是唯一的。此生成器将生成形状为(?,num_letters * n)的张量。我不喜欢这样,因为生成器也在被评估,并且希望对于每个被评估模型都保持不变。

解决方案2 是一个hack,创建一个生成器,该生成器封装原始生成器并增加生成的输出。

解决方案3::让模型输入shape =(?, num_letters)并连接必要的填充,以便形状为ctc所需的(?,num_letters * n)。

这是我尝试的方法:

num_letters = 3
n = 5

keras_tensor_input = keras.layers.Input( shape=[num_letters], dtype='float32' )
print("keras_tensor_input = ", keras_tensor_input)
# keras_tensor_input =  Tensor("input_1:0", shape=(?, 3), dtype=float32)
# note ? is batch size

keras_tensor_neg_1 = keras.backend.constant( -1, dtype='float32', shape=[num_letters] )
print("keras_tensor_neg_1 = ", keras_tensor_neg_1)
# keras_tensor_neg_1 =  Tensor("Const_1:0", shape=(3,), dtype=float32)
# note no batch size

keras_tensor_neg_1_tiled = keras.backend.tile(keras_tensor_neg_1, (n-1))
print("keras_tensor_neg_1_tiled = ", keras_tensor_neg_1_tiled)
# keras_tensor_neg_1_tiled =  Tensor("Tile_2:0", shape=(12,), dtype=float32)
# note no batch size, but now the correct fill length

# FAILED attempt to put in a batch size

layer_const_neg_1 = keras.layers.Lambda(lambda x: keras_tensor_neg_1_tiled ,output_shape=[(n-1)*num_letters] )
keras_tensor_neg_1_prime = layer_const_neg_1(keras_tensor_neg_1)
print("keras_tensor_neg_1_prime = ", keras_tensor_neg_1_prime)
# keras_tensor_neg_1_prime =  Tensor("Tile_2:0", shape=(12,), dtype=float32)

# CRASH AT NEXT STEP BECAUSE NO ? in keras_tensor_neg_1_prime

# concatenate the input from the generator and the padding
keras_tensor_concat = keras.layers.Concatenate()( inputs = [keras_tensor_input, keras_tensor_neg_1_prime] )
print("keras_tensor_concat = ", keras_tensor_concat)

my_model = keras.models.Model( inputs=[keras_tensor_input], output=keras_tensor_concat)

# dummy optimizer, loss, and metric just to allow compile to pass
my_model.compile(optimizer='rmsprop',loss='categorical_crossentropy', metrics=['accuracy'])

# a batch of size 1, for a tensor of shape =[3]
d1 = numpy.array([[1, 2, 3]])

out = my_model.predict( [ d1 ] )
print(out)

注释:

  1. 本来可以使恒定形状= [num_letters *(n-1)]并放下磁贴,但是仍然存在缺少批处理大小的相同问题。
  2. 如果我将batch_size作为第一个维度,那么它仍然无法抱怨无法将(?,3)与(1,12)串联

谢谢。

1 个答案:

答案 0 :(得分:0)

我找到了采用模型的解决方案

# a batch of size 1, for a tensor of shape =[3]
d1 = numpy.array([[1, 2, 3]])

并产生输出

out = my_model.predict( [ d1 ] )
print(out)
# [[ 1.  2.  3. -1. -1. -1. -1. -1. -1. -1. -1. -1. -1. -1. -1.]]

一个重要的教训是, keras.layers 要作为其他 keras.layers 的输出作为输入。因此,必须将 keras.backend 之类的功能(例如 tile )包装在 keras.layers.Lambda 中,然后再将其作为输入输入到 keras.layer中

谢谢

这是解决方案:

# instantiate a Keras tensor ... as per document https://keras.io/layers/core/
keras_tensor_input = keras.layers.Input( shape=[num_letters], dtype='float32' )
print("keras_tensor_input = ", keras_tensor_input)
# keras_tensor_input =  Tensor("input_1:0", shape=(?, 3), dtype=float32)

# https://stackoverflow.com/questions/53865471/using-subtract-layer-in-keras
keras_tensor_neg_1 = keras.layers.Lambda(lambda x: -keras.backend.ones_like(x) )(keras_tensor_input)
print("keras_tensor_neg_1 = ", keras_tensor_neg_1)
# keras_tensor_neg_1 =  Tensor("lambda_1/Neg:0", shape=(?, 3), dtype=float32)
# note batch size, just like keras_tensor_input

# https://stackoverflow.com/questions/53250533/how-to-use-tile-function-in-keras
keras_tensor_neg_1_tiled = keras.layers.Lambda(lambda x: keras.backend.tile(x, (1, n-1)))(keras_tensor_neg_1)
print("keras_tensor_neg_1_tiled = ", keras_tensor_neg_1_tiled)
# keras_tensor_neg_1_tiled =  Tensor("Tile_2:0", shape=(12,), dtype=float32)
# note batch size, just like keras_tensor_input

# concatenate the input from the generator and the padding
keras_tensor_concat = keras.layers.Concatenate()( inputs = [keras_tensor_input, keras_tensor_neg_1_tiled] )
print("keras_tensor_concat = ", keras_tensor_concat)
# keras_tensor_concat =  Tensor("concatenate_1/concat:0", shape=(?, 15), dtype=float32)

my_model = keras.models.Model( inputs=keras_tensor_input, output=keras_tensor_concat)

# dummy optimizer, loss, and metric so I can compile and test the model
my_model.compile(optimizer='rmsprop',loss='categorical_crossentropy', metrics=['accuracy'])

# a batch of size 1, for a tensor of shape =[3]
d1 = numpy.array([[1, 2, 3]])

out = my_model.predict( [ d1 ] )
print(out)
# [[ 1.  2.  3. -1. -1. -1. -1. -1. -1. -1. -1. -1. -1. -1. -1.]]