页面树结构

2017-11-09 ApacheCN 开源组织,第二期邀请成员活动,一起走的更远 : http://www.apachecn.org/member/209.html


MachineLearning 优酷地址 : http://i.youku.com/apachecn

转至元数据结尾
转至元数据起始

在本教程中,我们来看看Mikolov等人的word2vec模型  该模型用于学习向量表示的词,称为“词嵌入”。

强调

本教程旨在突出在TensorFlow中构建word2vec模型的有趣的实质部分。

  • 我们首先给出为什么我们要将单词代表向量的动机。
  • 我们看看模型背后的直觉,以及它如何训练(以数学为出发点)。
  • 我们还展示了TensorFlow中模型的简单实现。
  • 最后,我们看看如何使天真的版本缩放更好。

我们稍后在教程中浏览代码,但是如果您希望直接跳转,请随时查看 tensorflow/examples/tutorials/word2vec/word2vec_basic.py 中的简约实现。 此基本示例包含下载所需的代码一些数据,训练一下,可视化的结果。一旦您阅读和运行基本版本,您就可以毕业到  tensorflow_models/tutorials/embedding/word2vec.py ,这是一个更严重的实现,它展示了一些更高级的TensorFlow原理,关于如何有效地使用线程将数据移动到文本模型,训练过程中如何检查点等

但首先,我们来看看我们为什么要首先学习单词嵌入。如果您是嵌入式专业版,请随意跳过本部分,您只需要弄清楚细节。

 

动机:为什么要学习Word嵌入?

图像和音频处理系统使用编码为图像数据的各个原始像素强度的向量的丰富的高维数据集,或者例如用于音频数据的功率谱密度系数。对于像对象或语音识别这样的任务,我们知道成功执行任务所需的所有信息都会在数据中进行编码(因为人类可以从原始数据执行这些任务)。然而,自然语言处理系统传统上将单词视为离散原子符号,因此“猫”可以被表示为Id537“狗” Id143。这些编码是任意的,并且不会向系统提供关于各个符号之间可能存在的关系的有用信息。这意味着该模型可以很好地利用它对“ 猫正在处理“狗”的数据(使他们既是动物,四足,宠物等)。将单词代表为唯一的离散ids,进一步导致数据稀疏,通常意味着我们可能需要更多的数据才能成功地训练统计模型。使用向量表示可以克服其中的一些障碍。

矢量空间模型(VSM)在连续向量空间中表示(嵌入)单词,其中语义相似的单词被映射到附近的点('彼此嵌套在一起)“。VSM在NLP中有着悠久而丰富的历史,但所有方法都依赖于 分布式假设,这表明出现在相同语境中的词语共享语义意义。利用这一原则的不同方法可以分为两类:基于计数的方法(例如 潜在语义分析)和预测方法(例如 神经概率语言模型)。

 Baroni等人更详细地阐述了这一区别 ,但简而言之:基于计数的方法计算一个单词在大文本语料库中与其邻居单词共同出现的频率的统计量,然后将这些计数统计信息映射到每个单词的小而密集的向量。预测模型直接尝试从学习的小密度嵌入向量(被认为是模型的参数)来估计来自其邻居的单词。

Word2vec是用于从原始文本学习字嵌入的特别具有计算效率的预测模型。它有两种口味,即连续词语模型(CBOW)和Skip-Gram模型(Mikolov等人的 3.1和3.2节)。算法上,这些模型是相似的,除了CBOW预测来自源语境单词(“猫坐在”上)的目标单词(例如“mat”),而跳过的表示反向并且预测来自目标的源上下文单词话。这种反转似乎是一个任意的选择,但统计学上它的效果是CBOW平滑了大量的分布信息(通过将整个上下文视为一个观察)。在大多数情况下,这对于较小的数据集是有用的。然而,skip-gram将每个上下文目标对视为一个新的观察结果,当我们有更大的数据集时,这往往会更好。本教程的其余部分将重点介绍跳格式模型。

 

扩大噪声对比训练

传统上使用最大似然(ML)原理训练神经概率语言模型 以最大化下一个词的概率 w ^Ť (针对“目标”)给出了前面的单词  H(对于“历史”)在 softmax函数方面

哪里   计算单词的兼容性  与上下文  h(通常使用点积)。我们通过最大化 训练集上的对数似然性来训练这个模型,即通过最大化

这为语言建模产生了适当归一化的概率模型。然而,这是非常昂贵的,因为我们需要使用所有其他的分数来计算和归一化每个概率 V 话   在当前的情况下  h在每一个训练步骤

                      

另一方面,对于word2vec中的特征学习,我们不需要一个完整的概率模型。相反,使用二进制分类目标(逻辑回归)对CBOW和跳过式模型进行训练,以区分真实目标词 从  虚构(噪音)词  ,在相同的上下文中。下面我们来说明一个CBOW模型。对于skip-gram,方向简单地反转。

                    

在数学上,目标(对于每个例子)是最大化

哪里  是在看到这个词的模型下的二元逻辑回归概率   在上下文中  h 在数据集中D,根据学习的嵌入向量计算  θ。实际上,我们通过绘制来估计期望值 k 来自噪声分布的对比词(即我们计算 蒙特卡罗平均值)。

当模型将高概率分配给真实单词时,该目标最大化,并且对噪声词的概率低。在技术上,这被称为 负采样,并且使用这种损失函数有很好的数学动机:它提出的更新近似于在最大值中的softmax函数的更新。但是在计算上它是特别吸引人的,因为计算损失函数现在只有我们选择的噪声字数量 k),而不是词汇中的所有单词 V)。这使得训练更快。实际上我们将使用非常类似的 噪声对比估计(NCE) 损失,TensorFlow具有方便的辅助功能tf.nn.nce_loss()

