Подтвердить что ты не робот

TensorFlow с использованием LSTM для генерации текста

Я хотел бы использовать shadoworflow для генерации текста и модифицировал учебник 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, и это просто 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))
4b9b3361

Ответ 1

Я работал над одной и той же целью и просто получил ее на работу. Здесь у вас много прав, но я думаю, вы пропустили несколько шагов.

Во-первых, для генерации текста вам нужно создать другую версию модели, которая представляет только один временной интервал. Причина в том, что нам нужно пробовать каждый выход y, прежде чем мы сможем подать его на следующий шаг модели. Я сделал это, создав новую конфигурацию, которая устанавливает num_steps и batch_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)

Второе отличие состоит в том, что я получаю таблицу поиска от идентификаторов до строк слов (мне пришлось написать эту функцию, см. код ниже).

    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_probs и final_state. И мы даем ему вклад и состояние. На первой итерации вход <eos>, а состояние - 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")

И что модель, которую вы будете загружать с диска позже при создании текста.

Появилась еще одна проблема: я обнаружил, что иногда распределение вероятности, созданное функцией softmax Tensorflow, не суммировалось точно в 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