Tensorflow:无法理解ctc_beam_search_decoder()输出序列

时间:2017-08-03 11:24:55

标签: python tensorflow beam-search

我正在使用Tensorflow的tf.nn.ctc_beam_search_decoder()来解码RNN的输出,进行多对多映射(即每个网络小区的多个softmax输出)。

网络输出的简化版本和Beam搜索解码器是:

import numpy as np
import tensorflow as tf

batch_size = 4
sequence_max_len = 5
num_classes = 3

y_pred = tf.placeholder(tf.float32, shape=(batch_size, sequence_max_len, num_classes))
y_pred_transposed = tf.transpose(y_pred,
                                 perm=[1, 0, 2])  # TF expects dimensions [max_time, batch_size, num_classes]
logits = tf.log(y_pred_transposed)
sequence_lengths = tf.to_int32(tf.fill([batch_size], sequence_max_len))
decoded, log_probabilities = tf.nn.ctc_beam_search_decoder(logits,
                                                           sequence_length=sequence_lengths,
                                                           beam_width=3,
                                                           merge_repeated=False, top_paths=1)

decoded = decoded[0]
decoded_paths = tf.sparse_tensor_to_dense(decoded)  # Shape: [batch_size, max_sequence_len]

with tf.Session() as session:
    tf.global_variables_initializer().run()

    softmax_outputs = np.array([[[0.1, 0.1, 0.8], [0.8, 0.1, 0.1], [0.8, 0.1, 0.1], [0.8, 0.1, 0.1], [0.8, 0.1, 0.1]],
                                [[0.1, 0.2, 0.7], [0.1, 0.2, 0.7], [0.1, 0.2, 0.7], [0.1, 0.2, 0.7], [0.1, 0.2, 0.7]],
                                [[0.1, 0.7, 0.2], [0.1, 0.2, 0.7], [0.1, 0.2, 0.7], [0.1, 0.2, 0.7], [0.1, 0.2, 0.7]],
                                [[0.1, 0.2, 0.7], [0.1, 0.2, 0.7], [0.1, 0.2, 0.7], [0.1, 0.2, 0.7], [0.1, 0.2, 0.7]]])

    decoded_paths = session.run(decoded_paths, feed_dict = {y_pred: softmax_outputs})
    print(decoded_paths)

这种情况下的输出是:

[[0]
 [1]
 [1]
 [1]]

我的理解是输出张量应该是维度[batch_size, max_sequence_len],每行包含找到路径中相关类的索引。

在这种情况下,我希望输出类似于:

[[2, 0, 0, 0, 0],
 [2, 2, 2, 2, 2],
 [1, 2, 2, 2, 2],
 [2, 2, 2, 2, 2]]

我不了解ctc_beam_search_decoder的工作原理是什么?

1 个答案:

答案 0 :(得分:23)

tf.nn.ctc_beam_search_decoder documentation所示,输出的形状不是[batch_size, max_sequence_len]。相反,它是

[batch_size, max_decoded_length[j]]

(在您的情况下为j=0)。

基于this paper第2部分的开头(github repository中引用),max_decoded_length[0]max_sequence_len从上面开始,但它们不一定等于。相关的引用是:

  

设S是一组从固定分布中提取的训练样例   D_ {} XXZ。输入空间X =(R ^ m)是m的所有序列的集合   维实值向量。目标空间Z = L *是一组   标签的(有限)字母L上的所有序列。一般来说,我们   将L *的元素称为标记序列或标记。每个例子   在S中由一对序列(x,z)组成。目标序列z =   (z1,z2,...,zU)最多与输入序列x =(x1一样长,   x2,...,xT),即U <= T。由于输入和目标序列是   通常不是相同的长度,没有先验的对齐方式   它们。

事实上,max_decoded_length[0]取决于具体的矩阵softmax_outputs。特别是,具有完全相同尺寸的两个这样的矩阵可以导致不同的max_decoded_length[0]

例如,如果替换行

softmax_outputs = np.array([[[0.1, 0.1, 0.8], [0.8, 0.1, 0.1], [0.8, 0.1, 0.1], [0.8, 0.1, 0.1], [0.8, 0.1, 0.1]],
                                [[0.1, 0.2, 0.7], [0.1, 0.2, 0.7], [0.1, 0.2, 0.7], [0.1, 0.2, 0.7], [0.1, 0.2, 0.7]],
                                [[0.1, 0.7, 0.2], [0.1, 0.2, 0.7], [0.1, 0.2, 0.7], [0.1, 0.2, 0.7], [0.1, 0.2, 0.7]],
                                [[0.1, 0.2, 0.7], [0.1, 0.2, 0.7], [0.1, 0.2, 0.7], [0.1, 0.2, 0.7], [0.1, 0.2, 0.7]]])

包含行

np.random.seed(7)
r=np.random.randint(0,100,size=(4,5,3))
softmax_outputs=r/np.sum(r,2).reshape(4,5,1)

您将获得输出

[[1 0 1]
 [1 0 1]
 [1 0 0]
 [1 0 0]]

(在上面的示例中,softmax_outputs由logits组成,它与您提供的矩阵完全相同。

另一方面,将种子更改为np.random.seed(50)会产生输出

[[1 0]
 [1 0]
 [1 0]
 [0 1]]

P.S。

关于问题的最后部分:

  

在这种情况下,我希望输出类似于:

[[2, 0, 0, 0, 0],
 [2, 2, 2, 2, 2],
 [1, 2, 2, 2, 2],
 [2, 2, 2, 2, 2]]

请注意,根据documentationnum_classes实际上代表num_labels + 1。具体做法是:

  

输入Tensor的最内层尺寸大小num_classes代表   num_labels + 1个类,其中num_labels是真实标签的数量,   并且为空白保留最大值(num_classes - 1)   标签

     

例如,对于包含3个标签[a,b,c]的词汇表,   num_classes = 4,标签索引为{a:0,b:1,c:2,空白:   3}。

因此,您案例中的真实标签为0和1,并且为空白标签保留2。空白标签代表没有标签的情况(第3.1节here):

  

CTC网络还有一个softmax输出层(Bridle,1990)   单位比L中有标签。第一个| L |的激活   单位被解释为观察的概率   特定时间的相应标签。 额外的激活   单位是观察“空白”或没有标签的概率。在一起,   这些输出定义了所有可能方式的概率   将所有可能的标签序列与输入序列对齐。