让我们得到一个直观的感觉,这将如何在实践中工作!

 

Skip-gram模型

例如,我们来考虑数据集

the quick brown fox jumped over the lazy dog

我们首先形成一个单词的数据集和它们出现的上下文。我们可以以任何有意义的方式定义“上下文”,实际上人们已经看过句法上下文(即当前目标词的语法依赖关系,例如 Levy等人),左边的单词目标,目标的词到对等。现在,让我们坚持香草定义,并将“上下文”定义为目标单词左侧和右侧的单词窗口。使用1的窗口大小,我们有数据集

([the, brown], quick), ([quick, fox], brown), ([brown, jumped], fox), ... 

(context, target)对。回想一下,跳过 - 反转上下文和目标,并尝试从其目标词预测每个上下文单词,因此任务将从“快速”,“快速”和“狐狸”从“棕色”预测“和” '等等。因此我们的数据集变成了

(quick, the), (quick, brown), (brown, quick), (brown, fox), ... 

(input, output)对。目标函数是在整个数据集上进行定义的,但是我们通常 使用一次一个示例(或通常为“ 实例的”minibatch“)对随机梯度下降(SGD)进行优化 。所以我们来看看这个过程的一个步骤。batch_size 16 <= batch_size <= 512 

让我们想象一下在培训步骤  我们观察了上面的第一个训练情况,其目的是the从中预测quick。我们num_noise通过从一些噪声分布中抽取噪声(对比)示例来选择数量,通常是单格式分布,。为了简单起见,我们说 num_noise=1,我们选择sheep一个嘈杂的例子。接下来,我们计算这对观察和嘈杂的例子的损失,即时间步长的目标 Ť 变

目标是更新嵌入参数  θ改善(在这种情况下,最大化)这个目标函数。我们通过导出相对于嵌入参数的损耗梯度来做到这一点 θ,即 (幸运的是TensorFlow为此做了简单的帮助功能!)。然后,我们对渐变方向进行一小步,对嵌入进行更新。当在整个训练集上重复该过程时,这具有对于每个单词“移动”嵌入向量的效果,直到模型成功地区分来自噪声字的真实单词。

我们可以通过使用例如t-SNE维数降低技术来将它们投影到2维来可视化所学习的向量 。当我们检查这些可视化时,显而易见的是,矢量捕获一些一般的,而且实际上是相当有用的关于词语及其彼此之间关系的语义信息。当我们第一次发现诱导向量空间中的某些方向专门针对某些语义关系(例如男性女性动词时态甚至语言之间的国家 - 资本关系)时,这是非常有趣的,如下图所示(另见例如 Turian et al., 2010)。

这解释了为什么这些向量也可用作许多规范的NLP预测任务的特征,例如词性标签或命名实体识别(参见例如Collobert等人,2011 (pdf)的原始作品, 同比工作 突锐等,2010)。

但是现在,让我们用它来绘制漂亮的照片!

 

构建图

这是关于嵌入的,所以我们来定义我们的嵌入矩阵。这只是开始的一个大随机矩阵。我们将初始化单位立方体中均匀的值。

embeddings = tf.Variable(
    tf.random_uniform([vocabulary_size, embedding_size], -1.0, 1.0))
噪声对比估计损失根据逻辑回归模型定义。为此,我们需要定义词汇中每个单词的权重和偏差(也称为output weights相反input embeddings)。所以我们来定义一下。
nce_weights = tf.Variable(
  tf.truncated_normal([vocabulary_size, embedding_size],
                      stddev=1.0 / math.sqrt(embedding_size)))
