【问题标题】:TensorFlow using LSTMs for generating textTensorFlow 使用 LSTM 生成文本
【发布时间】:2016-08-05 05:30:00
【问题描述】:

我想用tensorflow生成文本,一直在修改LSTM教程(https://www.tensorflow.org/versions/master/tutorials/recurrent/index.html#recurrent-neural-networks)的代码来做这个,但是我最初的解决方案似乎产生了废话,即使经过很长时间的训练,也没有改善.我不明白为什么。这个想法是从零矩阵开始,然后一次生成一个单词。

这是代码,我在其中添加了以下两个函数 https://tensorflow.googlesource.com/tensorflow/+/master/tensorflow/models/rnn/ptb/ptb_word_lm.py

生成器如下所示

def generate_text(session,m,eval_op):

    state = m.initial_state.eval()

    x = np.zeros((m.batch_size,m.num_steps), dtype=np.int32)

    output = str()
    for i in xrange(m.batch_size):
        for step in xrange(m.num_steps):
            try:
                # Run the batch 
                # targets have to bee set but m is the validation model, thus it should not train the neural network
                cost, state, _, probabilities = session.run([m.cost, m.final_state, eval_op, m.probabilities],
                                                            {m.input_data: x, m.targets: x, m.initial_state: state})

                # Sample a word-id and add it to the matrix and output
                word_id = sample(probabilities[0,:])
                output = output + " " + reader.word_from_id(word_id)
                x[i][step] = word_id

            except ValueError as e:
                print("ValueError")

    print(output)

我已将变量“概率”添加到 ptb_model 中,它只是 logits 上的 softmax。

self._probabilities = tf.nn.softmax(logits)

以及采样:

def sample(a, temperature=1.0):
    # helper function to sample an index from a probability array
    a = np.log(a) / temperature
    a = np.exp(a) / np.sum(np.exp(a))
    return np.argmax(np.random.multinomial(1, a, 1))

【问题讨论】:

    标签: tensorflow lstm


    【解决方案1】:

    我一直在朝着完全相同的目标努力,并且刚刚成功。您在此处进行了许多正确的修改,但我认为您遗漏了几个步骤。

    首先,为了生成文本,您需要创建仅代表单个时间步长的模型的不同版本。原因是我们需要先对每个输出 y 进行采样,然后才能将其输入模型的下一步。为此,我创建了一个新配置,将 num_stepsbatch_size 都设置为 1。

    class SmallGenConfig(object):
      """Small config. for generation"""
      init_scale = 0.1
      learning_rate = 1.0
      max_grad_norm = 5
      num_layers = 2
      num_steps = 1 # this is the main difference
      hidden_size = 200
      max_epoch = 4
      max_max_epoch = 13
      keep_prob = 1.0
      lr_decay = 0.5
      batch_size = 1
      vocab_size = 10000
    

    我还通过以下几行向模型添加了概率:

    self._output_probs = tf.nn.softmax(logits)
    

    @property
    def output_probs(self):
      return self._output_probs
    

    然后,我的generate_text() 函数有一些不同之处。第一个是我使用tf.train.Saver() 对象从磁盘加载保存的模型参数。请注意,我们在使用上面的新配置实例化 PTBModel 之后执行此操作。

    def generate_text(train_path, model_path, num_sentences):
      gen_config = SmallGenConfig()
    
      with tf.Graph().as_default(), tf.Session() as session:
        initializer = tf.random_uniform_initializer(-gen_config.init_scale,
                                                    gen_config.init_scale)    
        with tf.variable_scope("model", reuse=None, initializer=initializer):
          m = PTBModel(is_training=False, config=gen_config)
    
        # Restore variables from disk.
        saver = tf.train.Saver() 
        saver.restore(session, model_path)
        print("Model restored from file " + model_path)
    

    第二个不同是我得到了从 ids 到单词字符串的查找表(我必须写这个函数,见下面的代码)。

        words = reader.get_vocab(train_path)
    

    我以与您相同的方式设置初始状态,但随后以不同的方式设置初始令牌。我想使用“句子结尾”标记,以便我用正确类型的单词开始我的句子。我查看了单词索引,发现<eos> 恰好有索引 2(确定性),所以我只是将其硬编码。最后,我将它包装在一个 1x1 Numpy 矩阵中,以便它是模型输入的正确类型.

        state = m.initial_state.eval()
        x = 2 # the id for '<eos>' from the training set
        input = np.matrix([[x]])  # a 2D numpy matrix 
    

    最后,这是我们生成句子的部分。请注意,我们告诉session.run() 计算output_probsfinal_state。我们给它输入和状态。在第一次迭代中,输入为&lt;eos&gt;,状态为initial_state,但在随后的迭代中,我们将最后一次采样输出作为输入,并将状态从最后一次迭代中传递出去。另请注意,我们使用words 列表从输出索引中查找单词字符串。

        text = ""
        count = 0
        while count < num_sentences:
          output_probs, state = session.run([m.output_probs, m.final_state],
                                       {m.input_data: input,
                                        m.initial_state: state})
          x = sample(output_probs[0], 0.9)
          if words[x]=="<eos>":
            text += ".\n\n"
            count += 1
          else:
            text += " " + words[x]
          # now feed this new word as input into the next iteration
          input = np.matrix([[x]]) 
    

    那么我们要做的就是打印出我们积累的文本。

        print(text)
      return
    

    generate_text() 函数就是这样。

    最后,让我给你看一下 get_vocab() 的函数定义,我把它放在 reader.py 中。

    def get_vocab(filename):
      data = _read_words(filename)
    
      counter = collections.Counter(data)
      count_pairs = sorted(counter.items(), key=lambda x: (-x[1], x[0]))
    
      words, _ = list(zip(*count_pairs))
    
      return words
    

    你需要做的最后一件事是能够在训练后保存模型,看起来像

    save_path = saver.save(session, "/tmp/model.ckpt")
    

    这就是您稍后在生成文本时将从磁盘加载的模型。

    还有一个问题:我发现有时 Tensorflow softmax 函数产生的概率分布的总和并不完全等于 1.0。当总和大于 1.0 时,np.random.multinomial() 会引发错误。所以我只好写自己的采样函数,看起来像这样

    def sample(a, temperature=1.0):
      a = np.log(a) / temperature
      a = np.exp(a) / np.sum(np.exp(a))
      r = random.random() # range: [0,1)
      total = 0.0
      for i in range(len(a)):
        total += a[i]
        if total>r:
          return i
      return len(a)-1 
    

    当你把所有这些放在一起时,这个小模型能够为我生成一些很酷的句子。祝你好运。

    【讨论】:

      【解决方案2】:

      我用你的代码,好像不对。所以我稍微修改了一下,它似乎工作。 这是我的代码,我不确定它是否正确:

      def generate_text(session,m,eval_op, word_list):
      output = []
      for i in xrange(20):
          state = m.initial_state.eval()
          x = np.zeros((1,1), dtype=np.int32)
          y = np.zeros((1,1), dtype=np.int32)
          output_str = ""
          for step in xrange(100):
              if True:
                  # Run the batch 
                  # targets have to bee set but m is the validation model, thus it should not train the neural network
                  cost, state, _, probabilities = session.run([m.cost, m.final_state, eval_op, m.probabilities],
                                                              {m.input_data: x, m.targets: y, m.initial_state: state})
                  # Sample a word-id and add it to the matrix and output
                  word_id = sample(probabilities[0,:])
                  if (word_id<0) or (word_id > len(word_list)):
                      continue
                  #print(word_id)
                  output_str = output_str + " " + word_list[word_id]
                  x[0][0] = word_id
          print(output_str)
          output.append(output_str)
      return output
      

      【讨论】:

        猜你喜欢
        • 2018-06-13
        • 2018-08-04
        • 1970-01-01
        • 1970-01-01
        • 2018-04-02
        • 2019-06-14
        • 2017-10-22
        • 2016-03-23
        • 1970-01-01
        相关资源
        最近更新 更多