2016-11-05 10 views
2

バニラキャラクターレベルのRNNを構築し、それをいくつかのデータで訓練しました。そこまですべてがうまくいった。Tensorflowテキスト生成中にRNNのバッチサイズを変更する

しかし、私はこのモデルを使ってテキストを生成したいと思います。問題は、このテキスト生成フェーズでは、のbatch_sizeが1であり、のnum_stepsのバッチも異なることです。

これはいくつかのエラーにつながり、いくつかのハッキーな修正を試みましたが、動作していません。これに対処する通常の方法は何ですか?

編集:入力したプレースホルダーの形状が[None、num_steps]ですが、[None、hidden_​​size]という形を受け入れない初期状態が問題です。

答えて

4

私はこの同じ問題を処理しました。あなたが対処する必要がある2つの問題があります。最初は、バッチサイズとステップサイズを1に調整しています。入力シーケンスのバッチと長さのディメンションをnoneに設定すると、簡単に行うことができます。つまり、128文字は128文字のASCII文字を表します(ただし、おそらく文字のサブセットのみが必要なため、おそらく文字数は少なくて済むかもしれません)。

最初の状態を扱うのが最もトリッキーです。これは、session.run()の呼び出しの間に保存する必要があるためです。あなたのnum_stepsは1であるため、各ステップの初めに0に初期化されます。私がお勧めするのは、初期状態をプレースホルダとして渡し、session.run()から返すことです。この方法で、モデルのユーザーはバッチ間で現在の状態を継続できます。これを行う最も簡単な方法は、使用しているすべてのRNNに対してstate_is_tupelがFalseに設定されていることを確認することです。そして、ダイナミックRNN関数から最終状態のテンソルを取得するだけです。

個人的にはstate_is_tupelをFalseに設定するのは嫌いです。私は自分のコードを書いて状態タプルを平坦化しました。次のコードは、サウンドを生成する私のプロジェクトからです。

 batch_size = tf.shape(self.input_sound)[0] 
     rnn = tf.nn.rnn_cell.MultiRNNCell([tf.nn.rnn_cell.LSTMCell(self.hidden_size) for _ in range(self.n_hidden)]) 
     zero_state = pack_state_tupel(rnn.zero_state(batch_size, tf.float32)) 
     self.input_state = tf.placeholder_with_default(zero_state, None) 
     state = unpack_state_tupel(self.input_state, rnn.state_size) 

     rnn_input_seq = tf.cond(self.is_training, lambda: self.input_sound[:, :-1], lambda: self.input_sound) 
     output, final_state = tf.nn.dynamic_rnn(rnn, rnn_input_seq, initial_state = state) 

     with tf.variable_scope('output_layer'): 
      output = tf.reshape(output, (-1, self.hidden_size)) 
      W = tf.get_variable('W', (self.hidden_size, self.sample_length)) 
      b = tf.get_variable('b', (self.sample_length,)) 
      output = tf.matmul(output, W) + b 
      output = tf.reshape(output, (batch_size, -1, self.sample_length)) 


     self.output_state = pack_state_tupel(final_state) 
     self.output_sound = output 

これは、このモデルでのみテストしましたが、どのタイプのRNNでも機能する次の2つの機能を使用します。私の生成機能で最後に

def pack_state_tupel(state_tupel): 
    if isinstance(state_tupel, tf.Tensor) or not hasattr(state_tupel, '__iter__'): 
     return state_tupel 
    else: 
     return tf.concat(1, [pack_state_tupel(item) for item in state_tupel]) 

def unpack_state_tupel(state_tensor, sizes): 
    def _unpack_state_tupel(state_tensor_, sizes_, offset_): 
     if isinstance(sizes_, tf.Tensor) or not hasattr(sizes_, '__iter__'): 
      return tf.reshape(state_tensor_[:, offset_ : offset_ + sizes_], (-1, sizes_)), offset_ + sizes_ 
     else: 
      result = [] 
      for size in sizes_: 
       s, offset_ = _unpack_state_tupel(state_tensor_, size, offset_) 
       result.append(s) 
      if isinstance(sizes_, tf.nn.rnn_cell.LSTMStateTuple): 
       return tf.nn.rnn_cell.LSTMStateTuple(*result), offset_ 
      else: 
       return tuple(result), offset_ 
    return _unpack_state_tupel(state_tensor, sizes, 0)[0] 

私は隠された状態sを管理する方法を参照してください。

def generate(self, seed, steps): 
    def _step(x, s = None): 
     feed_dict = {self.input_sound: np.reshape(x, (1, -1, self.sample_length))} 
     if s is not None: 
      feed_dict[self.input_state] = s 
     return self.session.run([self.output_sound, self.output_state], feed_dict) 

    seed_pad = self.sample_length - len(seed) % self.sample_length 
    if seed_pad: seed = np.pad(seed, (seed_pad, 0), 'constant') 

    y, s = _step(seed) 
    y = y[:, -1:] 

    result = [seed, y.flatten()] 
    for _ in range(steps): 
     y, s = _step(y, s) 
     result.append(y.flatten()) 

    return np.concatenate(result) 
0

tfの再利用はどうですか?

class Model(): 
    def __init__(self,batch_size,reuse) 
      self.batch_size = batch_size 
      self.reuse = reuse 
      self.input_x = tf.placeholder(.....) 
      self.input_y = tf.placeholder(.....) 
    def inference(self) 
      with tf.variable_scope('xxx',reuse=self.reuse) 
       ... 
       cell = tf.contrib.rnn.LSTMCell(xxx,reuse=self.reuse) 
       init_state = cell.zero_state(self.batch_size, dtype=tf.float32) 
       ... 
    def train_op(self): 
     .... 

if __name__ == '__main__': 
     train_model = model(batch=128,reuse=False) 
     test_model = model(batch=1,reuse=True) 
     with tf.Session() as sess: 
      sess.run(train_model.train_op,feed_dict={...}) 
      sess.run(test_model.prediction,feed_dict={...}) 

当然、tfグラフのdefine 2 branchのように見えますが、あまり良くないとは限りません。しかし、RNN Cellのinit_stateを渡したくなければ、それは方法です。

関連する問題