Dar*_*ook 21 python word2vec lstm tensorflow word-embedding
我一直试图通过https://www.tensorflow.org/tutorials/recurrent来了解示例代码 ,您可以在https://github.com/tensorflow/models/blob/master/tutorials/rnn/ptb找到它./ptb_word_lm.py
(使用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.
Run Code Online (Sandbox Code Playgroud)
我最大的问题是,如果给出句子的前几个单词,我如何使用生成的模型实际生成下一个单词建议?具体来说,我认为流程是这样的,但我无法理解评论行的代码是什么:
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)
Run Code Online (Sandbox Code Playgroud)
我的子问题是:
(我问他们都是一个问题,因为我怀疑他们都是联系在一起的,并且在我的理解中与一些差距有关.)
我期待在这里看到的是加载现有的word2vec单词嵌入集(例如使用gensim KeyedVectors.load_word2vec_format()),在每个句子中加载时将输入语料库中的每个单词转换为该表示,然后LSTM将吐出一个向量相同的维度,我们会尝试找到最相似的单词(例如使用gensim similar_by_vector(y, topn=1)).
使用softmax从相对较慢的similar_by_vector(y, topn=1)通话中拯救我们吗?
顺便说一句,对于已存在的word2vec,我的问题部分使用预先训练的word2vec与LSTM进行单词生成是类似的.然而,目前那里的答案并不是我想要的.我所希望的是一个简单的英语解释,为我打开灯光,插入我理解的差距. 在lstm语言模型中使用预先训练的word2vec?是另一个类似的问题.
更新: 使用语言模型tensorflow例如预测下一个单词,并预测使用LSTM PTB模型tensorflow例如下一个单词是类似的问题.但是,两者都没有显示实际获取句子前几个单词的代码,并打印出对下一个单词的预测.我试着在代码粘贴从第二个问题,并从/sf/answers/2749788821/(附带了一个GitHub的分支),但不能得到要么无差错运行.我认为他们可能是早期版本的TensorFlow?
另一个更新:另一个问题基本上是同一个问题:从Tensorflow预测LSTM模型的下一个单词示例 它链接到 使用语言模型tensorflow示例预测下一个单词(再次,答案不是我正在寻找的) .
如果它仍然是不明确的,我想写称为高级功能getNextWord(model, sentencePrefix),其中model的是,我已经从磁盘加载以前建成LSTM,并且sentencePrefix是一个字符串,如"打开",并可能会返回"pod".然后我可以用"打开pod"来调用它,它将返回"bay",依此类推.
一个示例(使用字符RNN,并使用mxnet)是在https://github.com/zackchase/mxnet-the-straight-dope/blob/master/chapter05_recurrent-neural-networks/simple-sample()末尾附近显示的函数.rnn.ipynb
您可以sample()在训练期间打电话,但您也可以在训练后和任何您想要的句子中打电话.
加载自定义数据而不是使用测试集:
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
Run Code Online (Sandbox Code Playgroud)
test_data应该包含单词ids(打印出来word_to_id用于映射).例如,它应该看起来像:[1,52,562,246] ......
我们需要logits在调用中返回FC layer()的输出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
}
Run Code Online (Sandbox Code Playgroud)
稍后在函数中,vals['top_word_id']将有一个带有顶部字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)
Run Code Online (Sandbox Code Playgroud)
隐藏层是否必须与输入的维度匹配(即word2vec嵌入的维度)
从技术上讲,没有.如果你看一下LSTM方程,你会注意到x(输入)可以是任何大小,只要适当调整权重矩阵即可.
如何/我可以引入预先训练的word2vec模型,而不是未初始化的word2vec模型?
我不知道,对不起.
我最大的问题是,如果给出句子的前几个单词,我如何使用生成的模型实际生成下一个单词建议?
即我正在尝试使用签名编写一个函数:getNextWord(model,sentencePrefix)
在我解释我的答案之前,先说一下你的建议 # 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
Run Code Online (Sandbox Code Playgroud)
在__init__功能中PTBModel你需要添加这一行:
self.logits = logits
Run Code Online (Sandbox Code Playgroud)
为什么要使用随机(未初始化,未经训练)的字嵌入?
首先要注意的是,尽管嵌入在开始时是随机的,但它们将与网络的其余部分一起训练.你训练后得到的嵌入将有比你与word2vec模型,例如,回答与向量运算比喻问题的能力得到的嵌入相似的性质(王 - 男人女人+ =女王等)在任务是你有相当数量训练数据如语言建模(不需要注释的训练数据)或神经机器翻译,从头开始训练嵌入是更常见的.
为何使用softmax?
Softmax是将相似性得分(logits)的矢量归一化为概率分布的函数.您需要一个概率分布来训练您具有交叉熵损失的模型,并能够从模型中进行采样.请注意,如果您只对训练模型中最可能的单词感兴趣,则不需要softmax,您可以直接使用logits.
隐藏层是否必须与输入的维度匹配(即word2vec嵌入的维度)
不,原则上它可以是任何价值.但是,使用尺寸低于嵌入维度的隐藏状态并没有多大意义.
如何/我可以引入预先训练的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)
Run Code Online (Sandbox Code Playgroud)
有很多问题,我会尽力澄清其中一些。
给定句子的前几个单词,如何使用生成的模型实际生成下一个单词建议?
这里的关键点是,下一个单词生成实际上是词汇表中的单词分类。所以你需要一个分类器,这就是输出中有一个 softmax 的原因。
原理是,在每个时间步,模型将根据最后一个单词嵌入和先前单词的内部记忆输出下一个单词。tf.contrib.rnn.static_rnn自动将输入组合到内存中,但我们需要提供最后一个单词嵌入并对下一个单词进行分类。
我们可以使用预训练的 word2vec 模型,只需embedding用预训练的模型初始化矩阵即可。我认为为了简单起见,本教程使用随机矩阵。内存大小与嵌入大小无关,可以使用更大的内存大小来保留更多信息。
这些教程是高水平的。如果你想深入了解细节,我建议你查看简单的 python/numpy 源代码。
| 归档时间: |
|
| 查看次数: |
5746 次 |
| 最近记录: |