python - Tensorflow: no se puede entender la secuencia de salida ctc_beam_search_decoder()
beam-search (1)
Estoy usando el tf.nn.ctc_beam_search_decoder()
de tf.nn.ctc_beam_search_decoder()
para decodificar la salida de un RNN haciendo un mapeo muchos-muchos (es decir, múltiples salidas de softmax para cada celda de red).
Una versión simplificada de la salida de la red y el decodificador de búsqueda de Beam es:
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)
El resultado en este caso es:
[[0]
[1]
[1]
[1]]
[batch_size, max_sequence_len]
el tensor de salida debe ser de dimensiones [batch_size, max_sequence_len]
, y cada fila contiene los índices de las clases relevantes en la ruta encontrada.
En este caso, esperaría que el resultado fuera similar a:
[[2, 0, 0, 0, 0],
[2, 2, 2, 2, 2],
[1, 2, 2, 2, 2],
[2, 2, 2, 2, 2]]
¿Qué no estoy entendiendo sobre cómo funciona ctc_beam_search_decoder
?
Como se indica en la documentación tf.nn.ctc_beam_search_decoder , la forma de la salida no es [batch_size, max_sequence_len]
. En cambio, es
[batch_size, max_decoded_length[j]]
(con j=0
en tu caso).
Basado en el comienzo de la sección 2 de este documento (que se cita en el repositorio de github ), max_decoded_length[0]
está delimitado desde arriba por max_sequence_len
, pero no son necesariamente iguales. La cita relevante es:
Sea S un conjunto de ejemplos de entrenamiento extraídos de una distribución fija D_ {XxZ}. El espacio de entrada X = (R ^ m) es el conjunto de todas las secuencias de vectores dimensionales con valores reales. El espacio objetivo Z = L * es el conjunto de todas las secuencias sobre el alfabeto (finito) L de las etiquetas. En general, nos referimos a elementos de L * como secuencias de etiquetas o etiquetados. Cada ejemplo en S consiste en un par de secuencias (x, z). La secuencia objetivo z = (z1, z2, ..., zU) es como máximo tan larga como la secuencia de entrada x = (x1, x2, ..., xT), es decir, U <= T. Dado que las secuencias de entrada y de destino generalmente no tienen la misma longitud, no hay una forma a priori de alinearlas.
De hecho, max_decoded_length[0]
depende de la matriz específica softmax_outputs
. En particular, dos de tales matrices con exactamente las mismas dimensiones pueden dar como resultado diferentes max_decoded_length[0]
.
Por ejemplo, si reemplaza la fila
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]]])
con las filas
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)
obtendrás la salida
[[1 0 1]
[1 0 1]
[1 0 0]
[1 0 0]]
(en los ejemplos anteriores, softmax_outputs
consta de logits y tiene exactamente las mismas dimensiones que la matriz que proporcionó).
Por otro lado, cambiando la semilla a np.random.seed(50)
da la salida
[[1 0]
[1 0]
[1 0]
[0 1]]
PD
Respecto a la última parte de su pregunta:
En este caso, esperaría que el resultado fuera similar a:
[[2, 0, 0, 0, 0], [2, 2, 2, 2, 2], [1, 2, 2, 2, 2], [2, 2, 2, 2, 2]]
Tenga en cuenta que, en función de la documentation , num_classes
realidad representa num_labels + 1
. Específicamente:
Las entradas El tamaño de dimensión más interno de Tensor,
num_classes
, representanum_labels + 1
clases, dondenum_labels
es el número de etiquetas verdaderas, y el valor más grande (num_classes - 1
) está reservado para la etiqueta en blanco.Por ejemplo, para un vocabulario que contiene 3 etiquetas [a, b, c],
num_classes = 4
y la indexación de las etiquetas es {a: 0, b: 1, c: 2, blank: 3}.
Entonces las etiquetas verdaderas en su caso son 0 y 1, y 2 está reservado para la etiqueta en blanco. La etiqueta en blanco representa la situación de no observar etiqueta (sección 3.1 aquí ):
Una red CTC tiene una capa de salida softmax (Bridle, 1990) con una unidad más que etiquetas en L. Las activaciones de la primera | L | las unidades se interpretan como las probabilidades de observar las etiquetas correspondientes en momentos particulares. La activación de la unidad extra es la probabilidad de observar una etiqueta ''en blanco'' o no. Juntas, estas salidas definen las probabilidades de todas las formas posibles de alinear todas las secuencias de etiquetas posibles con la secuencia de entrada.