本篇博客主要記錄一下對(duì)語(yǔ)言模型、Word2Vec、ELMo和BERT學(xué)習(xí)和總結(jié),有些地方肯定理解不到位,希望小伙伴們賜教。
一、詞表征(Word Representation)
1、詞表征
首先明確句子是序列化,里面攜帶了大量大信息。在NLP發(fā)展的進(jìn)程里面, 采用了one-hot vector的形式來(lái)表示一個(gè)句子里面的詞是一種方式。表示這個(gè)句子的方式如下:
1、首先是創(chuàng)建一張?jiān)~匯表(Vocabulary),然后每個(gè)詞都有對(duì)應(yīng)的位置,假設(shè)現(xiàn)在我們有10000個(gè)單詞。本例子來(lái)自于吳恩達(dá)的Deeplearningai。圖中所示的詞匯表大小就是10000。一般規(guī)模的商業(yè)應(yīng)用來(lái)說(shuō),詞匯表大小為30000到50000詞。大型互聯(lián)網(wǎng)是百萬(wàn)級(jí)別的詞匯表。

one-hot vector表示向量的缺陷:
(1)這種表示把每個(gè)詞都孤立出來(lái)了,使得算法對(duì)相關(guān)詞的泛化能力弱。兩個(gè)不同人名的one-hot vector的內(nèi)積為0,這樣來(lái)表示就不能體現(xiàn)出詞匯在某些方面的相關(guān)性
(2)這樣得到的向量是稀疏的,而且維度非常的大。
那么現(xiàn)在提個(gè)問(wèn)題:我們?cè)趺磥?lái)表示詞匯,能夠?qū)⒁恍┫嚓P(guān)詞匯之間的一些共通特征給表現(xiàn)出來(lái)呢?
2、詞嵌入(Word Embeddings)
前面我們看到了one-hot vector表示一個(gè)詞,只有一個(gè)維度有意義。那么我們可以想想,能不能把一些相似詞匯的一些特征抽取出來(lái),給詞不同的維度賦予一些意思呢?結(jié)果就出現(xiàn)了詞嵌入的方式來(lái)表示句子里面的詞。
(1)詞嵌入:顧名思義,就是將一些特征給嵌入到詞匯里面,讓它能表現(xiàn)出更多的信息。
現(xiàn)在舉個(gè)例子:
1)性別特征:我們可以看出一些詞如Man, Woman, King, Queen是有關(guān)系的,那么我們就在gender這一欄給填上相關(guān)性的權(quán)重,然后詞如Apple, Orange這些就與gender,沒(méi)有關(guān)系,那么就是賦予趨近于0的權(quán)重。
2)年齡特征:可以看出King, Queen和age還是很想關(guān)的,但是Man, Woman, Apple, Orange與此就沒(méi)有多大關(guān)系了。
采用相同的策略,我們可以從很多特征(Food、size、cost、alive等)來(lái)考察一個(gè)詞在這些特征上面是否有關(guān)系。在這里例子里面選取了300個(gè)特征,那么我們就可以將一個(gè)詞表示為300維的一個(gè)向量,那么這些向量里面很多維度上都不是0。而且我們也可以看出向量之間再做內(nèi)積就能體現(xiàn)出詞匯的相似度了。然后另外一個(gè)重要的特性就做類比推理,但是這種推理的準(zhǔn)確度在30%到75%區(qū)間范圍內(nèi)。

到這里了,你會(huì)想,我們?nèi)绾蝸?lái)得到一個(gè)詞嵌入的特征矩陣呢?
(2)學(xué)習(xí)詞嵌入
在介紹學(xué)習(xí)詞嵌入之前,把相關(guān)的符號(hào)在這里標(biāo)注下:
其中10000表示詞匯表次數(shù),300表示嵌入向量里面的特征數(shù)。所以我們有個(gè)詞匯表和嵌入矩陣之后,我們就能得到對(duì)應(yīng)單詞的詞向量了。
下面我們就開始對(duì)詞向量進(jìn)行一個(gè)學(xué)習(xí):
學(xué)習(xí)嵌入矩陣E的一個(gè)好方法就是2003年Bengio等人提出的神經(jīng)語(yǔ)言模型 ,關(guān)于語(yǔ)言模型的介紹可以參考我的前一篇博客。
這里我們以一句話為例,來(lái)說(shuō)明使用語(yǔ)言模型來(lái)學(xué)習(xí)詞嵌入。這句話:I want a glass of orange juice。
上下文(context):把預(yù)測(cè)詞前面的幾個(gè)詞作文上下文,這個(gè)例子中為a glass of orange
目標(biāo)詞(target):把要預(yù)測(cè)的單詞作為目標(biāo)詞,這個(gè)例子中的目標(biāo)詞就是juice
注意:這里是為了學(xué)習(xí)詞嵌入,不是為了構(gòu)建一個(gè)語(yǔ)言模型。