nce_biases = tf.Variable(tf.zeros([vocabulary_size]))
现在我们已经有了参数,我们可以定义我们的跳过模型图。为了简单起见,我们假设我们已经将我们的文本语料库整合为一个词汇表,以便每个单词都被表示为一个整数(详见 tensorflow / examples / tutorials / word2vec / word2vec_basic.py )。跳过模式需要两个输入。一个是表示源上下文单词的整数,另一个是针对目标单词的批处理。我们为这些输入创建占位符节点,以便我们以后可以提供数据。
# Placeholders for inputs
train_inputs = tf.placeholder(tf.int32, shape=[batch_size])
train_labels = tf.placeholder(tf.int32, shape=[batch_size, 1]) 
现在我们需要做的是查看批处理中每个源字的向量。TensorFlow有方便的帮助者,使这很容易。
embed = tf.nn.embedding_lookup(embeddings, train_inputs)
好的,现在我们对每一个单词都有嵌入,我们想尝试使用噪声对比的训练目标来预测目标词。
 
# Compute the NCE loss, using a sample of the negative labels each time.
loss = tf.reduce_mean(
  tf.nn.nce_loss(weights=nce_weights,
                 biases=nce_biases,
                 labels=train_labels,
                 inputs=embed,
                 num_sampled=num_sampled,
                 num_classes=vocabulary_size))
现在我们有一个损耗节点,我们需要添加计算梯度所需的节点并更新参数等等。为此,我们将使用随机梯度下降,而TensorFlow有一个方便的帮助者,使其变得容易。
# We use the SGD optimizer.
optimizer = tf.train.GradientDescentOptimizer(learning_rate=1.0).minimize(loss) 

训练模型

训练模型就像使用a feed_dict将数据推入占位符一样简单,并tf.Session.run在循环中调用 此新数据。

for inputs, labels in generate_batch(...):
  feed_dict = {train_inputs: inputs, train_labels: labels}
  _, cur_loss = session.run([optimizer, loss], feed_dict=feed_dict) 
请参阅 tensorflow/examples/tutorials/word2vec/word2vec_basic.py 中的完整示例代码 。

可视化学习嵌入

训练完成后,我们可以使用t-SNE来显示学习的嵌入。

Et 瞧!正如预期的那样,相似的词最终聚集在一起。对于展示更多TensorFlow的高级功能的word2vec的更重量级实现,请参阅 tensorflow_models/tutorials/embedding/word2vec.py 中的实现。

 

评估嵌入:类比推理

嵌入对于NLP中的各种预测任务很有用。训练完整的词性模型或命名实体模型,一种评估嵌入的简单方法是直接使用它们来预测句法和语义关系king is to queen as father is to ?。这被称为 模拟推理,任务由 Mikolov及其同事介绍 。从download.tensorflow.org下载此任务的数据集 。

看看我们如何做这个评估,看看build_eval_graph()和 eval()功能在 tensorflow_models/tutorials/embedding/word2vec.py

超参数的选择可能会严重影响此任务的准确性。为了在这个任务上实现最先进的性能,需要对一个非常大的数据集进行训练,仔细调整超参数,并利用诸如子数据抽样的技巧,这在本教程的范围之内。

 

优化实施

我们的香草实现展示了TensorFlow的灵活性。例如,改变培训目标就像tf.nn.nce_loss()将现有的替代方案 的调用交换出来一样简单tf.nn.sampled_softmax_loss()。如果您有一个损失函数的新想法,您可以手动为TensorFlow中的新目标写一个表达式,并让优化器计算其衍生。这种灵活性在机器学习模型开发的探索阶段是非常宝贵的,我们正在尝试几个不同的想法并快速迭代。

一旦你有一个模型结构,你对此感到满意,可能值得优化您的实现以更高效地运行(并且在更短的时间内覆盖更多的数据)。例如,我们在本教程中使用的朴素代码将受到损害的速度,因为我们使用Python来读取和提供数据项,每个都需要很少的TensorFlow后端工作。如果您发现您的模型严重瓶颈在输入数据上,您可能需要为您的问题实现自定义数据读取器,如新数据格式所述 。对于Skip-Gram建模的情况,我们实际上已经为此做了例子,例如在 tensorflow_models/tutorials/embedding/word2vec.py 中。

如果您的模型不再是I / O绑定,但是您希望更多的性能,您可以通过编写自己的TensorFlow Ops来进一步了解,如 添加新操作所述。我们再次为Skip-Gram案例 tensorflow_models/tutorials/embedding/word2vec_optimized.py 提供了一个例子 。随时对这些对手进行基准测量,以衡量每个阶段的绩效改进。

 

结论

在本教程中,我们介绍了word2vec模型,一种用于学习单词嵌入的计算效率模型。我们动机为什么嵌入式是有用的,讨论高效的培训技术,并展示了如何在TensorFlow中实现所有这些。总的来说,我们希望这可以显示TensorFlow如何为您提供早期实验所需的灵活性,以及您以后需要进行定制优化实施的控制。

 

  • 无标签