2016-11-05 1 views
2

바닐라 문자 레벨 RNN을 작성하고 일부 데이터에 대해 교육했습니다. 모든 것이 잘 될 때까지 잘 작동했습니다.Tensorflow 텍스트 생성 중 RNN의 일괄 처리 크기 변경

하지만 지금은 모델을 사용하여 텍스트를 생성하고 싶습니다. 문제는이 텍스트 생성 단계에서 batch_size이 1이고 num_steps 일괄 처리가 다르다는 것입니다.

이것은 여러 가지 오류로 이어지고 일부 해시 픽스를 시도했지만 작동하지 않습니다. 이 문제를 처리하는 일반적인 방법은 무엇입니까?

편집 : 더 구체적으로 입력 한 자리 표시 자의 모양은 [없음, num_steps]이지만, [없음, 숨겨진 크기]의 모양을 허용하지 않는 초기 상태로 문제가 있습니다.

답변

4

이 동일한 문제를 처리했습니다. 처리해야 할 두 가지 문제가 있습니다. 첫 번째는 일괄 처리 크기와 단계 크기를 1로 조정하는 것입니다. 입력 시퀀스의 배치 및 길이 치수를 none으로 설정하면 쉽게 수행 할 수 있습니다. 즉 [없음, 없음, 128], 128은 128 자의 ASCII 문자를 나타냅니다 (문자의 하위 집합 만 필요하기 때문에 더 적은 문자를 사용할 수도 있음).

초기 상태를 처리하는 것이 가장 많이 사용됩니다. 이것은 session.run() 호출 사이에 저장해야하기 때문입니다. 귀하의 num_steps가 하나이므로 각 단계의 시작 부분에서 0으로 초기화됩니다. 내가 권장하는 것은 초기 상태가 자리 표시 자로 전달되고 session.run()에서 반환되도록 허용하는 것입니다. 이렇게하면 모델 사용자는 배치간에 현재 상태를 계속할 수 있습니다. 이를 수행하는 가장 쉬운 방법은 state_is_tupel이 사용하는 모든 RNN에 대해 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에서 작동하는 다음 두 가지 기능이 사용됩니다.

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 그래프에서 2 분기 정의와 비슷하지만별로 좋지 않은 것처럼 보입니다. 그러나 RNN Cell의 init_state를 전달하지 않으려는 경우 이는 방법입니다.