那么現(xiàn)在我們就有訓(xùn)練集樣本了:content(w):維度((n-1)m,1),n-1指的是窗口里面的單詞數(shù),也就是例子中的4,m指的是詞向量的維度,例子中為300。那么例子中顯示的是(1200,1)。
w:要預(yù)測(cè)的下一個(gè)詞,例子中為juice,然后它的維度是(D, 1),D指的就是詞匯表的大小,也就是例子中所示的10000。
在softmax層,會(huì)計(jì)算10000個(gè)條件概率。然后可以通過(guò)反向傳播的方式,經(jīng)過(guò)梯度下降法,得到我們想獲得的嵌入矩陣E。
與n-gram模型相比,好處在于:
1、可以進(jìn)行詞語(yǔ)之間的相似度計(jì)算了,而且還能夠做類比。
2、不需要再考慮平滑操作了,因?yàn)閜(w|context)在0到1之間。
二、Word2Vec
看完了前面的神經(jīng)語(yǔ)言模型之后,我們看轉(zhuǎn)入了Word2Vec的兩個(gè)重要的模型CBOW(Continues bags of words)和Skip-gram模型。這兩個(gè)模型的示意圖如下:
這里可以明顯看出下面的的預(yù)測(cè)的方法:
| Model | 如何預(yù)測(cè) | 使用語(yǔ)料的規(guī)模 |
|---|---|---|
| CBOW | 使用上下文去預(yù)測(cè)目標(biāo)詞來(lái)訓(xùn)練得到詞向量 | 小型語(yǔ)料庫(kù)比較適合 |
| Skip-gram | 使用目標(biāo)詞去預(yù)測(cè)周圍詞來(lái)訓(xùn)練得到詞向量 | 在大型的語(yǔ)料上面表現(xiàn)得比較好 |
CBOW是非常常見的,但是不是非常常用的,最常用的還是Skip gram。所以本文就是針對(duì) Skip gram來(lái)進(jìn)行說(shuō)明了。
1、Skip-Gram模型
它只是一種學(xué)習(xí)方法而已。舉個(gè)例子:
I want a glass of orange juice。
思路就是我們有了glass之后,想去預(yù)測(cè)周圍的want a 和 of orange。現(xiàn)在我們?cè)趺慈?shù)學(xué)的方式去描述出來(lái)了。這里有一個(gè)window的size了。
Skip-Gram的目標(biāo)函數(shù)如下:
取對(duì)數(shù)之后的形式就
(w,c)在上下問(wèn)出現(xiàn),說(shuō)明它們的相似度很高,然后我們就需要ogP(c|w;\theta)是越大越好的,那么后面就用到的softmax的方式來(lái)得到一個(gè)概率。
這里注意我們的參數(shù)theta是兩次詞向量的矩陣
其中u代表了單詞作為上下文的詞向量,v代表了單詞作為中心詞的詞向量。這個(gè)在word2vec的源代碼中也是看得到的。
通過(guò)softwmax處理之后,我們就能得到
注意這里的上下文就是語(yǔ)料庫(kù)中的了。將改公式帶入到我們的目標(biāo)函數(shù)中去,就可以得到:
到這里來(lái)了之后,我們就得到了Skip-Gram模型的目標(biāo)函數(shù),但是這里有計(jì)算上的問(wèn)題,就是我們這里上下文取的是詞庫(kù),那么計(jì)算的時(shí)間復(fù)雜度很高。解決上面的問(wèn)題,目前使用了兩種手段:一個(gè)是負(fù)采樣,另外一個(gè)是層次化的softmax。
2、Skip-Gram與負(fù)采樣
先說(shuō)明一下負(fù)采樣之后的目標(biāo)函數(shù)有些變化,但是本質(zhì)上面還是一個(gè)道題。
這里就采用通俗易懂的方式來(lái)進(jìn)行說(shuō)明,假設(shè)我們的text如下
這里用到我們?cè)谶壿嫽貧w里面的思想
到目前為止的話,可能出現(xiàn)的問(wèn)題就是正樣本的數(shù)量非常少,然后負(fù)樣本的數(shù)量非常多,這個(gè)就是樣本數(shù)量極度不均衡的狀態(tài),所以我們需要從負(fù)樣本里面抽選一部分出來(lái),這樣的話,我們計(jì)算的時(shí)候就更快。
下面就是對(duì)負(fù)采樣的一個(gè)說(shuō)明:
I want a glass of orange juice
由上面的text,我們就知道了Vocab = {I, want, a, glass, of, orange, juice} 總共7個(gè)單詞,然后按照窗口是1的情況,進(jìn)行一個(gè)負(fù)采樣:
| 正樣本 | 負(fù)樣本 |
|---|---|
| (glass, a) | (glass, I), (glass, juice) |
| (glass, of) | (glass, want), (glass, I) |
| (of, glass) | (of, I), (of, juice) |
| (of, glass) | (of, want), (of, glass) |
這里就是一個(gè)負(fù)采樣的過(guò)程了,具體的負(fù)采樣的個(gè)數(shù)是一個(gè)超參數(shù)了,那么到了這里,我們就得到我們負(fù)采樣過(guò)程中的目標(biāo)函數(shù):
下面我們對(duì)各個(gè)未知數(shù)求一個(gè)偏導(dǎo):
得到偏導(dǎo)之后,我們就能夠采用梯度下降法去更新我們的參數(shù):
3、負(fù)采樣算法流程
for each (w, c) in 正樣本集合:
負(fù)采樣得到集合N(w):中心詞是w,負(fù)采樣。超參數(shù)為負(fù)樣本個(gè)數(shù)
進(jìn)行梯度計(jì)算
更新參數(shù)
在for循環(huán)里面,我們需要去進(jìn)行負(fù)采樣的操作。這里負(fù)采樣的個(gè)數(shù)就是一個(gè)訓(xùn)練時(shí)候的超參數(shù)了。一般選擇是5或者是10。另外為了進(jìn)行加速的處理,我們?cè)创a里面是用到了哈夫曼樹的方式去進(jìn)行一個(gè)提速的采樣。
三、詞向量的評(píng)估方式
訓(xùn)練得到詞向量之后,我們可以采用三種方法去進(jìn)行詞向量的好壞的評(píng)估:
1、可視化的方式評(píng)估:我們將我們學(xué)習(xí)到的100/200/300維的詞向量通過(guò)降維算法TSNE降到2為空間里面。然后通過(guò)可視化的方式看出詞向量的好壞。

