word2vector已經(jīng)成為NLP領(lǐng)域的基石算法。作為一名AI 從業(yè)者功偿,如果不能主動(dòng)去熟悉該算法恨旱,應(yīng)該感到臉紅。本文是一篇翻譯的文章仑氛,原文鏈接是:http://mccormickml.com/2016/04/19/word2vec-tutorial-the-skip-gram-model/
如果你的英語(yǔ)很好乙埃,強(qiáng)烈建議直接閱讀原文。這篇文章寫(xiě)的非常好调衰,簡(jiǎn)明扼要膊爪,語(yǔ)言流暢。是我認(rèn)為入門(mén)word2vector的最好文章嚎莉,沒(méi)有之一米酬。當(dāng)然,我也不是生硬的翻譯趋箩,而是理解之后按照自己的邏輯再寫(xiě)出來(lái)赃额,希望能更加清晰一些加派。歡迎在評(píng)論中說(shuō)出你的看法,多多交流跳芳。word2vector常見(jiàn)的有兩種算法CBOW和skip gram芍锦,本文使用skip gram算法作為講解對(duì)象。
一飞盆、算法的基本思想
word2vector娄琉,顧名思義,就是將語(yǔ)料庫(kù)中的詞轉(zhuǎn)化成向量吓歇,以便后續(xù)在詞向量的基礎(chǔ)上進(jìn)行各種計(jì)算孽水。最常見(jiàn)的表示方法是counting 編碼。假設(shè)我們的語(yǔ)料庫(kù)中是如下三句話:
I like deep learning
I like NLP
I enjoy flying
利用counting編碼城看,我們可以繪出如下矩陣:
假設(shè)語(yǔ)料庫(kù)中的單詞數(shù)量是N女气,則上圖矩陣的大小就是N*N,其中的每一行就代表一個(gè)詞的向量表示测柠。如第一行
0 2 1 0 0 0 0
是單詞I的向量表示炼鞠。其中的2代表I這個(gè)單詞與like這個(gè)詞在語(yǔ)料庫(kù)中共同出現(xiàn)了2次。
似乎我們很簡(jiǎn)單就完成了“word2vector”是不是轰胁?
但是這種辦法至少有三個(gè)缺陷:
- 1是詞語(yǔ)數(shù)量較大時(shí)谒主,向量維度高且稀疏,向量矩陣巨大而難以存儲(chǔ)
- 2是向量并不包含單詞的語(yǔ)義內(nèi)容软吐,只是基于數(shù)量統(tǒng)計(jì)瘩将。
- 3是當(dāng)有新的詞加入語(yǔ)料庫(kù)后,整個(gè)向量矩陣需要更新
盡管我們可以通過(guò)SVD來(lái)降低向量的維度凹耙,但是SVD本身卻是一個(gè)需要巨大計(jì)算量的操作姿现。
很明顯,這種辦法在實(shí)際中并不好用肖抱。我們今天學(xué)習(xí)的skip gram算法可以成功克服以上三個(gè)缺陷备典。它的基本思想是首先將所有詞語(yǔ)進(jìn)行one-hot編碼,輸入只有一個(gè)隱藏層的神經(jīng)網(wǎng)絡(luò)意述,定義好loss后進(jìn)行訓(xùn)練提佣,后面我們會(huì)講解如何定義loss,這里暫時(shí)按下不表荤崇。訓(xùn)練完成后拌屏,我們就可以用隱藏層的權(quán)重來(lái)作為詞的向量表示!术荤!
這個(gè)思想乍聽(tīng)起來(lái)很神奇是不是倚喂?其實(shí)我們?cè)缇褪煜に恕uto-encoder時(shí)瓣戚,我們也是用有一個(gè)隱藏層的神經(jīng)網(wǎng)絡(luò)進(jìn)行訓(xùn)練端圈,訓(xùn)練完成后焦读,丟去后面的output層,只用隱藏層的輸出作為最終需要的向量對(duì)象舱权,藉此成功完成向量的壓縮矗晃。
二、舉例說(shuō)明
1 構(gòu)造訓(xùn)練數(shù)據(jù)
假設(shè)我們的語(yǔ)料庫(kù)中只有一句話:
The quick brown fox jumps over the lazy dog.
這句話中共有8個(gè)詞(這里The與the算同一個(gè)詞)宴倍。
skip gram算法是怎么為這8個(gè)詞生成詞向量的呢张症?
我們知道用神經(jīng)網(wǎng)絡(luò)訓(xùn)練,大體有如下幾個(gè)步驟:
- 準(zhǔn)備好data啊楚,即X和Y
- 定義好網(wǎng)絡(luò)結(jié)構(gòu)
- 定義好loss
- 選擇合適的優(yōu)化器
- 進(jìn)行迭代訓(xùn)練
- 存儲(chǔ)訓(xùn)練好的網(wǎng)絡(luò)
所以吠冤,我們下面先來(lái)關(guān)注下如何確定X和Y的形式。
其實(shí)非常簡(jiǎn)單恭理,(x,y)就是一個(gè)個(gè)的單詞對(duì)。比如(the郭变,quick)就是一個(gè)單詞對(duì)颜价,the就是樣本數(shù)據(jù),quick就是該條樣本的標(biāo)簽诉濒。
那么周伦,如何從上面那句話中生成單詞對(duì)數(shù)據(jù)呢?答案就是n-gram方法未荒。多說(shuō)不如看圖:
我們以詞為單位掃描這句話专挪,每掃描到一個(gè)詞,都把該詞左右各兩個(gè)詞共4個(gè)詞拿出來(lái)片排,分別與被掃描的單詞組成單詞對(duì)寨腔,作為我們的訓(xùn)練數(shù)據(jù)。
這里有兩個(gè)細(xì)節(jié)率寡,一個(gè)就是取被掃描單詞左右各2個(gè)詞迫卢,這里的2被稱為窗口尺寸,是可以調(diào)整的冶共,用多大的窗口生成的單詞對(duì)來(lái)訓(xùn)練最好乾蛤,需要具體問(wèn)題具體分析。一般來(lái)說(shuō)捅僵,取5是很好的經(jīng)驗(yàn)值家卖。也就是左右各取5個(gè)單詞,共10個(gè)單詞庙楚。這里我們用2只是為了方便說(shuō)明問(wèn)題上荡。
第二個(gè)細(xì)節(jié)就是句子頭尾的單詞被掃描時(shí),其能取的單詞對(duì)數(shù)要少幾個(gè)醋奠,這個(gè)不影響大局榛臼,不用理會(huì)伊佃。
這里我們需要停下來(lái)細(xì)細(xì)琢磨下,我們這樣取單詞對(duì)作為訓(xùn)練數(shù)據(jù)的目的何在沛善?以(fox航揉,jumps)為例,jumps可以理解為fox的上下文金刁,我們將fox輸入神經(jīng)網(wǎng)絡(luò)時(shí)帅涂,希望網(wǎng)絡(luò)能夠告訴我們,在語(yǔ)料庫(kù)的8個(gè)單詞中尤蛮,jumps是更可能出現(xiàn)在fox周?chē)摹?br>
你可能會(huì)想媳友,(fox,brown)也是一個(gè)單詞對(duì)产捞,它輸入神經(jīng)網(wǎng)絡(luò)后醇锚,豈不是希望神經(jīng)網(wǎng)絡(luò)告訴我們,在8個(gè)單詞中坯临,brown是更可能出現(xiàn)在fox周?chē)富#咳绻沁@樣,那么訓(xùn)練完成后的神經(jīng)網(wǎng)絡(luò)看靠,輸入fox赶促,它的輸出會(huì)是brown和jumps的哪一個(gè)呢?
答案是取決于(fox挟炬,brown)和(fox鸥滨,jumps)兩個(gè)單詞對(duì)誰(shuí)在訓(xùn)練集中出現(xiàn)的次數(shù)比較多,神經(jīng)網(wǎng)絡(luò)就會(huì)針對(duì)哪個(gè)單詞對(duì)按照梯度下降進(jìn)行更多的調(diào)整谤祖,從而就會(huì)傾向于預(yù)測(cè)誰(shuí)將出現(xiàn)在fox周?chē)?/p>
2數(shù)字化表示單詞對(duì)
上面我們獲得了許多單詞對(duì)作為訓(xùn)練數(shù)據(jù)婿滓,但是神經(jīng)網(wǎng)絡(luò)不能直接接收和輸出字符串形式的單詞對(duì),所以需要將單詞對(duì)轉(zhuǎn)化為數(shù)字的形式泊脐。方法也很簡(jiǎn)單空幻,就是用one-hot編碼,如下圖所示:
(the容客,quick)單詞對(duì)就表示成
【(1,0,0,0,0,0,0,0)秕铛,(0,1,0,0,0,0,0,0)】
這樣就可以輸入神經(jīng)網(wǎng)絡(luò)進(jìn)行訓(xùn)練了,當(dāng)我們將the輸入神經(jīng)網(wǎng)絡(luò)時(shí)缩挑,希望網(wǎng)絡(luò)也能輸出一個(gè)8維的向量但两,并且第二維盡可能接近1,其他維盡可能接近0供置。也就是讓神經(jīng)網(wǎng)絡(luò)告訴我們谨湘,quick更可能出現(xiàn)在the的周?chē).?dāng)然,我們還希望這8維向量所有位置的值相加為1紧阔,WHY?因?yàn)橄嗉訛?就可以認(rèn)為這個(gè)8維向量描述的是一個(gè)概率分布坊罢,正好我們的y值也是一個(gè)概率分布(一個(gè)位置為1,其他位置為0)擅耽,我們就可以用交叉熵來(lái)衡量神經(jīng)網(wǎng)絡(luò)的輸出與我們的label y的差異大小活孩,也就可以定義出loss了。什么乖仇,你不知道啥是交叉熵憾儒?請(qǐng)參考我的另一篇文章【機(jī)器學(xué)習(xí)面試之各種混亂的熵】,應(yīng)該不會(huì)讓你失望乃沙。
3定義網(wǎng)絡(luò)結(jié)構(gòu)
通過(guò)之前的敘述起趾,我們已經(jīng)基本知道神經(jīng)網(wǎng)絡(luò)應(yīng)該是什么樣子了,總結(jié)一下警儒,可以確定如下情況:
- 神經(jīng)網(wǎng)絡(luò)的輸入應(yīng)該是8維的向量
- 神經(jīng)網(wǎng)絡(luò)只有一個(gè)隱藏層
-
神經(jīng)網(wǎng)絡(luò)的輸出應(yīng)該是一個(gè)8維向量训裆,且各維的值相加為1
有了這些信息,我們可以很容易定義出如下的網(wǎng)絡(luò)結(jié)構(gòu):
觀察這個(gè)網(wǎng)絡(luò)結(jié)構(gòu)冷蚂,我們可以發(fā)現(xiàn)缭保,它的隱藏層并沒(méi)有激活函數(shù),但是輸出層卻用了softmax蝙茶,這是為了保證輸出的向量是一個(gè)概率分布。
3 隱藏層
顯然诸老,輸出層的神經(jīng)元應(yīng)該是8個(gè)隆夯,這樣才能輸出一個(gè)8維的向量。那么隱藏層的神經(jīng)元應(yīng)該是多少别伏?
這取決于我們希望得到的詞向量是多少維蹄衷,有多少個(gè)隱藏神經(jīng)元詞向量就是多少維。每一個(gè)隱藏的神經(jīng)元接收的輸入都是一個(gè)8維向量厘肮,假設(shè)我們的隱藏神經(jīng)元有3個(gè)(僅僅是為了舉例說(shuō)明使用愧口,實(shí)際中,google推薦的是300個(gè)类茂,但具體多少合適耍属,需要你自己進(jìn)行試驗(yàn),怎么效果好怎么來(lái))巩检,如此以來(lái)厚骗,隱藏層的權(quán)重就可以用一個(gè)8行3列的矩陣來(lái)表示,這個(gè)8行3列的矩陣的第一行,就是三個(gè)隱藏神經(jīng)元對(duì)應(yīng)于輸入向量第一維的權(quán)重兢哭,如下圖所示:
下面就是見(jiàn)證奇跡的時(shí)刻领舰!
網(wǎng)絡(luò)訓(xùn)練完成后,這個(gè)8行3列的矩陣的每一行就是一個(gè)單詞的詞向量!如下圖所示:
so冲秽,訓(xùn)練完成后舍咖,我們只需要保存好隱藏層的權(quán)重矩陣即可,輸出層此時(shí)已經(jīng)完成歷史使命锉桑,可以丟掉了排霉。
那么怎么使用去掉了輸出層的網(wǎng)絡(luò)呢?
我們知道刨仑,網(wǎng)絡(luò)的輸入是one-hot編碼的單詞郑诺,它與隱藏層權(quán)重矩陣相乘實(shí)際上是取權(quán)重矩陣特定的行,如下圖所示:
這意味著杉武,隱藏層實(shí)際上相當(dāng)于是一個(gè)查找表辙诞,它的輸出就是輸入的單詞的詞向量。
4輸出層
當(dāng)我們從隱藏層獲得一個(gè)單詞的詞向量后轻抱,就要經(jīng)過(guò)輸出層了飞涂。
輸出層的神經(jīng)元數(shù)量和語(yǔ)料庫(kù)中的單詞數(shù)量一樣。每一個(gè)神經(jīng)元可以認(rèn)為對(duì)應(yīng)一個(gè)單詞的輸出權(quán)重祈搜,詞向量乘以該輸出權(quán)重就得到一個(gè)數(shù)较店,該數(shù)字代表了輸出神經(jīng)元對(duì)應(yīng)的單詞出現(xiàn)在輸入單詞周?chē)目赡苄源笮。ㄟ^(guò)對(duì)所有的輸出層神經(jīng)元的輸出進(jìn)行softmax操作容燕,我們就把輸出層的輸出規(guī)整為一個(gè)概率分布了梁呈。如下圖所示:
這里有一點(diǎn)需要注意,我們說(shuō)輸出的是該單詞出現(xiàn)在輸入單詞周?chē)母怕蚀笮≌好兀@個(gè)“周?chē)卑瑔卧~的前面官卡,也包含單詞的后面。
三醋虏、直覺(jué)的啟示
前面寻咒,我們表示,skip gram算法生成的詞向量可以包含語(yǔ)義信息颈嚼,也就是說(shuō)毛秘,語(yǔ)義相近的詞其詞向量也相近。這里阻课,我們給一個(gè)直覺(jué)的解釋叫挟。
首先,語(yǔ)義相近的詞往往有著類(lèi)似的上下文柑肴。這是什么意思呢霞揉?舉例來(lái)說(shuō),“聰明”和“伶俐”兩個(gè)詞語(yǔ)義是相近的晰骑,那么它們的使用場(chǎng)景也是相似的适秩,它們周?chē)脑~很大程度上是相近或相同的绊序。
語(yǔ)義相近的詞有著相似的上下文,讓我們的神經(jīng)網(wǎng)絡(luò)在訓(xùn)練過(guò)程中對(duì)相近的詞產(chǎn)生相近的輸出向量秽荞。網(wǎng)絡(luò)如何做到這一點(diǎn)呢骤公?答案就是訓(xùn)練完成后,網(wǎng)絡(luò)能夠?qū)φZ(yǔ)義相近的詞產(chǎn)生相近的詞向量扬跋。因?yàn)榇藭r(shí)的輸出層已經(jīng)訓(xùn)練完成阶捆,不會(huì)改變了。
這個(gè)直覺(jué)式的思考顯然是不嚴(yán)謹(jǐn)?shù)那仗珔s能讓我們對(duì)神經(jīng)網(wǎng)絡(luò)有很好的洞見(jiàn)洒试。
記得李宏毅說(shuō)過(guò),有人問(wèn)朴上,LSTM設(shè)計(jì)那么復(fù)雜垒棋,設(shè)計(jì)的人怎么知道這樣的結(jié)構(gòu)就能達(dá)到記憶的效果呢?事實(shí)上痪宰,不是知道這樣做會(huì)有記憶的效果才去這樣做叼架,而是這樣做了,才有這樣的效果衣撬。是不是有點(diǎn)雞生蛋蛋生雞的趕腳乖订?這就是為什么深度學(xué)習(xí)被稱為玄學(xué)的原因吧。
四具练、下篇預(yù)告
你可能注意到了乍构,skip-gram算法構(gòu)造的神經(jīng)網(wǎng)絡(luò)神經(jīng)元太多了,導(dǎo)致權(quán)重矩陣非常大扛点。 假設(shè)我們的語(yǔ)料庫(kù)中的詞有10000個(gè)蜡吧,生成的詞向量為300維。那么權(quán)重系數(shù)就有10000*300*2那么多占键,訓(xùn)練如此巨大的網(wǎng)絡(luò)難度很大。下一篇文章中會(huì)介紹一些小技巧元潘,幫助我們減小訓(xùn)練的難度畔乙,使得訓(xùn)練是可行的。