本篇博客主要记录一下对语言模型、Word2Vec、ELMo和BERT学习和总结,有些地方肯定理解不到位,希望小伙伴们赐教。
一、词表征(Word Representation)
1、词表征
首先明确句子是序列化,里面携带了大量大信息。在NLP发展的进程里面, 采用了one-hot vector的形式来表示一个句子里面的词是一种方式。表示这个句子的方式如下:
1、首先是创建一张词汇表(Vocabulary),然后每个词都有对应的位置,假设现在我们有10000个单词。本例子来自于吴恩达的Deeplearningai。图中所示的词汇表大小就是10000。一般规模的商业应用来说,词汇表大小为30000到50000词。大型互联网是百万级别的词汇表。
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%区间范围内。
到这里了,你会想,我们如何来得到一个词嵌入的特征矩阵呢?
(2)学习词嵌入
在介绍学习词嵌入之前,把相关的符号在这里标注下:
其中10000表示词汇表次数,300表示嵌入向量里面的特征数。所以我们有个词汇表和嵌入矩阵之后,我们就能得到对应单词的词向量了。
下面我们就开始对词向量进行一个学习:
学习嵌入矩阵E的一个好方法就是2003年Bengio等人提出的神经语言模型 ,关于语言模型的介绍可以参考我的前一篇博客。
这里我们以一句话为例,来说明使用语言模型来学习词嵌入。这句话:I want a glass of orange juice。
上下文(context):把预测词前面的几个词作文上下文,这个例子中为a glass of orange
目标词(target):把要预测的单词作为目标词,这个例子中的目标词就是juice
注意:这里是为了学习词嵌入,不是为了构建一个语言模型。
那么现在我们就有训练集样本了: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模型。这两个模型的示意图如下:这里可以明显看出下面的的预测的方法:
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的目标函数如下:
取对数之后的形式就
(w,c)在上下问出现,说明它们的相似度很高,然后我们就需要ogP(c|w;\theta)是越大越好的,那么后面就用到的softmax的方式来得到一个概率。
这里注意我们的参数theta是两次词向量的矩阵
其中u代表了单词作为上下文的词向量,v代表了单词作为中心词的词向量。这个在word2vec的源代码中也是看得到的。
通过softwmax处理之后,我们就能得到
注意这里的上下文就是语料库中的了。将改公式带入到我们的目标函数中去,就可以得到:
到这里来了之后,我们就得到了Skip-Gram模型的目标函数,但是这里有计算上的问题,就是我们这里上下文取的是词库,那么计算的时间复杂度很高。解决上面的问题,目前使用了两种手段:一个是负采样,另外一个是层次化的softmax。
2、Skip-Gram与负采样
先说明一下负采样之后的目标函数有些变化,但是本质上面还是一个道题。
这里就采用通俗易懂的方式来进行说明,假设我们的text如下
这里用到我们在逻辑回归里面的思想
到目前为止的话,可能出现的问题就是正样本的数量非常少,然后负样本的数量非常多,这个就是样本数量极度不均衡的状态,所以我们需要从负样本里面抽选一部分出来,这样的话,我们计算的时候就更快。
下面就是对负采样的一个说明:
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) |
这里就是一个负采样的过程了,具体的负采样的个数是一个超参数了,那么到了这里,我们就得到我们负采样过程中的目标函数:
下面我们对各个未知数求一个偏导:
得到偏导之后,我们就能够采用梯度下降法去更新我们的参数:
3、负采样算法流程
for each (w, c) in 正样本集合:
负采样得到集合N(w):中心词是w,负采样。超参数为负样本个数
进行梯度计算
更新参数
在for循环里面,我们需要去进行负采样的操作。这里负采样的个数就是一个训练时候的超参数了。一般选择是5或者是10。另外为了进行加速的处理,我们源代码里面是用到了哈夫曼树的方式去进行一个提速的采样。
三、词向量的评估方式
训练得到词向量之后,我们可以采用三种方法去进行词向量的好坏的评估:
1、可视化的方式评估:我们将我们学习到的100/200/300维的词向量通过降维算法TSNE降到2为空间里面。然后通过可视化的方式看出词向量的好坏。
2、计算词向量的相似度或者相关性去评估。这种评估的方式就需要用到人工去标记相似度。
3、通过类比来评估。
四、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
Use text data from to train the model
-output
Use to save the resulting word vectors / word clusters
-size
Set size of word vectors; default is 100
-window
Set max skip length between words; default is 5
-sample
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
Use Hierarchical Softmax; default is 0 (not used)
-negative
Number of negative examples; default is 5, common values are 3 - 10 (0 = not used)
-threads
Use threads (default 12)
-iter
Run more training iterations (default 5)
-min-count
This will discard words that appear less than times; default is 5
-alpha
Set the starting learning rate; default is 0.025 for skip-gram and 0.05 for CBOW
-classes
Output word classes rather than word vectors; default number of classes is 0 (vectors are written)
-debug
Set the debug mode (default = 2 = more info during training)
-binary
Save the resulting vectors in binary moded; default is 0 (off)
-save-vocab
The vocabulary will be saved to
-read-vocab
The vocabulary will be read from , not constructed from the training data
-cbow
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、