2、計(jì)算詞向量的相似度或者相關(guān)性去評(píng)估。這種評(píng)估的方式就需要用到人工去標(biāo)記相似度。
3、通過(guò)類比來(lái)評(píng)估。

四、Word2Vec操作和改進(jìn)
我們可以從https://code.google.com/archive/p/word2vec/source/default/source
下載下來(lái)word2vec的C++源碼。
make word2vec
通過(guò)make進(jìn)行編譯得到了word2vec的二進(jìn)制文件。
./word2vec
運(yùn)行一下,我們就能夠看到里面提醒的一些參數(shù)了。
? 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思想非常的牛逼,但是也存在了很多的缺點(diǎn)和問(wèn)題:
1、學(xué)習(xí)出來(lái)的詞向量是固定的。這就導(dǎo)致了在任何的語(yǔ)境里面它表達(dá)的意思都是固定的了。實(shí)際上我們希望得到的是在不同語(yǔ)境下面得到不同的詞向量。所以后來(lái)就有了ELMo和BERT模型了。
2、窗口的長(zhǎng)度是有限的。解決的方式就通過(guò)language model了。
3、無(wú)法有效的學(xué)習(xí)低頻詞匯和未登陸詞。解決的方法就是subword embedding了。
4、預(yù)測(cè)不具備uncertainty。因?yàn)槲覀兊脑~向量都是固定住了的。但是不同語(yǔ)境下面的詞語(yǔ)的意義不同。解決的方式就是采用高斯embedding了。
5、可解釋性不夠。這個(gè)就是深度學(xué)習(xí)的一個(gè)通病了。
參考資料:
1、Deeplearningai主頁(yè)
2、網(wǎng)易云課堂-Deeplearningai
3、Yoshua Bengio, etc, A Neural Probabilistic Language Model(2003)
4、https://github.com/dav/word2vec
5、