我正在使用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
的工作原理是什么?
答案 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]]
请注意,根据documentation,num_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 |的激活 单位被解释为观察的概率 特定时间的相应标签。 额外的激活 单位是观察“空白”或没有标签的概率。在一起, 这些输出定义了所有可能方式的概率 将所有可能的标签序列与输入序列对齐。