word2vec原理、推导与总结

本篇博客主要记录一下对语言模型、Word2Vec、ELMo和BERT学习和总结,有些地方肯定理解不到位,希望小伙伴们赐教。

一、词表征(Word Representation)

1、词表征

首先明确句子是序列化,里面携带了大量大信息。在NLP发展的进程里面, 采用了one-hot vector的形式来表示一个句子里面的词是一种方式。表示这个句子的方式如下:
1、首先是创建一张词汇表(Vocabulary),然后每个词都有对应的位置,假设现在我们有10000个单词。本例子来自于吴恩达的Deeplearningai。图中所示的词汇表大小就是10000。一般规模的商业应用来说,词汇表大小为30000到50000词。大型互联网是百万级别的词汇表。

image.png
2、将句子里面的每个单词转换为one-hot vector。one-hot vector从字面上来理解就是向量里面只有1个1,也就是找到这个词在词汇表里面的位置处填上1,然后其他的位置都是0。可以看出one-hot vector的模长为1。
one-hot vector表示向量的缺陷:
(1)这种表示把每个词都孤立出来了,使得算法对相关词的泛化能力弱。两个不同人名的one-hot vector的内积为0,这样来表示就不能体现出词汇在某些方面的相关性

(2)这样得到的向量是稀疏的,而且维度非常的大。

那么现在提个问题:我们怎么来表示词汇,能够将一些相关词汇之间的一些共通特征给表现出来呢?

2、词嵌入(Word Embeddings)

前面我们看到了one-hot vector表示一个词,只有一个维度有意义。那么我们可以想想,能不能把一些相似词汇的一些特征抽取出来,给词不同的维度赋予一些意思呢?结果就出现了词嵌入的方式来表示句子里面的词。
(1)词嵌入:顾名思义,就是将一些特征给嵌入到词汇里面,让它能表现出更多的信息。
现在举个例子:
1)性别特征:我们可以看出一些词如Man, Woman, King, Queen是有关系的,那么我们就在gender这一栏给填上相关性的权重,然后词如Apple, Orange这些就与gender,没有关系,那么就是赋予趋近于0的权重。
2)年龄特征:可以看出King, Queen和age还是很想关的,但是Man, Woman, Apple, Orange与此就没有多大关系了。
采用相同的策略,我们可以从很多特征(Food、size、cost、alive等)来考察一个词在这些特征上面是否有关系。在这里例子里面选取了300个特征,那么我们就可以将一个词表示为300维的一个向量,那么这些向量里面很多维度上都不是0。而且我们也可以看出向量之间再做内积就能体现出词汇的相似度了。然后另外一个重要的特性就做类比推理,但是这种推理的准确度在30%到75%区间范围内。

image.png

到这里了,你会想,我们如何来得到一个词嵌入的特征矩阵呢?
(2)学习词嵌入
在介绍学习词嵌入之前,把相关的符号在这里标注下:
其中10000表示词汇表次数,300表示嵌入向量里面的特征数。所以我们有个词汇表和嵌入矩阵之后,我们就能得到对应单词的词向量了。
下面我们就开始对词向量进行一个学习:
学习嵌入矩阵E的一个好方法就是2003年Bengio等人提出的神经语言模型 ,关于语言模型的介绍可以参考我的前一篇博客。
这里我们以一句话为例,来说明使用语言模型来学习词嵌入。这句话:I want a glass of orange juice。
上下文(context):把预测词前面的几个词作文上下文,这个例子中为a glass of orange
目标词(target):把要预测的单词作为目标词,这个例子中的目标词就是juice
注意:这里是为了学习词嵌入,不是为了构建一个语言模型。
image.png

那么现在我们就有训练集样本了:(context(w),w)content(w):维度((n-1)m,1),n-1指的是窗口里面的单词数,也就是例子中的4,m指的是词向量的维度,例子中为300。那么例子中显示的是(1200,1)。
w:要预测的下一个词,例子中为juice,然后它的维度是(D, 1),D指的就是词汇表的大小,也就是例子中所示的10000。
在softmax层,会计算10000个条件概率。然后可以通过反向传播的方式,经过梯度下降法,得到我们想获得的嵌入矩阵E。
与n-gram模型相比,好处在于:
1、可以进行词语之间的相似度计算了,而且还能够做类比。
2、不需要再考虑平滑操作了,因为p(w|context)在0到1之间。

二、Word2Vec

看完了前面的神经语言模型之后,我们看转入了Word2Vec的两个重要的模型CBOW(Continues bags of words)和Skip-gram模型。这两个模型的示意图如下:
CBOW和Skip gram

这里可以明显看出下面的的预测的方法:

Model 如何预测 使用语料的规模
CBOW 使用上下文去预测目标词来训练得到词向量 小型语料库比较适合
Skip-gram 使用目标词去预测周围词来训练得到词向量 在大型的语料上面表现得比较好

