シーケンス予測に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
私の場合、文ごとに変更する必要があります。いくつかのハックを試しましたが、何も機能していないようです。
以下に説明されているバケット化とパディングのアイデアを使用できます。
また、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スレッドもご覧ください。
代わりに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
入力シーケンスの最大長を制限し、短いシーケンスをその長さにパディングし、各シーケンスの長さを記録して、 tf.nn.dynamic_rnn を使用できます。入力シーケンスを通常どおり処理しますが、seq_length
で示されるシーケンスの最後の要素の後、セルの状態をそのままコピーし、出力のためにゼロテンソルを出力します。
で説明されているバケット化とパディングのアイデアを使用できます。
また、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,:,:]
死んだ問題について投稿して申し訳ありませんが、より良い解決策のためにPRを提出しました。 dynamic_rnn
は非常に柔軟ですが、非常に遅いです。それが唯一のオプションである場合は機能しますが、CuDNNははるかに高速です。このPRはCuDNNLSTM
に可変長のサポートを追加するので、すぐにそれを使用できることを願っています。
長さの降順でシーケンスをソートする必要があります。その後、pack_sequence
、RNNを実行してからunpack_sequence
。