web-dev-qa-db-ja.com

TensorFlowで可変長シーケンスのバッチを処理する方法は?

シーケンス予測にRNN(特にLSTM)を使用しようとしていました。しかし、可変シーケンス長の問題に遭遇しました。例えば、

sent_1 = "I am flying to Dubain"
sent_2 = "I was traveling from US to Dubai"

これに基づいた単純なRNNを使用して、現在の単語の次の単語を予測しようとしています PTB LSTMモデルを構築するためのベンチマーク

しかし num_stepsパラメータ(以前の非表示状態への展開に使用)は、各Tensorflowのエポックで同じままにする必要があります。基本的に、文の長さが異なるため、文のバッチ処理はできません。

 # inputs = [tf.squeeze(input_, [1])
 #           for input_ in tf.split(1, num_steps, inputs)]
 # outputs, states = rnn.rnn(cell, inputs, initial_state=self._initial_state)

ここに、 num_steps私の場合、文ごとに変更する必要があります。いくつかのハックを試しましたが、何も機能していないようです。

21
Seja Nair

以下に説明されているバケット化とパディングのアイデアを使用できます。

シーケンス間モデル

また、RNNネットワークを作成するrnn関数は、パラメーターsequence_length。を受け入れます

例として、同じサイズの文のバケットを作成し、必要な量のゼロでパディングするか、Wordを表すプレースホルダーを使用して、その後にseq_length = len(zero_words)でそれらをフィードできます。

seq_length = tf.placeholder(tf.int32)
outputs, states = rnn.rnn(cell, inputs, initial_state=initial_state, sequence_length=seq_length)

sess = tf.Session()
feed = {
    seq_length: 20,
    #other feeds
}
sess.run(outputs, feed_dict=feed)

このredditスレッドもご覧ください。

「可変長」シーケンスを使用したTensorflowの基本的なRNNの例

21
Taras Sereda

代わりにdynamic_rnnを使用し、配列をsequence_lengthパラメーターに渡すことで、1つのバッチ内でもすべてのシーケンスの長さを指定できます。以下に例を示します。

def length(sequence):
    used = tf.sign(tf.reduce_max(tf.abs(sequence), reduction_indices=2))
    length = tf.reduce_sum(used, reduction_indices=1)
    length = tf.cast(length, tf.int32)
    return length

from tensorflow.nn.rnn_cell import GRUCell

max_length = 100
frame_size = 64
num_hidden = 200

sequence = tf.placeholder(tf.float32, [None, max_length, frame_size])
output, state = tf.nn.dynamic_rnn(
    GRUCell(num_hidden),
    sequence,
    dtype=tf.float32,
    sequence_length=length(sequence),
)

コードはトピックの 完全な記事 から取得されます。チェックしてください。

更新:別の 素晴らしい投稿 on dynamic_rnn vs rnn

15
Datalker

入力シーケンスの最大長を制限し、短いシーケンスをその長さにパディングし、各シーケンスの長さを記録して、 tf.nn.dynamic_rnn を使用できます。入力シーケンスを通常どおり処理しますが、seq_lengthで示されるシーケンスの最後の要素の後、セルの状態をそのままコピーし、出力のためにゼロテンソルを出力します。

4
tnq177

で説明されているバケット化とパディングのアイデアを使用できます。

シーケンス間モデル

また、RNNネットワークを作成するrnn関数は、パラメーターsequence_lengthを受け入れます。

例として、同じサイズのセンテンスのバケットを作成し、必要な量のゼロをパディングするか、ゼロのWordを意味するplaceholdresにseq_length = len(zero_words)を付けてフィードできます。

seq_length = tf.placeholder(tf.int32)
outputs, states = rnn.rnn(cell, inputs,initial_state=initial_state,sequence_length=seq_length)

sess = tf.Session()
feed = {
seq_lenght: 20,
#other feeds
       }
sess.run(outputs, feed_dict=feed)

ここで、最も重要なことは、sequence_lengthを提供するときに、1つの文によって取得された状態を次の文の状態として使用する場合です(たとえば、20とパディング後の文は50です)。 20番目のタイムステップで取得した状態が必要です。そのために、行う

tf.pack(states)

その呼び出しの後

for i in range(len(sentences)):
state_mat   = session.run([states],{
            m.input_data: x,m.targets: y,m.initial_state: state,     m.early_stop:early_stop })
state = state_mat[early_stop-1,:,:]
4
Seja Nair

死んだ問題について投稿して申し訳ありませんが、より良い解決策のためにPRを提出しました。 dynamic_rnnは非常に柔軟ですが、非常に遅いです。それが唯一のオプションである場合は機能しますが、CuDNNははるかに高速です。このPRはCuDNNLSTMに可変長のサポートを追加するので、すぐにそれを使用できることを願っています。

長さの降順でシーケンスをソートする必要があります。その後、pack_sequence、RNNを実行してからunpack_sequence

https://github.com/tensorflow/tensorflow/pull/22308

1