Подтвердить что ты не робот

Tensorflow: не может понять последовательность вывода ctc_beam_search_decoder()

Я использую 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?

4b9b3361

Ответ 1

Как указано в tf.nn.ctc_beam_search_decoder документации, форма вывода не [batch_size, max_sequence_len]. Вместо этого это

[batch_size, max_decoded_length[j]]

j=0 в вашем случае).

Основываясь на начале раздела 2 этой статьи (который цитируется в репозиторий github), 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 состоит из логитов, и это точно такие же размеры, как и предоставленная вами матрица).

С другой стороны, изменение семени на 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]]

Обратите внимание, что на основе документации num_classes фактически представляет num_labels + 1. В частности:

Входы Внутренний размер измерения тензора, num_classes, представляет num_labels + 1, где num_labels - количество истинных меток, и наибольшее значение (num_classes - 1) зарезервировано для пробела метка.

Например, для словаря, содержащего 3 метки [a, b, c], num_classes = 4 и индексирование меток: {a: 0, b: 1, c: 2, blank: 3}.

Таким образом, истинные метки в вашем случае равны 0 и 1, а 2 - для пустой метки. Пустая метка представляет ситуацию отсутствия метки (раздел 3.1 здесь):

Сеть CTC имеет выходной уровень softmax (Bridle, 1990) с еще одним чем есть метки в L. Активации первого | L | единицы интерпретируются как вероятности наблюдения соответствующие метки в определенное время. Активация дополнительного единица - вероятность наблюдения "пустой" или "нет". Вместе, эти результаты определяют вероятности всех возможных выравнивание всех возможных последовательностей меток с входной последовательностью.