Использовать учебный код LSTM, чтобы предсказать следующее слово в предложении?

Я пытался понять пример кода с помощью https://www.tensorflow.org/tutorials/recurrent который вы можете найти на https://github.com/tensorflow/models/blob/master/tutorials/rnn/ptb/ptb_word_lm.py.

(Используя тензорный поток 1.3.0.)

Я резюмировал (как мне кажется) ключевые части моего вопроса ниже:

 size = 200
 vocab_size = 10000
 layers = 2
 # input_.input_data is a 2D tensor [batch_size, num_steps] of
 #    word ids, from 1 to 10000

 cell = tf.contrib.rnn.MultiRNNCell(
    [tf.contrib.rnn.BasicLSTMCell(size) for _ in range(2)]
    )

 embedding = tf.get_variable(
      "embedding", [vocab_size, size], dtype=tf.float32)
 inputs = tf.nn.embedding_lookup(embedding, input_.input_data)

inputs = tf.unstack(inputs, num=num_steps, axis=1)
outputs, state = tf.contrib.rnn.static_rnn(
    cell, inputs, initial_state=self._initial_state)

output = tf.reshape(tf.stack(axis=1, values=outputs), [-1, size])
softmax_w = tf.get_variable(
    "softmax_w", [size, vocab_size], dtype=data_type())
softmax_b = tf.get_variable("softmax_b", [vocab_size], dtype=data_type())
logits = tf.matmul(output, softmax_w) + softmax_b

# Then calculate loss, do gradient descent, etc.

Мой самый большой вопрос: как мне использовать созданную модель для фактического создания предложения следующего слова с учетом первых нескольких слов предложения? Конкретно, я предполагаю, что поток такой, но я не могу понять, каким будет код для прокомментированных строк:

prefix = ["What", "is", "your"]
state = #Zeroes
# Call static_rnn(cell) once for each word in prefix to initialize state
# Use final output to set a string, next_word
print(next_word)

Мои подвопросы:

  • Зачем использовать случайное (неинициализированное, неподготовленное) встраивание слов?
  • Зачем использовать softmax?
  • Должен ли скрытый слой соответствовать размеру ввода (т.е. размеру вложений word2vec)
  • Как / Могу ли я использовать предварительно обученную модель word2vec вместо неинициализированной?

(Я задаю их все как один вопрос, поскольку подозреваю, что все они связаны между собой и связаны с некоторым пробелом в моем понимании.)