CBOW是非常常见的,但是不是非常常用的,最常用的还是Skip gram。所以本文就是针对 Skip gram来进行说明了。

1、Skip-Gram模型

它只是一种学习方法而已。举个例子:
I want a glass of orange juice。
思路就是我们有了glass之后,想去预测周围的want a 和 of orange。现在我们怎么去数学的方式去描述出来了。这里有一个window的size了。
Skip-Gram的目标函数如下:
l(\theta) = arg \max_\theta \prod_{w\in Text} \prod_{C\in Context(w)} P(c|w;\theta)

取对数之后的形式就
L(\theta) = arg \max_\theta \sum_{w\in Text} \sum_{C\in Context(w)} logP(c|w;\theta) (w,c)在上下问出现,说明它们的相似度很高,然后我们就需要ogP(c|w;\theta)是越大越好的,那么后面就用到的softmax的方式来得到一个概率。

这里注意我们的参数theta是两次词向量的矩阵
\theta = [u, v]
其中u代表了单词作为上下文的词向量,v代表了单词作为中心词的词向量。这个在word2vec的源代码中也是看得到的。
通过softwmax处理之后,我们就能得到
P(c|w;\theta) = \frac {e^{u_{c}*v_{w}}}{\sum_{c^{\prime} \in corpus} e^{u_{c^{\prime}}*v_{w}}} 注意这里的上下文就是语料库中的了。将改公式带入到我们的目标函数中去,就可以得到:
\begin{eqnarray} L(\theta) &=& arg \max_\theta \sum_{w\in Text} \sum_{C\in Context(w)} logP(c|w;\theta)\\ & =& arg \max_\theta \sum_{w\in Text} \sum_{C\in Context(w)} log \frac {e^{u_{c}*v_{w}}}{\sum_{c^{\prime} \in corpus} e^{u_{c^{\prime}}*v_{w}}} \\ &=& arg \max_\theta \sum_{w\in Text} \sum_{C\in Context(w)}[u_{c}*v_{w}-log\sum_{c^{\prime} \in corpus}e^{u_{c^{\prime}}*v_{w}}] \end{eqnarray} 到这里来了之后,我们就得到了Skip-Gram模型的目标函数,但是这里有计算上的问题,就是我们这里上下文取的是词库,那么计算的时间复杂度很高。解决上面的问题,目前使用了两种手段:一个是负采样,另外一个是层次化的softmax。

2、Skip-Gram与负采样

先说明一下负采样之后的目标函数有些变化,但是本质上面还是一个道题。
这里就采用通俗易懂的方式来进行说明,假设我们的text如下
text = w_{1}w_{2}w_{3}w_{4}w_{5}

这里用到我们在逻辑回归里面的思想
l(\theta) = arg \max_\theta \prod_{(c,w)\in D}P(D=1|c,w; \theta) \prod_{(c,w)\in \tilde{D}}P(D=0|c,w; \theta)

\begin{eqnarray} L(\theta) &=& arg \max_\theta[ \sum_{(c,w)\in D}P(D=1|c,w; \theta) +\sum_{(c,w)\in \tilde{D}}P(D=0|c,w; \theta)]\\ &=& arg \max_\theta[\sum_{(c,w)\in D} log\sigma(u_{c}\cdot v_{w}) +\sum_{(c,w)\in \tilde{D}}log\sigma(-u_{c}\cdot v_{w})] \end{eqnarray} 到目前为止的话,可能出现的问题就是正样本的数量非常少,然后负样本的数量非常多,这个就是样本数量极度不均衡的状态,所以我们需要从负样本里面抽选一部分出来,这样的话,我们计算的时候就更快。
下面就是对负采样的一个说明:
I want a glass of orange juice
由上面的text,我们就知道了Vocab = {I, want, a, glass, of, orange, juice} 总共7个单词,然后按照窗口是1的情况,进行一个负采样:

正样本 负样本
(glass, a) (glass, I), (glass, juice)
(glass, of) (glass, want), (glass, I)
(of, glass) (of, I), (of, juice)
(of, glass) (of, want), (of, glass)

