J'entraîne une cellule LSTM sur des lots de séquences de différentes longueurs. Le tf.nn.rnn a le paramètre très pratique sequence_length, mais après l'avoir appelé, je ne sais pas comment choisir les lignes de sortie correspondant au dernier pas de temps de chaque article du lot.

Mon code est essentiellement le suivant:

lstm_cell = tf.nn.rnn_cell.LSTMCell(num_lstm_units, input_size)
lstm_outputs, state = tf.nn.rnn(lstm_cell, input_list, dtype=tf.float32, sequence_length=sequence_lengths)

lstm_outputs est une liste avec la sortie LSTM à chaque pas de temps. Cependant, chaque élément de mon lot a une longueur différente, et je voudrais donc créer un tenseur contenant la dernière sortie LSTM valide pour chaque élément de mon lot.

Si je pouvais utiliser l'indexation numpy, je ferais simplement quelque chose comme ceci:

all_outputs = tf.pack(lstm_outputs)
last_outputs = all_outputs[sequence_lengths, tf.range(batch_size), :]

Mais il s'avère que pour l'instant le tensorflow ne le prend pas en charge (je connais la fonctionnalité demande).

Alors, comment pourrais-je obtenir ces valeurs?

5
erickrf 7 mars 2016 à 07:02

3 réponses

Meilleure réponse

Une solution de contournement plus acceptable a été publiée par danijar sur la page de demande de fonctionnalité que j'ai liée dans la question. Il n'a pas besoin d'évaluer les tenseurs, ce qui est un gros plus.

Je l'ai fait fonctionner avec tensorflow 0.8. Voici le code:

def extract_last_relevant(outputs, length):
    """
    Args:
        outputs: [Tensor(batch_size, output_neurons)]: A list containing the output
            activations of each in the batch for each time step as returned by
            tensorflow.models.rnn.rnn.
        length: Tensor(batch_size): The used sequence length of each example in the
            batch with all later time steps being zeros. Should be of type tf.int32.

    Returns:
        Tensor(batch_size, output_neurons): The last relevant output activation for
            each example in the batch.
    """
    output = tf.transpose(tf.pack(outputs), perm=[1, 0, 2])
    # Query shape.
    batch_size = tf.shape(output)[0]
    max_length = int(output.get_shape()[1])
    num_neurons = int(output.get_shape()[2])
    # Index into flattened array as a workaround.
    index = tf.range(0, batch_size) * max_length + (length - 1)
    flat = tf.reshape(output, [-1, num_neurons])
    relevant = tf.gather(flat, index)
    return relevant
5
erickrf 3 mai 2016 à 10:13

Si vous n'êtes intéressé que par la dernière sortie valide, vous pouvez la récupérer via l'état retourné par tf.nn.rnn() en considérant qu'il s'agit toujours d'un tuple (c, h) où c est le dernier état et h est la dernière sortie. Lorsque l'état est un LSTMStateTuple, vous pouvez utiliser l'extrait de code suivant (fonctionnant dans tensorflow 0.12):

lstm_cell = tf.nn.rnn_cell.LSTMCell(num_lstm_units, input_size)
lstm_outputs, state = tf.nn.rnn(lstm_cell, input_list, dtype=tf.float32, sequence_length=sequence_lengths)
last_output = state[1]
1
learningTask 15 janv. 2017 à 13:28

Ce n'est pas la meilleure solution, mais vous pouvez évaluer vos sorties, puis utiliser simplement l'indexation numpy pour obtenir les résultats et créer une variable tensorielle à partir de cela? Cela pourrait fonctionner comme un espace d'arrêt jusqu'à ce que tensorflow obtienne cette fonctionnalité. par exemple.

all_outputs = session.run(lstm_outputs, feed_dict={'your inputs'})
last_outputs = all_outputs[sequence_lengths, tf.range(batch_size), :]
use_this_as_an_input_to_new_tensorflow_op = tf.constant(last_outputs)
2
Daniel Slater 7 mars 2016 à 14:17