Python 使用LSTM教程代码预测句子中的下一个单词?

Python 使用LSTM教程代码预测句子中的下一个单词?,python,tensorflow,lstm,word2vec,word-embedding,Python,Tensorflow,Lstm,Word2vec,Word Embedding,我一直在努力理解示例代码 你可以在 (使用tensorflow 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.

我一直在努力理解示例代码 你可以在

(使用tensorflow 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单词嵌入(例如,使用gensim的
KeyedVectors.load_word2vec_format()
),在加载每个句子时将输入语料库中的每个单词转换为该表示,然后LSTM将吐出一个相同维度的向量,我们会尝试找到最相似的单词(例如,使用gensim的
similor\u by_vector(y,topn=1)

使用softmax是否将我们从相对缓慢的
类似的\u by_向量(y,topn=1)
呼叫中拯救出来


顺便说一句,我的问题中先前存在的word2vec部分是类似的。然而,目前的答案并不是我想要的。我所希望的是一个简单的英语解释,它为我打开了灯,填补了我理解上的任何空白。   这是另一个类似的问题

更新:和是类似的问题。但是,这两种方法都没有显示代码来实际提取句子的前几个单词,并打印出对下一个单词的预测。我试着粘贴第二个问题的代码和(github分支附带的)的代码,但无法在没有错误的情况下运行这两个问题。我想它们可能是TensorFlow的早期版本

另一个更新:又一个问题问了基本相同的问题: 它链接到 (而且,这里的答案也不是我想要的)

如果仍然不清楚,我试图编写一个名为
getNextWord(model,sentencePrefix)
的高级函数,其中
model
是我从磁盘加载的先前构建的LSTM,
sentencePrefix
是一个字符串,例如“openthew”,它可能返回“pod”。然后我可能会用“打开吊舱”来称呼它,它会返回“海湾”,以此类推

示例(带有字符RNN,并使用mxnet)是本节末尾附近显示的
sample()
函数
您可以在培训期间调用
sample()
,但也可以在培训结束后调用它,并且可以使用您想要的任何句子。

有很多问题,我将尝试澄清其中的一些问题

给定句子的前几个单词,如何使用生成的模型实际生成下一个单词的建议

这里的关键是,下一代单词实际上是词汇表中的单词分类。所以你需要一个分类器,这就是为什么在输出中有一个softmax

其原理是,在每个时间步,模型将根据最后一个单词的嵌入和前一个单词的内存输出下一个单词
tf.contrib.rnn.static\u rnn
自动将输入合并到内存中,但我们需要提供最后一个单词的嵌入并对下一个单词进行分类

我们可以使用预先训练好的word2vec模型,只需使用预先训练好的模型初始化
嵌入
矩阵即可。我认为为了简单起见,教程使用了随机矩阵。内存大小与嵌入大小无关,您可以使用更大的内存大小来保留更多信息

这些教程是高级的。如果您想深入了解详细信息,我建议您查看纯python/numpy的源代码。

Main Question 加载词 加载自定义数据,而不是使用测试集:

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\u数据
应包含单词id(打印出映射的
word\u-to\u-id
)。例如,它应该如下所示:[1,52,562,246]

显示预测 我们需要在调用
sess.run时返回FC层(
logits
)的输出

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\u word\u id']
将有一个带有顶部单词id的整数数组。在
word\u to\u 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(输入)可以是任何大小,只要适当调整权重矩阵

我如何/可以引入预先培训过的word2vec模型,而不是未初始化的模型

我不知道,对不起

我最大的问题是h
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
self.logits = logits
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)
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')
eval_config = get_config()
eval_config.num_steps = 1
eval_config.batch_size = 1
model_input = PTBInput(eval_config, test_data)
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
# 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
self.probas = tf.nn.softmax(logits, name='probas')
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
reader = tf.train.NewCheckpointReader(CKPT_FILE)
reader.get_variable_to_shape_map()