Я ожидал увидеть здесь загрузку существующего набора вложений слов word2vec (например, с использованием KeyedVectors.load_word2vec_format() от gensim), преобразование каждого слова во входном корпусе в это представление при загрузке в каждом предложении, а затем LSTM будет выдавать вектор того же измерения, и мы попытаемся найти наиболее похожее слово (например, используя gensim's similar_by_vector(y, topn=1)).

Спасает ли нас использование softmax от относительно медленного similar_by_vector(y, topn=1) вызова?


Кстати, для уже существующей части word2vec моего вопроса Использование предварительно обученного word2vec с LSTM для генерации слов аналогично. Однако ответы там в настоящее время не то, что я ищу. Я надеюсь на простое объяснение на английском языке, которое включит для меня свет и восполнит любой пробел в моем понимании. Использовать предварительно обученный word2vec в языковой модели lstm? - еще один аналогичный вопрос.

ОБНОВЛЕНИЕ: Прогнозирование следующего слова с использованием примера тензорного потока языковой модели и Предсказание следующего слова с использованием примера тензорного потока модели LSTM ptb - это похожие вопросы. Однако ни один из них не показывает, как код фактически берет первые несколько слов предложения и распечатывает предсказание следующего слова. Я пробовал вставить код из второго вопроса и из https://stackoverflow.com/a/39282697/841830 ( который поставляется с веткой github), но не может работать без ошибок. Я думаю, они могут быть для более ранней версии TensorFlow?

ДРУГОЕ ОБНОВЛЕНИЕ: Еще один вопрос, в основном задающий то же самое: Прогнозирование следующего слова модели LSTM из примера Tensorflow Он ссылается на Предсказание следующего слова с использованием примера тензорного потока языковой модели (и, опять же, ответы там не совсем то, что Я ищу).

Если все еще не ясно, что я пытаюсь написать высокоуровневую функцию с именем getNextWord(model, sentencePrefix), где model - это ранее созданный LSTM, который я загрузил с диска, а sentencePrefix - это строка, например «Открыть» , и он может вернуть "pod". Затем я мог бы вызвать его с помощью «Откройте контейнер», и он вернет «залив» и так далее.

Примером (с символом RNN и использованием mxnet) является функция sample(), показанная в конце https://github.com/zackchase/mxnet-the-straight-dope/blob/master/chapter05_recurrent-нейронныесети/simple-rnn.ipynb Вы можете вызвать sample() во время обучения, но вы также можете вызвать его после обучения и с любым предложением.


person Darren Cook    schedule 08.09.2017    source источник
comment
К сожалению, на тот момент, когда мне нужно было назначить награду, ни один из ответов у меня не работал; поэтому я пока оставляю его без галочки. Я назначил награду за ответ, который, казалось, наиболее точно отвечал на мой ключевой вопрос.   -  person Darren Cook    schedule 18.09.2017
comment
Ответы не сработали для вас, потому что нет общего ответа для всех реализаций языковой модели, каждая реализация немного отличается. Я думаю, что в этом вопросе следует выбрать уровень, который нужно задать: интуитивное понимание или конкретная реализация кода. Не то чтобы я против этого вопроса, я проголосовал за него. На самом деле, если у вас есть понимание модели и свободное владение Python, реализация будет несложной. Однако это требует времени, поэтому, если вы разместите здесь свое решение для этой конкретной языковой модели после ее реализации, оно будет очень полезно для других.   -  person THN    schedule 19.09.2017
comment
@THN Это было немного более объективно. Под словом «не сработало» я имел в виду, что пытался реализовать getNextWord(model, sentencePrefix) из каждого предложенного ответа, но каждый из них либо заканчивался выдачей исключений, либо имел пробел в объяснении, которое действительно было сутью вопроса. Если / когда у меня это сработает, я отвечу сам. (Кстати, спасибо, что первым ответил - это действительно помогло мне прояснить мой вопрос, что привело к поиску других связанных вопросов.)   -  person Darren Cook    schedule 19.09.2017
comment
Вам удалось заставить его работать? Я занимаюсь той же проблемой!   -  person Caterpillaraoz    schedule 28.09.2017
comment
@Caterpillaraoz Нет, еще нет. Так что, если вы справитесь с этим, пожалуйста, опубликуйте код!   -  person Darren Cook    schedule 28.09.2017
comment
@DarrenCook Я был очень удивлен, что в учебник этого не было, это всего лишь следующий логический шаг. Я открыл другой вопрос, будем надеяться, что меня не опекут как дубликат !. Мне нужно 1. сохранить сеть на диск 2. вызывать ее всякий раз, когда я хочу получить следующие 10 наиболее вероятных слов. Конечно, я опубликую код, и если на мой вопрос не будет ответа, я напишу ребятам по тензорному потоку за помощью.   -  person Caterpillaraoz    schedule 28.09.2017
comment
Вы когда-нибудь догадывались об этом? Я с той же проблемой!   -  person pr338    schedule 12.02.2019


Ответы (4)


Главный вопрос

Загрузка слов

Загрузите пользовательские данные вместо использования набора тестов:

reader.py@ptb_raw_data

test_path = os.path.join(data_path, "ptb.test.txt")
test_data = _file_to_word_ids(test_path, word_to_id)  # change this line

test_data должен содержать идентификаторы слов (распечатайте word_to_id для сопоставления). Например, это должно выглядеть так: [1, 52, 562, 246] ...

Отображение прогнозов

Нам нужно вернуть вывод уровня FC (logits) в вызове sess.run

ptb_word_lm.py@PTBModel.__init__

    logits = tf.reshape(logits, [self.batch_size, self.num_steps, vocab_size])
    self.top_word_id = tf.argmax(logits, axis=2)  # add this line

ptb_word_lm.py@run_epoch

  fetches = {
      "cost": model.cost,
      "final_state": model.final_state,
      "top_word_id": model.top_word_id # add this line
  }

Позже в функции vals['top_word_id'] будет массив целых чисел с идентификатором верхнего слова. Посмотрите это в word_to_id, чтобы определить предсказанное слово. Я проделал это некоторое время назад с маленькой моделью, и максимальная точность 1 была довольно низкой (20-30% iirc), даже несмотря на то, что недоумение было тем, что было предсказано в заголовке.

Подвопросы

Зачем использовать случайное (неинициализированное, неподготовленное) встраивание слов?

Вы должны спросить авторов, но, на мой взгляд, обучение встраиванию делает этот учебник более самостоятельным: вместо того, чтобы рассматривать вложение как черный ящик, он показывает, как оно работает.

Зачем использовать softmax?

Окончательный прогноз не определяется косинусным сходством с выводом скрытого слоя. После LSTM есть уровень FC, который преобразует встроенное состояние в быстрое кодирование последнего слова.

Вот набросок операций и измерений в нейронной сети:

word -> one hot code (1 x vocab_size) -> embedding (1 x hidden_size) -> LSTM -> FC layer (1 x vocab_size) -> softmax (1 x vocab_size)

Должен ли скрытый слой соответствовать размеру ввода (т.е. размеру вложений word2vec)

Технически нет. Если вы посмотрите на уравнения LSTM, вы заметите, что x (вход) может иметь любой размер, если матрица весов настроена соответствующим образом.

Уравнения LSTM

Как / Могу ли я использовать предварительно обученную модель word2vec вместо неинициализированной?

Не знаю, извини.

person c2huc2hu    schedule 11.09.2017
comment
Спасибо. Я думаю, что это может быть правильным образом, но он все еще не отвечает на мой ключевой вопрос: как только у меня будет построена модель, я хочу загрузить ее с диска, дать ей строку (первые несколько слов в предложении), и попросите его предложить следующее слово в предложении. Я хочу сделать это несколько раз, каждый раз с разными строками префикса. Т.е. Пытаюсь написать функцию с подписью: getNextWord(model, sentencePrefix) - person Darren Cook; 13.09.2017
comment
Я выполнил ваши инструкции, но когда я это сделаю print(vals['top_word_id']), я вижу [[1 2] [1 1] [0 2] ... [1 1]] Т.е. ни одного числа я не могу передать word_to_id[]. (Я также не видел, как я могу указать префикс предложения при таком подходе.) - person Darren Cook; 13.09.2017
comment
Когда вы печатаете vals['top_word_id'], используете ли вы test_config или eval_config? (Отметьте переменную num_steps) Вы должны использовать последнюю, потому что вы оцениваете модель. Вы можете указать префикс предложения, просмотрев слова в sentencePrefix в word_to_id. По общему признанию, этот подход - не самый чистый способ написания кода. - person c2huc2hu; 15.09.2017

Мой самый большой вопрос: как использовать созданную модель, чтобы на самом деле создать предложение следующего слова, учитывая первые несколько слов предложения?

Т.е. Пытаюсь написать функцию с подписью: getNextWord (модель, предложениеPrefix)

Прежде чем я объясню свой ответ, сначала сделайте замечание о вашем предложении # Call static_rnn(cell) once for each word in prefix to initialize state: имейте в виду, что static_rnn не возвращает значение, подобное массиву numpy, а возвращает тензор. Вы можете оценить тензор до значения, когда он запускается (1) в сеансе (сеанс сохраняет состояние вашего вычислительного графика, включая значения параметров вашей модели) и (2) с входными данными, которые необходимы для расчета значение тензора. Входные данные могут быть предоставлены с помощью считывателей ввода (подход, описанный в руководстве) или с помощью заполнителей (что я буду использовать ниже).

Теперь следует собственно ответ: модель в учебнике была разработана для чтения входных данных из файла. Ответ @ user3080953 уже показал, как работать с вашим собственным текстовым файлом, но, насколько я понимаю, вам нужно больше контроля над тем, как данные передаются в модель. Для этого вам нужно будет определить свои собственные заполнители и передать данные в эти заполнители при вызове session.run().

В приведенном ниже коде я разделил PTBModel на подклассы и сделал его ответственным за явную подачу данных в модель. Я представил специальный PTBInteractiveInput, интерфейс которого похож на PTBInput, поэтому вы можете повторно использовать функциональность PTBModel. Для обучения модели вам еще понадобится PTBModel.

class PTBInteractiveInput(object):
  def __init__(self, config):
    self.batch_size = 1
    self.num_steps = config.num_steps
    self.input_data = tf.placeholder(dtype=tf.int32, shape=[self.batch_size, self.num_steps])
    self.sequence_len = tf.placeholder(dtype=tf.int32, shape=[])
    self.targets = tf.placeholder(dtype=tf.int32, shape=[self.batch_size, self.num_steps])

class InteractivePTBModel(PTBModel):

  def __init__(self, config):
    input = PTBInteractiveInput(config)
    PTBModel.__init__(self, is_training=False, config=config, input_=input)
    output = self.logits[:, self._input.sequence_len - 1, :]
    self.top_word_id = tf.argmax(output, axis=2)

  def get_next(self, session, prefix):
    prefix_array, sequence_len = self._preprocess(prefix)
    feeds = {
      self._input.sequence_len: sequence_len,
      self._input.input_data: prefix_array,
    }
    fetches = [self.top_word_id]
    result = session.run(fetches, feeds)
    self._postprocess(result)

  def _preprocess(self, prefix):
    num_steps = self._input.num_steps
    seq_len = len(prefix)
    if seq_len > num_steps:
      raise ValueError("Prefix to large for model.")
    prefix_ids = self._prefix_to_ids(prefix)
    num_items_to_pad = num_steps - seq_len
    prefix_ids.extend([0] * num_items_to_pad)
    prefix_array = np.array([prefix_ids], dtype=np.float32)
    return prefix_array, seq_len

  def _prefix_to_ids(self, prefix):
    # should convert your prefix to a list of ids
    pass

  def _postprocess(self, result):
    # convert ids back to strings
    pass

В __init__ функции PTBModel вам нужно добавить эту строку:

self.logits = logits

Зачем использовать случайное (неинициализированное, неподготовленное) встраивание слов?

Во-первых, обратите внимание, что, хотя вначале вложения случайны, они будут обучаться вместе с остальной частью сети. Вложения, которые вы получаете после обучения, будут иметь те же свойства, что и вложения, которые вы получаете с моделями word2vec, например, способность отвечать на вопросы аналогии с векторными операциями (король - мужчина + женщина = королева и т. Д.). обучающих данных, таких как языковое моделирование (которое не требует аннотированных обучающих данных) или нейронный машинный перевод, чаще всего обучают вложениям с нуля.

Зачем использовать softmax?

Softmax - это функция, которая нормализует вектор оценок сходства (логитов) к распределению вероятностей. Распределение вероятностей необходимо для обучения модели с кросс-энтропийными потерями и возможности выборки из модели. Обратите внимание: если вас интересуют только наиболее вероятные слова обученной модели, softmax вам не нужен, и вы можете использовать логиты напрямую.

Должен ли скрытый слой соответствовать размеру ввода (т.е. размеру вложений word2vec)

Нет, в принципе это может быть любое значение. Однако использование скрытого состояния с более низкой размерностью, чем ваше измерение встраивания, не имеет особого смысла.

Как / Могу ли я использовать предварительно обученную модель word2vec вместо неинициализированной?

Вот автономный пример инициализации вложения с заданным массивом numpy. Если вы хотите, чтобы встраивание оставалось фиксированным / постоянным во время обучения, установите trainable на False.

import tensorflow as tf
import numpy as np
vocab_size = 10000
size = 200
trainable=True
embedding_matrix = np.zeros([vocab_size, size]) # replace this with code to load your pretrained embedding
embedding = tf.get_variable("embedding",
                            initializer=tf.constant_initializer(embedding_matrix),
                            shape=[vocab_size, size],
                            dtype=tf.float32,
                            trainable=trainable)
person GeertH    schedule 14.09.2017
comment
Спасибо! Я вставил ваш код в середину ptb_word_lm.py. Если бы я хотел протестировать его, скажем, выводя предложение следующего слова для тестового префикса после каждой эпохи обучения, я должен создать один экземпляр InteractivePTBModel в верхней части основного (например, сразу после того, как у меня есть конфигурация), или создать он обновляется каждый раз в цикле (например, на github.com/tensorflow/models/blob/master/tutorials/rnn/ptb/) - person Darren Cook; 15.09.2017
comment
Я получаю RuntimeError: график завершен и не может быть изменен. (при моей первой попытке создать экземпляр внутри цикла). Очень длинное сообщение об ошибке, но я думаю, что оно вызвано self.input_data = tf.placeholder(dtype=tf.float32, shape=[self.batch_size, self.num_steps]) - person Darren Cook; 15.09.2017
comment
Каждый раз, когда вы инициализируете InteractivePTBModel новые операции, к вычислительному графу добавляются. Ошибка, которую вы получаете, вызвана тем фактом, что вы инициализируете график внутри managed_session, что не позволяет изменять график. Вы можете создать модель здесь , аналогично тому, как создаются модели проверки и тестирования. Надеюсь, это поможет. - person GeertH; 15.09.2017
comment
self.input_data и self.targets, похоже, хотят быть in32, а не float32. К сожалению, исправление этого привело меня только к следующей ошибке (если говорить о формах, которые должны быть одинакового ранга и срезанными срезами). Я все еще пытаюсь создать объект InteractivePTBModel, даже не вызывая для него get_next()! Ваш код работал на вас? - person Darren Cook; 15.09.2017
comment
Вы правы, конечно, заполнители должны быть int32. Я обновил свой ответ. С помощью правок также должна быть исправлена ​​ошибка равного ранга (что, я считаю, произошло потому, что self.self.sequence_len был определен как вектор, а не скаляр). У меня сейчас нет времени тестировать код. - person GeertH; 16.09.2017

Вопросов много, я бы постарался прояснить некоторые из них.

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

Ключевым моментом здесь является то, что следующее поколение слов на самом деле является классификацией слов в словаре. Итак, вам нужен классификатор, поэтому на выходе есть softmax.

Принцип заключается в том, что на каждом временном шаге модель будет выводить следующее слово на основе встраивания последнего слова и внутренней памяти предыдущих слов. tf.contrib.rnn.static_rnn автоматически объединяет ввод в память, но нам нужно обеспечить встраивание последнего слова и классифицировать следующее слово.

Мы можем использовать предварительно обученную модель word2vec, просто инициализируйте embedding матрицу с предварительно обученной. Я думаю, что в учебнике для простоты используется случайная матрица. Размер памяти не связан с размером встраивания, вы можете использовать больший размер памяти, чтобы сохранить больше информации.

Эти уроки являются высокоуровневыми. Если вы хотите глубоко разобраться в деталях, я бы посоветовал взглянуть на исходный код в виде простого python / numpy.

person THN    schedule 09.09.2017
comment
Спасибо. Я только что добавил к своему вопросу псевдокод: я надеюсь на ответ, который покажет мне настоящий код, так что я действительно могу распечатать ответ. - person Darren Cook; 09.09.2017
comment
Re: использование softmax, поскольку это классификация слов: при встраивании слов косинусное сходство используется для поиска ближайшего слова к нашему 300-мерному векторному вводу. Я не понимаю, почему вместо этого мы используем softmax. Это для скорости (и если да, то есть ли компромисс), чтобы дать более простое руководство (например, без зависимости от gensim), более качественные результаты, это единственный способ обучить LSTM или что-то еще? - person Darren Cook; 09.09.2017
comment
Классификация слов @DarrenCook - это прямой способ получить следующее слово. Конечно, есть и другие способы, например, ваше предложение о внедрении подобия, но нет никакой гарантии, что они будут работать лучше, так как я не вижу дополнительной информации. Не говоря уже о том, что было бы сложно вычислить градиент. Этот ответ дает только интуицию, я думаю, вы можете искать код в репозиториях языковых моделей. - person THN; 09.09.2017

Вы можете найти весь код в конце ответа.


Я полагаю, что на большинство ваших вопросов (почему Softmax, как использовать предварительно обученный слой встраивания и т. Д.) Были даны ответы. Однако, поскольку вы все еще ждали краткого кода для создания сгенерированного текста из семени, здесь я пытаюсь рассказать, как я в итоге сделал это сам.

Я изо всех сил пытался, начиная с официального руководства по Tensorflow, добраться до точки, где я мог легко генерировать слова из созданной модели. К счастью, после того, как я получил некоторые ответы практически на все ответы, которые вы упомянули в своем вопросе, я получил лучшее представление о проблеме (и решениях). Это может содержать ошибки, но, по крайней мере, он запускается и генерирует некоторый текст ...

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

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

Допустим, вы следовали текущему руководству, предоставленному tenorflow (v1.4 на момент написания), здесь , который сохранит модель после ее обучения.

Затем нам остается загрузить его с диска и написать функцию, которая принимает эту модель и некоторый начальный ввод и возвращает сгенерированный текст.


Сгенерировать текст из сохраненной модели

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

Первые необходимые шаги

FLAGS = tf.flags.FLAGS
FLAGS.model = "medium" # or whatever size you used

Теперь, что очень важно, мы создаем словари для сопоставления идентификаторов со словами и наоборот (так что нам не нужно читать список целых чисел ...).

word_to_id = reader._build_vocab('../data/ptb.train.txt') # here we load the word -> id dictionnary ()
id_to_word = dict(zip(word_to_id.values(), word_to_id.keys())) # and transform it into id -> word dictionnary
_, _, test_data, _ = reader.ptb_raw_data('../data')

Затем мы загружаем класс конфигурации, также устанавливая для num_steps и batch_size значение 1, поскольку мы хотим отбирать по одному слову за раз, в то время как LSTM будет обрабатывать также по одному слову за раз. Также создание экземпляра ввода на лету:

eval_config = get_config()
eval_config.num_steps = 1
eval_config.batch_size = 1
model_input = PTBInput(eval_config, test_data)

Строительный график

Чтобы загрузить сохраненную модель (сохраненную модулем Supervisor.saver в руководстве), нам нужно сначала перестроить график (легко с классом PTBModel), который должен использовать ту же конфигурацию как при обучении:

sess = tf.Session()
initializer = tf.random_uniform_initializer(-eval_config.init_scale, eval_config.init_scale)
# not sure but seems to need the same name for variable scope as when saved ....!!
with tf.variable_scope("Model", reuse=None, initializer=initializer):
    tf.global_variables_initializer()
    mtest = PTBModel(is_training=False, config=eval_config, input=model_input)

Восстановление сохраненных весов:

sess.run(tf.global_variables_initializer())
saver = tf.train.Saver()
saver.restore(sess, tf.train.latest_checkpoint('../Whatever_folder_you_saved_in')) # the path must point to the hierarchy where your 'checkpoint' file is

... Выборка слов из заданного семени:

Сначала нам нужно, чтобы модель содержала доступ к выходным данным логитов или, точнее, распределению вероятностей по всему словарю. Итак, в файле ptb_lstm.py добавьте строку:

# the line goes somewhere below the reshaping "logits = tf.reshape(logits, [self.batch_size, ..."
self.probas = tf.nn.softmax(logits, name="probas")

Затем мы можем разработать некоторую функцию выборки (здесь вы можете использовать все, что вам нравится, лучший подход - выборка с температурой, которая имеет тенденцию сглаживать или повышать резкость распределений), вот основной метод случайной выборки :

def sample_from_pmf(probas):
    t = np.cumsum(probas)
    s = np.sum(probas)
    return int(np.searchsorted(t, np.random.rand(1) * s))

И, наконец, функция, которая принимает начальное значение, вашу модель, словарь, который сопоставляет слово с идентификаторами, и наоборот, в качестве входных данных и выводит сгенерированную строку текстов:

def generate_text(session, model, word_to_index, index_to_word, 
                  seed='</s>', n_sentences=10):
    sentence_cnt = 0
    input_seeds_id = [word_to_index[w] for w in seed.split()]
    state = session.run(model.initial_state)

    # Initiate network with seeds up to the before last word:
    for x in input_seeds_id[:-1]:
        feed_dict = {model.initial_state: state,
                     model.input.input_data: [[x]]}
        state = session.run([model.final_state], feed_dict)

    text = seed
    # Generate a new sample from previous, starting at last word in seed
    input_id = [[input_seeds_id[-1]]]
    while sentence_cnt < n_sentences:
        feed_dict = {model.input.input_data: input_id,
                     model.initial_state: state}
        probas, state = session.run([model.probas, model.final_state],
                                 feed_dict=feed_dict)
        sampled_word = sample_from_pmf(probas[0])
        if sampled_word == word_to_index['</s>']:
            text += '.\n'
            sentence_cnt += 1
        else:
            text += ' ' + index_to_word[sampled_word]
        input_wordid = [[sampled_word]]

    return text

TL;DR

Не забудьте добавить строчку:

self.probas = tf.nn.softmax(logits, name='probas')

В файле ptb_lstm.py, в определении __init__ класса PTBModel, в любом месте после строки logits = tf.reshape(logits, [self.batch_size, self.num_steps, vocab_size]).

Весь скрипт, просто запустите его из того же каталога, где у вас есть reader.py, ptb_lstm.py:

import reader
import numpy as np
import tensorflow as tf
from ptb_lstm import PTBModel, get_config, PTBInput

FLAGS = tf.flags.FLAGS
FLAGS.model = "medium"

def sample_from_pmf(probas):
    t = np.cumsum(probas)
    s = np.sum(probas)
    return int(np.searchsorted(t, np.random.rand(1) * s))

def generate_text(session, model, word_to_index, index_to_word, 
                  seed='</s>', n_sentences=10):
    sentence_cnt = 0
    input_seeds_id = [word_to_index[w] for w in seed.split()]
    state = session.run(model.initial_state)

    # Initiate network with seeds up to the before last word:
    for x in input_seeds_id[:-1]:
        feed_dict = {model.initial_state: state,
                     model.input.input_data: [[x]]}
        state = session.run([model.final_state], feed_dict)

    text = seed
    # Generate a new sample from previous, starting at last word in seed
    input_id = [[input_seeds_id[-1]]]
    while sentence_cnt < n_sentences:
        feed_dict = {model.input.input_data: input_id,
                     model.initial_state: state}
        probas, state = sess.run([model.probas, model.final_state],
                                 feed_dict=feed_dict)
        sampled_word = sample_from_pmf(probas[0])
        if sampled_word == word_to_index['</s>']:
            text += '.\n'
            sentence_cnt += 1
        else:
            text += ' ' + index_to_word[sampled_word]
        input_wordid = [[sampled_word]]

    print(text)

if __name__ == '__main__':

    word_to_id = reader._build_vocab('../data/ptb.train.txt') # here we load the word -> id dictionnary ()
    id_to_word = dict(zip(word_to_id.values(), word_to_id.keys())) # and transform it into id -> word dictionnary
    _, _, test_data, _ = reader.ptb_raw_data('../data')

    eval_config = get_config()
    eval_config.batch_size = 1
    eval_config.num_steps = 1
    model_input = PTBInput(eval_config, test_data, name=None)

    sess = tf.Session()
    initializer = tf.random_uniform_initializer(-eval_config.init_scale,
                                            eval_config.init_scale)
    with tf.variable_scope("Model", reuse=None, initializer=initializer):
        tf.global_variables_initializer()
        mtest = PTBModel(is_training=False, config=eval_config, 
                         input_=model_input)

    sess.run(tf.global_variables_initializer())

    saver = tf.train.Saver()
    saver.restore(sess, tf.train.latest_checkpoint('../models'))

    while True:
        print(generate_text(sess, mtest, word_to_id, id_to_word, seed="this sentence is"))
        try:
            raw_input('press Enter to continue ...\n')
        except KeyboardInterrupt:
            print('\b\bQuiting now...')
            break

Обновлять

Что касается восстановления старых контрольных точек (для меня модель была сохранена 6 месяцев назад, я не уверен в том, что тогда использовалась точная версия TF) с недавним тензорным потоком (по крайней мере, 1.6), это может вызвать ошибку о том, что некоторые переменные не найдены (см. Комментарий). В этом случае вам следует обновить контрольные точки с помощью этот сценарий.

Также обратите внимание, что мне пришлось изменить это еще больше, так как я заметил, что функция saver.restore пыталась прочитать lstm_cell переменные, хотя мои переменные были преобразованы в basic_lstm_cell, что также привело к NotFound Error. Так что простое исправление, небольшое изменение в checkpoint_convert.py скрипте, строки 72-73, - это удалить basic_ в новых именах.

Удобный способ проверить имена переменных, содержащихся в ваших контрольных точках: (CKPT_FILE - суффикс, который стоит перед .index, .data0000-1000 и т. Д.):

reader = tf.train.NewCheckpointReader(CKPT_FILE)
reader.get_variable_to_shape_map()

Таким образом вы можете убедиться, что у вас действительно правильные имена (или плохие в старых версиях контрольных точек).

person H. Rev.    schedule 19.01.2018
comment
Большое спасибо, stackoverflow.com/users/5303618/h-rev. Код выглядит многообещающе, но я не могу заставить его работать. Я получаю следующую ошибку. Есть идеи, как это исправить? Файл test.py, строка 64, в ‹module› mtest = PTBModel (is_training = False, config = eval_config, input_ = model_input) ... ValueError: Variable Model / RNN / multi_rnn_cell / cell_0 / basic_lstm_cell / kernel не существует, или не был создан с помощью tf.get_variable (). Вы хотели установить reuse = tf.AUTO_REUSE в VarScope? - person Niklas Heidloff; 07.06.2018
comment
На момент написания это сработало, и теперь я действительно получаю ту же ошибку (с tensofrlow 1.6+). Проблема возникает, если вы сохранили модель с более ранней версией и восстановили с помощью более поздней. Изменилось соглашение об именах для параметров LSTM, например cell_0/basic_lstm_cell/weights стал cell_0/basic_lstm_cell/kernel. Вот почему вы не можете восстановить их, если попытаетесь восстановить старые контрольные точки с помощью недавнего TF (так плохо ...). Используйте этот скрипт, чтобы обновите свои контрольно-пропускные пункты. (См. Обновление в ответе) - person H. Rev.; 08.06.2018
comment
@NiklasHeidloff Удалось ли вам это решить? У меня такая же проблема. Я пытаюсь использовать контрольную точку сразу после ее сохранения. Так что, по крайней мере, в моем случае причина не может быть в разнице между версиями. - person FCA; 10.09.2019