这里就是一个负采样的过程了,具体的负采样的个数是一个超参数了,那么到了这里,我们就得到我们负采样过程中的目标函数:
L(\theta) = arg \max_\theta[\sum_{(c,w)\in D} log\sigma(u_{c}\cdot v_{w}) +\sum_{c^{\prime }\in N(w)}. log\sigma(-u_{c^{\prime}}\cdot v_{w})
下面我们对各个未知数求一个偏导:
\begin{eqnarray} \frac{\partial L(\theta)}{\partial u_{c}} &=& [1-\sigma(u_{c}\cdot v_{w})]\cdot v_{w}\\ \frac{\partial L(\theta)}{\partial u_{c^{\prime}}} &=& [\sigma(-u_{c^{\prime}}\cdot v_{w})-1]\cdot v_{w}\\ \frac{\partial L(\theta)}{\partial v_{w}} &=& [1-\sigma(u_{c}\cdot v_{w})]\cdot u_{c}+ \sum_{c^{\prime \in N(w)}}[\sigma(-u_{c^{\prime}}\cdot v_{w})-1]\cdot u_{c^{\prime}} \\ \end{eqnarray}
得到偏导之后,我们就能够采用梯度下降法去更新我们的参数:
u_{c} := u_{c} - \alpha \cdot \frac{\partial L(\theta)}{\partial u_{c}}

u_{c^{\prime}} := u_{c^{\prime}} - \alpha \cdot \frac{\partial L(\theta)}{\partial u_{c}^{\prime}}

v_{w} := v_{w} - \alpha \cdot \frac{\partial L(\theta)}{\partial v_{w}}

3、负采样算法流程
for each (w, c) in 正样本集合:
    负采样得到集合N(w):中心词是w,负采样。超参数为负样本个数
    进行梯度计算
    更新参数

在for循环里面,我们需要去进行负采样的操作。这里负采样的个数就是一个训练时候的超参数了。一般选择是5或者是10。另外为了进行加速的处理,我们源代码里面是用到了哈夫曼树的方式去进行一个提速的采样。

三、词向量的评估方式

训练得到词向量之后,我们可以采用三种方法去进行词向量的好坏的评估:
1、可视化的方式评估:我们将我们学习到的100/200/300维的词向量通过降维算法TSNE降到2为空间里面。然后通过可视化的方式看出词向量的好坏。


T-SNE

2、计算词向量的相似度或者相关性去评估。这种评估的方式就需要用到人工去标记相似度。
3、通过类比来评估。

analogy

四、Word2Vec操作和改进

我们可以从https://code.google.com/archive/p/word2vec/source/default/source
下载下来word2vec的C++源码。

make word2vec

通过make进行编译得到了word2vec的二进制文件。

./word2vec

运行一下,我们就能够看到里面提醒的一些参数了。

☁  trunk  ./word2vec
WORD VECTOR estimation toolkit v 0.1c

Options:
Parameters for training:
    -train <file>
        Use text data from <file> to train the model
    -output <file>
        Use <file> to save the resulting word vectors / word clusters
    -size <int>
        Set size of word vectors; default is 100
    -window <int>
        Set max skip length between words; default is 5
    -sample <float>
        Set threshold for occurrence of words. Those that appear with higher frequency in the training data
        will be randomly down-sampled; default is 1e-3, useful range is (0, 1e-5)
    -hs <int>
        Use Hierarchical Softmax; default is 0 (not used)
    -negative <int>
        Number of negative examples; default is 5, common values are 3 - 10 (0 = not used)
    -threads <int>
        Use <int> threads (default 12)
    -iter <int>
        Run more training iterations (default 5)
    -min-count <int>
        This will discard words that appear less than <int> times; default is 5
    -alpha <float>
        Set the starting learning rate; default is 0.025 for skip-gram and 0.05 for CBOW
    -classes <int>
        Output word classes rather than word vectors; default number of classes is 0 (vectors are written)
    -debug <int>
        Set the debug mode (default = 2 = more info during training)
    -binary <int>
        Save the resulting vectors in binary moded; default is 0 (off)
    -save-vocab <file>
        The vocabulary will be saved to <file>
    -read-vocab <file>
        The vocabulary will be read from <file>, not constructed from the training data
    -cbow <int>
        Use the continuous bag of words model; default is 1 (use 0 for skip-gram model)

Examples:
./word2vec -train data.txt -output vec.txt -size 200 -window 5 -sample 1e-4 -negative 5 -hs 0 -binary 0 -cbow 1 -iter 3

word2vec的源码有很多种,这里可以去看看C++版本的word2vec。地址就是https://github.com/dav/word2vec
虽然word2vec思想非常的牛逼,但是也存在了很多的缺点和问题:
1、学习出来的词向量是固定的。这就导致了在任何的语境里面它表达的意思都是固定的了。实际上我们希望得到的是在不同语境下面得到不同的词向量。所以后来就有了ELMo和BERT模型了。
2、窗口的长度是有限的。解决的方式就通过language model了。
3、无法有效的学习低频词汇和未登陆词。解决的方法就是subword embedding了。
4、预测不具备uncertainty。因为我们的词向量都是固定住了的。但是不同语境下面的词语的意义不同。解决的方式就是采用高斯embedding了。
5、可解释性不够。这个就是深度学习的一个通病了。

参考资料:
1、Deeplearningai主页
2、网易云课堂-Deeplearningai
3、Yoshua Bengio, etc, A Neural Probabilistic Language Model(2003)
4、https://github.com/dav/word2vec
5、

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容