本篇是 Word Vector Embeddings的实现部分。
该章节位于Tensroflow For Machine Inteligence这本书的自然语言处理部分。
在第六章的翻译中把6.2 分为了上下两部分,上半部分相当于前言,先半部分是实现。
6.2.1Preparing the Wikipedia Corpus
在准备去详细介绍skip-gram模型之前,需要先准备数据集---在本案中使用英文维基百科数据集。默认的数据集含所有页面的完整修订历史记录,当前页面版本的文本大约有100GB,但已经有足够了。这次的练习也使用其他的语言可以用,您可以在Wikimedia下载网站上查看可用转储的概述:https://dumps.wikimedia.org/backup-index.html.
为了可以将获取的数据中转化成正确的格式,这里需要有两部操作。正如你之前在本书中看到的,数据收集和数据的清洗都是必须且重要的任务。最终,我们要遍历维基百科页面,将他们表示为one-hot编码词。采用一下步骤:
1. 下载数据集,提取页面和单词。
2. 统计单词形成最常用单词的vocabulary
3. 使用vocabulary对提取的页面编码。
在主存上对整个文集(维基数据集)修改做起来不太容易,所以我们必须使用数据流(data stream)一行一行的读取文件,并把中间(intermediate)结果写入到磁盘上。如果这样照做,我们在这些步骤之间就有检查点,如果有什么出现崩溃的话,不必从头开始。我们使用以下类来处理维基百科。在Init()上对文件是否存在进行检查。
注意,我们还不得不去实现Wclass的两个重要函数。第一个是_read_pages() 会下载Wikipedia数据库,并从该数据库中解压出XML文件,然后迭代页面并提取纯文本以摆脱任何格式。为了读取压缩文件,我们需要bz2模块提供的open()方法,它的工作方式与其标准的等效工具类似,但是即使在流式传输文件时也需要处理压缩和解压缩。我们节约存储空间,我们会对中间结果压缩。用于提取单词的正则表达式仅捕获连续字母的序列和个别出现的某些特殊字符。
我们需要一个用于one-hot 编码的vocabulary. 然后我们可以用词汇表中的intex来对每个单词进行编码。为了移除拼写错误的和未知的单词,vocabulary中只包含vocabulary-1个最常用的单词以及一个 符号用于替代vocabulary中不存在的单词。这个符号也会在word-vector中给出,以后我们可以用它来代表未曾见过的单词。
由于我们提取到的是纯文本,并为单词定义了编码,我们可以现场形成以训练实例。(one the fly应该是俚语,大意是随后,现场)这样的做法很棒,因为存储示例需要大量的存储空间。由于大部分时间都会花在训练上,所以这对性能影响不大。我们也希望将所得到的样本分批分组,以便更有效地进行训练。由于分类器并不需要太多的内存,我们可以使用很大的批次。
那么我们如何形成训练实例呢?请记住,skip-gram模型预测的是当前单词的上下文单词。在遍历文本的时候,将当前单词作为数据将它周围的单词作为target,用这种方式创建训练样本。假设上下文距离是R=5, 我们可以对每个单词产生10个训练样本,左右五个单词作为目标。然而,有人可能会认为近邻比远邻更重要的语义语境。因此,我们通过随机选择一个上下文大小来创建较少的带有远端语境的训练样例,对于每个单词来说,上下文的大小在[1,D=10]中随机产生。
6.2.2 Model structure
现在,Wikipedia 数据集已经准备好了,开始定义模型来计算word embeddings.
每个单词开始由一个随机向量表示。从单词的中间表示中,分类器将尝试预测其上下文单词之一的当前表示。然后,我们将传播错误来调整输入词的权重和表示。因此,使用tf.Variabale表达表示。如下图
使用MomentumOptimizer并不是太好,但这种优化器的优势是可以很快的收敛。这使得它在庞大的维基百科语料库上表现的很好,Skip-gram背后的思想是可以在更聪明的算法上使用更多的数据。
我们模型中现在唯一缺少的就是分类器了。这是skip-gram模型成功的关键,下面我们会介绍这个分类器如何工作。
6.2.3 Noise Contrastive Classifier
对于skip-gram模型来说,可以使用很多种代价函数(cost function), 但是noise-constrastive estimation loss代价函数被认为是效果最好的。理想情况下(ideallly),我们不仅要让预测接近目标,而且还要远离当前单词不是目标的单词。虽然都可以很好地模拟为softmax分类器,但我们不希望每次都计算和训练字母表中所有单词的输出。总是使用一些新的随机向量作为负面的例子的方法,也被称为对比的样本。虽然需要几十个类,平均到softmax分类器需要经过足够的训练迭代。为此,Tensorflow 提供了一个较为方便的函数tf.nn.nce_loss函数。
6.2.4 Training the model
如今已经准备好数据库,也定义好了模型。还剩一些代码需要把所有的东西连在一起。训练过后,我们将最后的embeddings存储到另一个文件中。下面的示例是在普通CPU下,使用Wikipedia的子集训练需要5个小时左右。如果要使用全集,只需要将URL切换成https://dumps.wikimedia.org/enwiki/20160501/enwiki-20160501-pages-meta-current.xml.bz2即可。
正如你所看到的,我们会使用一个AttrDict类。它相当于一个python的dict, 只不过我们在访问关键字(key)的时候,可以得到其属性(attributes)。更多细节,请参阅代码结构和实用程序一章(the chapter Code Structure and Utilities )。
经过大约5个小时的训练以后,我们将把学习的embeddings作为一个Numpy数组存储。当我们在以后的章节中想要使用这个embeddings的时候就没有必要在计算了。直接拿来使用就行。在网上有预先训练的词语嵌入(pre-trained word embeddings),我们稍后会在需要时给出这些embeddings。
2018年1月2日。
下周:
第三节 6.3 Sequence Classification