前言
最近一直在看TensorFlow的东西,也不知道怎么做才好,借着TF的word2vec的例子,我来分析一下周杰伦所唱的歌。
准备
首先,我准备了周杰伦唱过的歌的歌词,你可以在这里周杰伦唱过的歌下载这个例子。当然你有更好的例子的话,欢迎联系本弱
根据TF官方的数据,其给的是一个英文的分词表,所以移花接木的,这里可以使用中文分词工具jieba
来处理歌词的分词。
|
|
这里的words
是用于记录分词后的周杰伦的歌词的一个列表。
创建一个字典来方便检索数据
这里根据TF的入门指导,选择字典来检索数据,并且为后面skip-gram
模型的生成提供指导。
|
|
这里使用collection
这个高效的容器来检索前600个出现次数最多的词,并且检索出来。然后将检索的前600个字编号。
创建一个索引数组,遍历原始数据中的列表,如果当前遍历对象是600个字中的一员,那么对应索引数组中的成员就赋予600个字的标号,如果不是,程序就会认为其是不可识别的,将其指向未知这个字符(UNK)的标号(应该是0),遍历结束后,补充上更新后的不可识别的字符。这样数据就转换成了一个带有索引编号的数组,一个字符计数的字典,一个标号的字典以及其反式字典。
然后删除掉原始数据,以便节省内存空间。
建立skip-gram模型
什么是skip-gram模型?
和词袋模型相反,skip-gram
是通过从一个文字来预测的上下文。
其实, 用一个向量唯一标识一个word已经提出有一段时间了. Tomáš Mikolov的word2vec算法的一个不同之处在于, 他把一个word映射到高维(50到300维), 并且在这个维度上有了很多有意思的语言学特性, 比如单词”Rome”的表达vec(‘Rome’)
, 可以是vec(‘Paris’) – vec(‘France’) + vec(‘Italy’)
的计算结果.
向量空间模型 (VSMs)将词汇表达(嵌套)于一个连续的向量空间中,语义近似的词汇被映射为相邻的数据点。向量空间模型在自然语言处理领域中有着漫长且丰富的历史,不过几乎所有利用这一模型的方法都依赖于 分布式假设,其核心思想为出现于上下文情景中的词汇都有相类似的语义。采用这一假设的研究方法大致分为以下两类:基于技术的方法 (e.g. 潜在语义分析), 和 预测方法 (e.g. 神经概率化语言模型).
如何建立一个skip-gram模型?
建议直接参考TensorFlow中文教程
the quick brown fox jumped over the lazy dog
我们首先对一些单词以及它们的上下文环境建立一个数据集。我们可以以任何合理的方式定义‘上下文’,而通常上这个方式是根据文字的句法语境的(使用语法原理的方式处理当前目标单词可以看一下这篇文献 Levy et al.,比如说把目标单词左边的内容当做一个‘上下文’,或者以目标单词右边的内容,等等。现在我们把目标单词的左右单词视作一个上下文, 使用大小为1的窗口,这样就得到这样一个由(上下文, 目标单词)
组成的数据集:
([the, brown], quick), ([quick, fox], brown), ([brown, jumped], fox), ...
前文提到Skip-Gram模型是把目标单词和上下文颠倒过来,所以在这个问题中,举个例子,就是用'quick'
来预测 'the'
和 'brown'
,用 'brown'
预测 'quick'
和 'brown'
。因此这个数据集就变成由(输入, 输出)
组成的:
(quick, the), (quick, brown), (brown, quick), (brown, fox), ...
目标函数通常是对整个数据集建立的,但是本问题中要对每一个样本(或者是一个batch_size
很小的样本集,通常设置为16 <= batch_size <= 512
)在同一时间执行特别的操作,称之为随机梯度下降 SGD。我们来看一下训练过程中每一步的执行。
假设用 t 表示上面这个例子中quick 来预测 the 的训练的单个循环。用 num_noise
定义从噪声分布中挑选出来的噪声(相反的)单词的个数,通常使用一元分布,P(w)。为了简单起见,我们就定num_noise=1
,用sheep
选作噪声词。接下来就可以计算每一对观察值和噪声值的损失函数了。
构建针对skip-gram的数据集
skip-gram
模型可以理解为每次从一个长度为[skipWindow...,target,skipWindow... ]
的样本中找出位于两端的元素和目标输出构成的一个(输出,输入)
的一个样本。
|
|
在这个函数之中,batchSize
指的是每次选择的样本的数量,而numSkip
指的则是每次target和周围词的复用率,dataIndex
作为一个全局变量则是起到一个类似于指针的作用。
代码在初始化的时候,初始化了定形状的batch
和label
矩阵,接着,代码将会从当前dataIndex
取2 * skipWinnow + 1
个长度为2 * skipWinnow + 1
压进一个长度为双端队列。接着根据指示其就会选出target周围的numSkip
个词,接着索引指向下一个字符,继续操作。直至选出batchSize
个样本出来。batch
是选出的输出词,而label
则是输入词。
开始skip-gram的训练
预设定条件之后,就可以开始skip-gram
的训练了。
|
|
首先使用了两个占位符,其主要作为batch
和label
所feed的对象。由于我们没有GPU配置(渣电脑是AMD的显卡,哈哈哈)。然后建立了一个形状为[vocabularySize, embeddingSize]
的一个嵌套的矩阵。我们用唯一的随机值来初始化这个大矩阵。
然后我们需要对批数据中的单词建立嵌套向量,TensorFlow提供了方便的工具函数。也就是tf.nn.embedding_lookup
对噪声-比对的损失计算就使用一个逻辑回归模型。对此,我们需要对语料库中的每个单词定义一个权重值(weight)和偏差值(baise)。(也可称之为输出权重 与之对应的 输入嵌套值)。
所以说word2vec是只有一个隐层的全连接神经网络, 用来预测给定单词的关联度大的单词.WI 的大小是VxN, V是单词字典的大小, 每次输入是一个单词, N是你设定的隐层大小.
对于整个数据集,当梯度下降的过程中不断地更新参数,对应产生的效果就是不断地移动每个单词的嵌套向量,直到可以把真实单词和噪声单词很好得区分开。所以这里使用的是NCE
函数。
|
|
训练模型
训练的过程很简单,只要在循环中使用feed_dict
不断给占位符填充数据,同时调用session.run
即可。
|
|
结果
还是很尴尬的。。。
展望
可以利用这个为之后的seq2seq
模型的建立提供支持
所有的代码下载
点击这里
Note : 可能有乱码哦~