深度學習word2vec筆記之基礎篇算法篇應用篇--寫的非常到位


深度學習word2vec
筆記之基礎篇


  聲明:

1)該博文是多位博主以及多位文檔資料的主人所無私奉獻的論文資料整理的。具體引用的資料請看參考文獻。具體的版本聲明也參考原文獻

2)本文僅供學術交流,非商用。所以每一部分具體的參考資料並沒有詳細對應,更有些部分本來就是直接從其他博客複製過來的。如果某部分不小心侵犯了大家的利益,還望海涵,並聯系老衲刪除或修改,直到相關人士滿意爲止。

3)本人才疏學淺,整理總結的時候難免出錯,還望各位前輩不吝指正,謝謝。

4)閱讀本文需要機器學習、語言模型等等基礎(如果沒有也沒關係了,沒有就看看,當做跟同學們吹牛的本錢)。

5)本人對語言模型也是新人,中間有些結論未必是正確的,各位如有發現,請指出,本人會盡量改正,避免誤導讀者。
6)此屬於第一版本,若有錯誤,還需繼續修正與增刪。還望大家多多指點。請直接回帖,本人來想辦法處理。
7)本人手上有word版的和pdf版的,已上傳到csdn,下載url:http://download.csdn.net/detail/mytestmy/8565955,或者http://download.csdn.net/detail/mytestmy/8565959,資源分1分,評論後據說可以返還的,就有勞各位幫忙攢點分吧。如果有必要可以回覆或者發郵件到郵箱[email protected],將按各位需求回覆。

一.前言

伴隨着深度學習的大紅大紫,只要是在自己的成果裏打上deep learning字樣,總會有人去看。深度學習可以稱爲當今機器學習領域的當之無愧的巨星,也特別得到工業界的青睞。

在各種大舉深度學習大旗的公司中,Google公司無疑是旗舉得最高的,口號喊得最響亮的那一個。2013年末,Google發佈的word2vec工具引起了一幫人的熱捧,大家幾乎都認爲它是深度學習在自然語言領域的一項了不起的應用,各種歡呼“深度學習在自然語言領域開始發力了”。

互聯網界很多公司也開始跟進,使用word2vec產出了不少成果。身爲一個互聯網民工,有必要對這種炙手可熱的技術進行一定程度的理解。

好在word2vec也算是比較簡單的,只是一個簡單三層神經網絡。在瀏覽了多位大牛的博客,隨筆和筆記後,整理成自己的博文,或者說抄出來自己的博文。

二.背景知識

2.1詞向量

自然語言處理(NLP)相關任務中,要將自然語言交給機器學習中的算法來處理,通常需要首先將語言數學化,因爲機器不是人,機器只認數學符號。向量是人把自然界的東西抽象出來交給機器處理的東西,基本上可以說向量是人對機器輸入的主要方式了。

詞向量就是用來將語言中的詞進行數學化的一種方式,顧名思義,詞向量就是把一個詞表示成一個向量。

主要有兩種表示方式,下面分別介紹,主要參考了@皮果提在知乎上的問答,也就是參考文獻【2】。

2.1.1 One-Hot Representation

 

一種最簡單的詞向量方式是 one-hotrepresentation,就是用一個很長的向量來表示一個詞,向量的長度爲詞典的大小,向量的分量只有一個 1,其他全爲 0, 1 的位置對應該詞在詞典中的位置。舉個例子,

  “話筒”表示爲 [0 0 0 1 00 0 0 0 0 0 0 0 0 0 0 ...]

  “麥克”表示爲 [0 0 0 0 00 0 0 1 0 0 0 0 0 0 0 ...]

每個詞都是茫茫 0 海中的一個 1。

這種 One-hotRepresentation 如果採用稀疏方式存儲,會是非常的簡潔:也就是給每個詞分配一個數字 ID。比如剛纔的例子中,話筒記爲 3,麥克記爲 8(假設從 0 開始記)。如果要編程實現的話,用 Hash 表給每個詞分配一個編號就可以了。這麼簡潔的表示方法配合上最大熵、SVM、CRF 等等算法已經很好地完成了 NLP 領域的各種主流任務。

但這種詞表示有兩個缺點:(1)容易受維數災難的困擾,尤其是將其用於 Deep Learning 的一些算法時;(2)不能很好地刻畫詞與詞之間的相似性(術語好像叫做“詞彙鴻溝”):任意兩個詞之間都是孤立的。光從這兩個向量中看不出兩個詞是否有關係,哪怕是話筒和麥克這樣的同義詞也不能倖免於難。

所以會尋求發展,用另外的方式表示,就是下面這種。

2.1.2 Distributed Representation

另一種就是DistributedRepresentation 這種表示,它最早是 Hinton 於 1986 年提出的,可以克服 one-hot representation 的缺點。其基本想法是直接用一個普通的向量表示一個詞,這種向量一般長成這個樣子:[0.792, −0.177, −0.107, 0.109, −0.542, ...],也就是普通的向量表示形式。維度以 50 維和 100 維比較常見。

當然一個詞怎麼表示成這麼樣的一個向量是要經過一番訓練的,訓練方法較多,word2vec是其中一種,在後面會提到,這裏先說它的意義。還要注意的是每個詞在不同的語料庫和不同的訓練方法下,得到的詞向量可能是不一樣的。

詞向量一般維數不高,很少有人閒着沒事訓練的時候定義一個10000維以上的維數,所以用起來維數災難的機會現對於one-hot representation表示就大大減少了。

由於是用向量表示,而且用較好的訓練算法得到的詞向量的向量一般是有空間上的意義的,也就是說,將所有這些向量放在一起形成一個詞向量空間,而每一向量則爲該空間中的一個點,在這個空間上的詞向量之間的距離度量也可以表示對應的兩個詞之間的“距離”。所謂兩個詞之間的“距離”,就是這兩個詞之間的語法,語義之間的相似性。

一個比較爽的應用方法是,得到詞向量後,假如對於某個詞A,想找出這個詞最相似的詞,這個場景對人來說都不輕鬆,畢竟比較主觀,但是對於建立好詞向量後的情況,對計算機來說,只要拿這個詞的詞向量跟其他詞的詞向量一一計算歐式距離或者cos距離,得到距離最小的那個詞,就是它最相似的。

這樣的特性使得詞向量很有意義,自然就會吸引比較多的人去研究,前有Bengio發表在JMLR上的論文《A Neural Probabilistic Language Model》,又有Hinton的層次化Log-Bilinear模型,還有google的TomasMikolov 團隊搞的word2vec,等等。

詞向量在機器翻譯領域的一個應用,就是google的TomasMikolov 團隊開發了一種詞典和術語表的自動生成技術,該技術通過向量空間,把一種語言轉變成另一種語言,實驗中對英語和西班牙語間的翻譯準確率高達90%。

介紹算法工作原理的時候舉了一個例子:考慮英語和西班牙語兩種語言,通過訓練分別得到它們對應的詞向量空間 E 和 S。從英語中取出五個詞 one,two,three,four,five,設其在 E 中對應的詞向量分別爲 v1,v2,v3,v4,v5,爲方便作圖,利用主成分分析(PCA)降維,得到相應的二維向量 u1,u2,u3,u4,u5,在二維平面上將這五個點描出來,如下圖左圖所示。類似地,在西班牙語中取出(與 one,two,three,four,five 對應的) uno,dos,tres,cuatro,cinco,設其在 S 中對應的詞向量分別爲 s1,s2,s3,s4,s5,用 PCA 降維後的二維向量分別爲 t1,t2,t3,t4,t5,將它們在二維平面上描出來(可能還需作適當的旋轉),如下圖右圖所示:


觀察左、右兩幅圖,容易發現:五個詞在兩個向量空間中的相對位置差不多,這說明兩種不同語言對應向量空間的結構之間具有相似性,從而進一步說明了在詞向量空間中利用距離刻畫詞之間相似性的合理性。


2.2語言模型

2.2.1基本概念

語言模型其實就是看一句話是不是正常人說出來的。這玩意很有用,比如機器翻譯、語音識別得到若干候選之後,可以利用語言模型挑一個儘量靠譜的結果。在 NLP 的其它任務裏也都能用到。

語言模型形式化的描述就是給定一個T個詞的字符串s,看它是自然語言的概率P(w1,w2,…,wt)。w1 到 wT 依次表示這句話中的各個詞。有個很簡單的推論是:

  {\rm{p}}\left( s \right) = {\rm{p}}\left( {{w_1},{w_2}, \cdots {w_T}} \right)   = {\rm{p}}\left( {{w_1}} \right){\rm{p(}}{w_2}{\rm{|}}{w_1}){\rm{p}}({w_3}|{w_1},{w_2}) \cdots {\rm{p}}({w_t}|{w_1},{w_2}, \cdots {w_{T - 1}})             (1)

上面那個概率表示的意義是:第一個詞確定後,看後面的詞在前面的詞出現的情況下出現的概率。如一句話“大家喜歡喫蘋果”,總共四個詞“大家”,“喜歡”,“喫”,“蘋果”,怎麼分詞現在不討論,總之詞已經分好,就這四個。那麼這句話是一個自然語言的概率是:

P(大家,喜歡,喫,蘋果)=p(大家)p(喜歡|大家)p(喫|大家,喜歡)p(蘋果|大家,喜歡,喫)

p(大家)表示“大家”這個詞在語料庫裏面出現的概率;

p(喜歡|大家)表示“喜歡”這個詞出現在“大家”後面的概率;

p(喫|大家,喜歡)表示“喫”這個詞出現在“大家喜歡”後面的概率;

p(蘋果|大家,喜歡,喫)表示“蘋果”這個詞出現在“大家喜歡喫”後面的概率。

把這些概率連乘起來,得到的就是這句話平時出現的概率。

如果這個概率特別低,說明這句話不常出現,那麼就不算是一句自然語言,因爲在語料庫裏面很少出現。如果出現的概率高,就說明是一句自然語言。

看到了上面的計算,看有多麻煩:只有四個詞的一句話,需要計算的是p(大家),p(喜歡|大家),p(喫|大家,喜歡),p(蘋果|大家,喜歡,喫)這四個概率,這四個概率還要預先計算好,考慮詞的數量,成千上萬個,再考慮組合數,p(喫|大家,喜歡)這個有“大家”、“喜歡”和“喫”的組合,總共會上億種情況吧;再考慮p(蘋果|大家,喜歡,喫)這個概率,總共也會超過萬億種。

從上面的情況看來,計算起來是非常麻煩的,一般都用偷懶的方式。

爲了表示簡單,上面的公式(1)用下面的方式表示

{\rm{p}}\left( {\rm{s}} \right) = {\rm{p}}\left( {{w_1},{w_2}, \cdots {w_T}} \right) =  \prod \limits_{i = 1}^T p({w_i}|Contex{t_i})

其中,如果Contexti是空的話,就是它自己p(w),另外如“喫”的Context就是“大家”、“喜歡”,其餘的對號入座。

符號搞清楚了,就看怎麼偷懶了。

2.2.2 N-gram模型

接下來說怎麼計算p({w_i}|Contex{t_i}),上面看的是跟據這句話前面的所有詞來計算,那麼就得計算很多了,比如就得把語料庫裏面p(蘋果|大家,喜歡,喫)這種情況全部統計一遍,那麼爲了計算這句話的概率,就上面那個例子,都得掃描四次語料庫。這樣一句話有多少個詞就得掃描多少趟,語料庫一般都比較大,越大的語料庫越能提供準確的判斷。這樣的計算速度在真正使用的時候是萬萬不可接受的,線上掃描一篇文章是不是一推亂七八糟的沒有序列的文字都得掃描很久,這樣的應用根本沒人考慮。

最好的辦法就是直接把所有的p({w_i}|Contex{t_i})提前算好了,那麼根據排列組上面的來算,對於一個只有四個詞的語料庫,總共就有4!+3!+2!+1!個情況要計算,那就是24個情況要計算;換成1000個詞的語料庫,就是 \sum \limits_{i = 1}^{1000} i!個情況需要統計,對於計算機來說,計算這些東西簡直是開玩笑。

這就誕生了很多偷懶的方法,N-gram模型是其中之一了。N-gram什麼情況呢?上面的context都是這句話中這個詞前面的所有詞作爲條件的概率,N-gram就是隻管這個詞前面的n-1個詞,加上它自己,總共n個詞,計算p({w_i}|Contex{t_i})只考慮用這n個詞來算,換成數學的公式來表示,就是

{\rm{p}}\left( {{w_i}{\rm{|}}Contex{t_i}} \right) = {\rm{p}}({w_i}|{w_{i - n + 1}},{w_{i - n + 2}}, \cdots ,{w_{i - 1}})

這裏如果n取得比較小的話,就比較省事了,當然也要看到n取得太小,會特別影響效果的,有可能計算出來的那個概率很不準。怎麼平衡這個效果和計算就是大牛們的事情了,據大牛們的核算,n取2效果都還湊合,n取3就相當不錯了,n取4就頂不住了。看下面的一些數據,假設詞表中詞的個數 |V| = 20,000 詞,那麼有下面的一些數據。


照圖中的數據看去,取n=3是目前計算能力的上限了。在實踐中用的最多的就是bigram和trigram了,而且效果也基本夠了。

N-gram模型也會有寫問題,總結如下:

1、n不能取太大,取大了語料庫經常不足,所以基本是用降級的方法

2、無法建模出詞之間的相似度,就是有兩個詞經常出現在同一個context後面,但是模型是沒法體現這個相似性的。

3、有些n元組(n個詞的組合,跟順序有關的)在語料庫裏面沒有出現過,對應出來的條件概率就是0,這樣一整句話的概率都是0了,這是不對的,解決的方法主要是兩種:平滑法(基本上是分子分母都加一個數)和回退法(利用n-1的元組的概率去代替n元組的概率)

2.2.3N-pos模型

當然學術是無止境的,有些大牛覺得這還不行,因爲第i個詞很多情況下是條件依賴於它前面的詞的語法功能的,所以又弄出來一個n-pos模型,n-pos模型也是用來計算的,但是有所改變,先對詞按照詞性(Part-of-Speech,POS)進行了分類,具體的數學表達是

{\rm{p}}\left( {{w_i}{\rm{|}}Contex{t_i}} \right) = {\rm{p}}\left( {{w_i}|{\rm{c}}\left( {{w_{i - n + 1}}} \right),{\rm{c}}\left( {{w_{i - n + 2}}} \right), \cdots ,{\rm{c}}\left( {{w_{i - 1}}} \right)} \right)

其中c是類別映射函數,功能是把V個詞映射到K個類別(1=<K<=V)。這樣搞的話,原來的V個詞本來有{V^n}種n元組減少到了{\rm{V}} \times {{\rm{K}}^{n - 1}}種。

其他的模型還很多,不一一介紹了。

2.2.4模型的問題與目標

如果是原始的直接統計語料庫的語言模型,那是沒有參數的,所有的概率直接統計就得到了。但現實往往會帶一些參數,所有語言模型也能使用極大似然作爲目標函數來建立模型。下面就討論這個。

假設語料庫是一個由T個詞組成的詞序列s(這裏可以保留疑問的,因爲從很多資料看來是不管什麼多少篇文檔,也不管句子什麼的,整個語料庫就是一長串詞連起來的,或許可以根據情況拆成句子什麼的,這裏就往簡單裏說),其中有V個詞,則可以構建下面的極大似然函數

{\rm{L}} =  \prod \limits_{i = 1}^T p\left( {{w_i}{\rm{|}}Contex{t_i}} \right)

另外,做一下對數似然

{\rm{l}} = {\rm{logL}} = \frac{1}{V} \sum \limits_{i = 1}^T logp\left( {{w_i}{\rm{|}}Contex{t_i}} \right)

對數似然還有些人稱爲交叉熵,這裏不糾結也不介紹。

上面的問題跟正常的情況不太符合,來看看下一種表達。假設語料庫是有S個句子組成的一個句子序列(順序不重要),同樣是有V個詞,似然函數就會構建成下面的樣子

{\rm{L}} =  \prod \limits_j^{\rm{S}} \left( { \prod \limits_{{i_j} = 1}^{{T_j}} p\left( {{w_{{i_j}}}{\rm{|}}Contex{t_{{i_j}}}} \right)} \right)

對數似然就會是下面的樣子

{\rm{l}} = {\rm{logL}} = \frac{1}{V} \sum \limits_{j = 1}^{\rm{S}} \left( { \sum \limits_{{i_j} = 1}^{{T_j}} logp\left( {{w_{{i_j}}}{\rm{|}}Contex{t_{{i_j}}}} \right)} \right)

有意向的同學可以擴展到有文檔的樣子,這裏就不介紹了。

爲啥要注意這個問題呢?原因有多種,計算p({w_i}|Contex{t_i})這個東西的參數是主要的原因。

爲啥會有參數呢?在計算p({w_i}|Contex{t_i})這個東西的過程中,有非常多的方法被開發出來了,如上面的平滑法,回退法上面的,但這些都是硬統計一下基本就完了;這就帶來一些需要求的參數,如平滑法中使用的分子分母分別加上的常數是什麼?

這還不夠,假如用的是trigram,還得存儲一個巨大的元組與概率的映射(如果不存儲,就得再進行使用的時候實際統計,那太慢了),存這個東西可需要很大的內存,對計算機是個大難題。

這都難不倒大牛們,他們考慮的工作是利用函數來擬合計算p({w_i}|Contex{t_i}),換句話說,不是根據語料庫統計出來的,而是直接把context和wi代到一個函數裏面計算出來的,這樣在使用的時候就不用去查那個巨大的映射集了(或者取語料庫裏面統計這個概率)。用數學的方法描述就是

p\left( {{w_i}{\rm{|}}Contex{t_i}} \right) = {\rm{f}}\left( {{w_i},Contex{t_i};{\rm{\theta }}} \right)

這樣的工作也體現了科學家們的價值——這幫人終於有點東西可以忙了。

那麼探索這個函數的具體形式就是主要的工作了,也是後面word2vec的工作的主要內容。函數的形式實在太多了,線性的還好,非線性真叫一個多,高維非線性的就更多了。

探索一個函數的具體形式的術語叫做擬合。

然後就有人提出了用神經網絡來擬合這個函數,就有了各種方法,word2vec是其中的一種。


致謝

多位Google公司的研究員無私公開的資料。

多位博主的博客資料。


參考文獻

[1]http://techblog.youdao.com/?p=915  Deep Learning實戰之word2vec,網易有道的pdf

[2] http://www.zhihu.com/question/21714667/answer/19433618 @皮果提在知乎上的問答

[3]http://www.zhihu.com/question/21661274/answer/19331979  @楊超在知乎上的問答《Word2Vec的一些理解》

[4] ​第​五​章​ ​n​-​g​r​a​m​語​言​模​型  百度文庫上的一個資料

[5] 主題:統計自然語言處理的數學基礎  百度文庫上的一個資料






深度學習word2vec筆記之算法篇

聲明:

1)該博文是Google專家以及多位博主所無私奉獻的論文資料整理的。具體引用的資料請看參考文獻。具體的版本聲明也參考原文獻

2)本文僅供學術交流,非商用。所以每一部分具體的參考資料並沒有詳細對應,更有些部分本來就是直接從其他博客複製過來的。如果某部分不小心侵犯了大家的利益,還望海涵,並聯系老衲刪除或修改,直到相關人士滿意爲止。

3)本人才疏學淺,整理總結的時候難免出錯,還望各位前輩不吝指正,謝謝。

4)閱讀本文需要機器學習、概率統計算法等等基礎(如果沒有也沒關係了,沒有就看看,當做跟同學們吹牛的本錢),基礎篇url:http://blog.csdn.net/mytestmy/article/details/26961315 。

5)此屬於第一版本,若有錯誤,還需繼續修正與增刪。還望大家多多指點。請直接回帖,本人來想辦法處理。

6)word版的和pdf版的文檔已上傳到csdn,下載url:http://download.csdn.net/detail/mytestmy/8565955,或者http://download.csdn.net/detail/mytestmy/8565959,資源分1分,評論後據說可以返還的,就有勞各位幫忙攢點分吧。如果有必要可以回覆或者發郵件到郵箱:[email protected]


前言

在看word2vec的資料的時候,經常會被叫去看那幾篇論文,而那幾篇論文也沒有系統地說明word2vec的具體原理和算法,所以老衲就斗膽整理了一個筆記,希望能幫助各位儘快理解word2vec的基本原理,避免浪費時間。

當然如果已經瞭解了,就隨便看看得了。


一. CBOW加層次的網絡結構與使用說明

Word2vec總共有兩種類型,每種類型有兩個策略,總共4種。這裏先說最常用的一種。這種的網絡結構如下圖。

其中第一層,也就是最上面的那一層可以稱爲輸入層。輸入的是若干個詞的詞向量(詞向量的意思就是把一個詞表示成一個向量的形式表達,後面會介紹)。中間那個層可以成爲隱層,是輸入的若干個詞向量的累加和,注意是向量的累加和,結果是一個向量。
第三層是方框裏面的那個二叉樹,可以稱之爲輸出層,隱層的那個節點要跟輸出層的那個二叉樹的所有非葉節點鏈接的,線太多畫不過來了。第三層的這個二叉樹是一個霍夫曼樹,每個非葉節點也是一個向量,但是這個向量不代表某個詞,代表某一類別的詞;每個葉子節點代表一個詞向量,爲了簡單隻用一個w表示,沒有下標。另外要注意的是,輸入的幾個詞向量其實跟這個霍夫曼樹中的某幾個葉子節點是一樣的,當然輸入的那幾個詞跟它們最終輸出的到的那個詞未必是同一個詞,而且基本不會是同一個詞,只是這幾個詞跟輸出的那個詞往往有語義上的關係。
還有要注意的是,這個霍夫曼樹的所有葉子節點就代表了語料庫裏面的所有詞,而且是每個葉子節點對應一個詞,不重複。
這個網絡結構的功能是爲了完成一個的事情——判斷一句話是否是自然語言。怎麼判斷呢?使用的是概率,就是計算一下這句話的“一列詞的組合”的概率的連乘(聯合概率)是多少,如果比較低,那麼就可以認爲不是一句自然語言,如果概率高,就是一句正常的話。這個其實也是語言模型的目標。前面說的“一列詞的組合”其實包括了一個詞跟它的上下文的聯合起來的概率,一種普通的情況就是每一個詞跟它前面所有的詞的組合的概率的連乘,這個後面介紹。
對於上面的那個網絡結構來說,網絡訓練完成後,假如給定一句話s,這句話由詞w1,w2,w3,…,wT組成,就可以利用計算這句話是自然語言的概率了,計算的公式是下面的公式

其中的Context表示的是該詞的上下文,也就是這個詞的前面和後面各若干個詞,這個“若干”(後面簡稱c)一般是隨機的,也就是一般會從1到5之間的一個隨機數;每個p({w_i}|Contex{t_i})代表的意義是前後的c個詞分別是那幾個的情況下,出現該詞的概率。舉個例子就是:“大家 喜歡 喫 好喫 的 蘋果”這句話總共6個詞,假設對“喫”這個詞來說c隨機抽到2,則“喫”這個詞的context是“大家”、“喜歡”、“好喫”和“的”,總共四個詞,這四個詞的順序可以亂,這是word2vec的一個特點。
計算p({w_i}|Contex{t_i})的時候都要用到上面的那個網絡,具體計算的方法用例子說明,假設就是計算“喫”這個詞的在“大家”、“喜歡”、“好喫”和“的”這四個詞作爲上下文的條件概率,又假設“喫”這個詞在霍夫曼樹中是的最右邊那一個葉子節點,那麼從根節點到到達它就有兩個非葉節點,根節點對應的詞向量命名爲A,根節點的右孩子節點對應的詞向量命名爲B,另外再假設“大家”、“喜歡”、“好喫”和“的”這四個詞的詞向量的和爲C,則

其中{\rm{\sigma }}\left( {\rm{x}} \right) = 1/\left( {1 + {e^{ - x}}} \right),是sigmoid公式。爲什麼這麼算,看完後面就明白了,這裏僅僅說個流程,讓後面的描述流暢起來。要注意的是,如果“喫”這個詞在非葉節點B的左孩子節點(假設稱爲E)的右邊的那個葉子節點,也就是在圖中右邊的三個葉子的中間那個,則有

上面的那句話的每個詞都計算p({w_i}|Contex{t_i})後連乘起來得到聯合概率,這個概率如果大於某個閾值,就認爲是正常的話;否則就認爲不是自然語言,要排除掉。
對於這個神經網絡的描述索然無味,因爲主角也不是這個概率,這個神經網絡最重要的是輸出層的那個霍夫曼樹的葉子節點上的那些向量,那些向量被稱爲詞向量,詞向量就是另外一篇博文裏面介紹的,是個好東西。

怎麼得到這些詞向量更加是一個重要的過程,也是word2vec這整個算法最重要的東西,後面會認真介紹。

至於霍夫曼樹,其實是一個優化的解法,後面再提。


二.優化目標與解問題

2.1從霍夫曼樹到條件概率的計算

前面已經提過語言模型的目標就是判斷一句話是否是正常的,至於怎麼判斷則需要計算很多條件概率如p({w_i}|Contex{t_i}),然後還要把這些條件概率連乘起來得到聯合概率。這樣就帶來了問題了——怎麼去計算p({w_i}|Contex{t_i}),有很多辦法的,後面的章節會介紹。這裏的word2vec的計算這個條件概率的方法是利用神經網絡的能量函數,因爲在能量模型中,能量函數的功能是把神經網絡的狀態轉化爲概率表示,這在另外一篇博文RBM裏面有提到,具體要看hinton的論文來了解了。能量模型有個特別大的好處,就是能擬合所有的指數族的分佈。那麼,如果認爲這些條件概率是符合某個指數族的分佈的話,是可以用能量模型去擬合的。總之word2vec就認爲p({w_i}|Contex{t_i})這個條件概率可以用能量模型來表示了。
既然是能量模型,那麼就需要能量函數,word2vec定義了一個非常簡單的能量函數
E(A,C)=-(A∙C)
其中A可以認爲是某個詞的詞向量,C是這個詞的上下文的詞向量的和(向量的和),基本上就可以認爲C代表Context;中間的點號表示兩個向量的內積。
然後根據能量模型(這個模型假設了溫度一直是1,所以能量函數沒有分母了),就可以表示出詞A的在上下文詞向量C下的概率來了
                 (2.1.2)
其中V表示語料庫裏面的的詞的個數,這個定義的意思是在上下文C出現的情況下,中間這個詞是A的概率,爲了計算這個概率,肯定得把語料庫裏面所有的詞的能量都算一次,然後再根據詞A的能量,那個比值就是出現A的概率。這種計算概率的方式倒是能量模型裏面特有的,這個定義在論文《Hierarchical Probabilistic Neural Network Language Model》裏面,這裏拿來改了個形式。
這個概率其實並不好統計,爲了算一個詞的的概率,得算上這種上下文的情況下所有詞的能量,然後還計算指數值再加和。注意那個分母,對語料庫裏面的每個詞,分母都要算上能量函數,而且再加和,假如有V個詞彙,整個語料庫有W個詞,那麼一輪迭代中光計算分母就有W*V*D個乘法,如果詞向量維度是D的話。比如,語料庫有100000000個詞,詞彙量是10000,計算100維的詞向量,一輪迭代要〖10〗^14次乘法,計算機計算能力一般是〖10〗^9每秒,然後一輪迭代就要跑100000秒,大約27小時,一天多吧。1000輪迭代就三年了。
這時候科學家們的作用又體現了,假如把語料庫的所有詞分成兩類,分別稱爲G類和H類,每類一半,其中詞A屬於G類,那麼下面的式子就可以成立了
p(A│C)=p(A|G,C)p(G|C)                        (2.1.3)
這個式子的的含義算明確的了,詞A在上下文C的條件下出現的概率,與後面的這個概率相等——在上下文C的條件下出現了G類詞,同時在上下文爲C,並且應該出現的詞是G類詞的條件下,詞A出現的概率。
列出這麼一個式子在論文《Hierarchical Probabilistic Neural Network Language Model》裏面也有個證明的,看原始的情況
P(Y=y│X=x)=P(Y=y|D=d(y),X)P(D=d(y)|X=x)

其中d是一個映射函數,把Y裏面的元素映射到詞的類別D裏面的元素。還有個證明


式子(2.1.3)說明了一個問題,計算一個詞A在上下文C的情況下出現的概率,可以先對語料庫中的詞分成兩簇,然後能節省計算。現在來展示一下怎麼節省計算,假設G,H這兩類的簇就用G和H表示(G和H也是一個詞向量,意思就是G表示了其中一簇的詞,H表示了另外一簇的詞,G和H只是一個代表,也不是什麼簇中心的說法。其實如果情況極端點,只有兩個詞,看下面的式子就完全沒問題了。在多個詞的情況下,就可以認爲詞被分成了兩團,G和H個表示一團的詞,計算概率什麼的都以一整團爲單位),那麼式子(2.3)中的p(G|C)可以用下面的式子計算

也就是說,可以不用關心這兩個簇用什麼表示,只要利用一個F=H-G的類詞向量的一個向量就可以計算P(G|C)了,所以這一步是很節省時間的。再看另外一步

由於在G內的詞數量只有V/2個,也就是說計算分母的時候只要計算V/2個詞的能量就可以了。這已經省了一半的計算量了,可惜科學家們是貪得無厭的,所以還要繼續省,怎麼來呢?把G類詞再分成兩個簇GG,GH,A在GH裏面,然後
p(A│G,C)=p(A|GH,G,C)p(GH|G,C)
同樣有



同樣可以把GG-GH用一個類詞向量表達,這時候
p(A│C)=p(A|GH,G,C)p(GH|G,C)p(G|C)
繼續下去假設繼續分到GHG簇的時候只剩兩個詞了,再分兩簇爲GHGG和GHGH,其中的簇GHGG就只有一個詞A,那麼p(A│C)可以用下面的式子算
p(A│C)=p(A│GHGG,GHG,GH,G,C)p(GHGG|GHG,GH,G,C)p(GHG|GH,G,C)p(GH|G,C)p(G|C)
其中p(A|GHGG,GHG,GH,G)是1,因爲只有一個單詞,代到公式(2.2)就可以得到,那麼就有
p(A│C)=p(GHGG|GHG,GH,G,C)p(GHG|GH,G,C)p(GH|G,C)p(G|C)
也就是

假設再令FFF=GHH-GHG,FF=GG-GH,F=H-G,那麼p(A|C)只要算這三個詞與上下文C的能量函數了,確實比原來的要節省很多計算的。
對於上面的霍夫曼樹來說假設G表示向右,H表示向左,那麼A就是從右邊開始數的第二個葉子節點,就是圖中右邊的三個W的中間那個。那麼F,FF,FFF就是這個葉子節點路徑上的三個非葉節點。
但是一個詞總是會一會向左,一會向右的,也就是在根節點那裏,一會是p(G|C)那麼F=H-G,一會又是p(H|C)那麼F=G-H,如果F在每個節點都是唯一一個值,就可以直接用一次詞向量表示這個非葉節點了。這下難不倒科學家的,令F一直是等於H-G,那麼一直有

並且有p(G|C)=1-p(H|C)。
這樣每個非葉節點就可以用唯一一個詞向量表示了。
看到這裏,總該明白爲啥p(A|C)要這麼算了吧。再換種情況,上面的概率這個概率的計算方法是不是也是同樣的道理?
總結下來,p({w_i}|Contex{t_i})可以用下面的公式計算了

其中C表示上下文的詞向量累加後的向量,qk表示從根節點下來到葉子節點的路徑上的那些非葉節點,dk就是編碼了,也可以說是分類,因爲在霍夫曼樹的每個非葉節點都只有兩個孩子節點,那可以認爲當wi在這個節點的左子樹的葉子節點上時dk=0,否則dk=1。這樣的話每個詞都可以用一組霍夫曼編碼來表示,就有了上面的那個式子中間的那個dk,整個p(w│Context)就可以用霍夫曼樹上的若干個非葉節點和詞w的霍夫曼編碼來計算了。

看到這務必想明白,因爲開始要討論怎麼訓練了。

2.1.1霍夫曼樹


上面輸出層的二叉樹是霍夫曼樹,其實並沒有要求是霍夫曼樹,隨便一個不太離譜的二叉樹都可以的,但是用霍夫曼樹能達到最優的計算效果。
根據之前的討論,已經知道了語料庫裏面每個詞都要從根節點下來,一直走到葉子節點,每經過一個非葉節點,就要計算一個sigmoid函數。
隨便亂分也能達到效果,但是信息熵理論給出了最優的方案——霍夫曼樹。具體可以查看其它資料。

2.2目標函數

假設語料庫是有S個句子組成的一個句子序列(順序不重要),整個語料庫有V個詞,似然函數就會構建成下面的樣子
                                                         (2.2.1)
其中T_j表示第j個句子的詞個數,極大似然要對整個語料庫去做的。對數似然就會是下面的樣子
                              (2.2.2)
如果前面有個1/V,對數似然還有些人稱爲交叉熵,這個具體也不瞭解,就不介紹了;不用1/V的話,就是正常的極大似然的樣子。
有意向的同學可以擴展到有文檔的樣子,這裏就不介紹了。
但是對於word2vec來說,上面的似然函數得改改,變成下面的樣子

其中的Cij表示上下文相加的那個詞向量。對數似然就是下面的

這裏就不要1/V了。
這個看起來應該比較熟悉了,很像二分類的概率輸出的邏輯迴歸——logistic regression模型。沒錯了,word2vec就是這麼考慮的,把在霍夫曼樹向左的情況,也就是dk=0的情況認爲是正類,向右就認爲是負類(這裏的正負類只表示兩種類別之一)。這樣每當出現了一個上下文C和一個詞在左子樹的情況,就認爲得到了一個正類樣本,否則就是一個負類樣本,每個樣本的屬於正類的概率都可以用上面的參數算出來,就是\sigma \left( {{q_{{i_{jk}}}} \cdot Contex{t_{{i_j}}}} \right),如果是向右的話,就用1 - \sigma \left( {{q_{{i_{jk}}}} \cdot Contex{t_{{i_j}}}} \right)計算其概率。注意每個詞可以產生多個樣本,因爲從霍夫曼樹的根節點開始,每個葉子節點都產生一個樣本,這個樣本的label(也就是屬於正類或者負類標誌)可以用霍夫曼編碼來產生,前面說過了,向左的霍夫曼編碼dk=0,所以很自然地可以用1-dk表示每個樣本label。
在這裏,霍夫曼編碼也變成了一個重要的東西了。
這樣就好多了,問題到這也該清楚了,上面那個l(θ)就是對數似然,然後負對數似然f=-l(θ)就是需要最小化的目標函數了。

2.3解法

解法選用的是SGD,博文《在線學習算法FTRL》中說過SGD算法的一些情況。具體說來就是對每一個樣本都進行迭代,但是每個樣本隻影響其相關的參數,跟它無關的參數不影響。對於上面來說,第j個樣本的第ij個詞的負對數似然是

第j個樣本的第ij個詞的在遇到第kij個非葉節點時的負對數似然是

計算{f_{{k_{ij}}}}的梯度,注意參數包括{q_{{k_{ij}}}}{C_{{i_j}}},其中{C_{{i_j}}}的梯度是用來計算{w_{{i_j}}}的時候用到。另外需要注意的是logσ(x)的梯度是1-σ(x),log(1-σ(x))的梯度是-σ(x),



上面的Fq和Fc只是簡寫,有了梯度就可以對每個參數進行迭代了

同時,每個詞的詞向量也可以進行迭代了

注意第二個迭代的wI是代表所有的輸入詞的,也就是假如輸入了4個詞,這四個詞都要根據這個方式進行迭代(注意是上下文的詞纔是輸入詞,才根據梯度更新了,但是wij這個詞本身不更新的,就是輪到它自己在中間的時候就不更新了)。第二個迭代式確實不好理解,因爲這裏的意思是所有非葉節點上的對上下文的梯度全部加和就得到了這個詞的上下文的梯度,看起來這個就是BP神經網絡的誤差反向傳播。
論文《Hierarchical Probabilistic Neural Network Language Model》和《Three New Graphical Models for Statistical Language Modelling》中看起來也是這麼樣的解釋,人家都是Context的幾個詞首尾連接得到的一個向量,對這個長向量有一個梯度,或者一個超大的V*m矩陣(m是詞向量的維度),對這個矩陣每個元素有一個梯度,這些梯度自然也包括了輸入詞的梯度。
如果有人發現了這個做法的解釋請告知。

2.4代碼中的trick

如前文,c表示左右各取多少個詞,代碼中c是一個從0到window-1的一個數,是對每個詞都隨機生成的,而這個window就是用戶自己輸入的一個變量,默認值是5(這裏得換換概念了,代碼中的c代表當前處理到了那個詞的下標,實際的隨機變量是b)。代碼實際實現的時候是換了一種方法首先生成一個0到window-1的一個數b,然後訓練的詞(假設是第i個詞)的窗口是從第i-(window-b)個詞開始到第i+(window-b)個詞結束,中間用a != window這個判斷跳過了這個詞他自己,也就是更新詞向量的時候只更新上下文相關的幾個輸入詞,這個詞本身是不更新的。要注意的是每個詞的b都不一樣的,都是隨機生成的,這就意味着連窗口大小都是隨機的。
如果有人看過代碼,就會發現,其中的q_(k_ij )在代碼中用矩陣syn1表示,C_(i_j )在代碼中用neu1表示。葉子節點裏面的每個詞向量在代碼中用syn0表示,利用下標移動去讀取。
核心代碼如下,其中的vocab[word].code[d]就表示d_(k_ij ),其他就是迭代過程,代碼是寫得相當簡潔啊。

代碼中的419行就是計算Cij,425-428行就是計算f,也就是σ(q_(k_ij )∙C_(i_j ) )的值,432行就是累積Cij的誤差,434就是更新q_(k_ij)^(n+1)。

注意上面,對每個輸入詞都進行了更新,更新的幅度就是432行中誤差累計的結果。

三. CBOW加抽樣的網絡結構與使用說明

3.1網絡結構與使用說明

網絡結構如下

如(二)中,中間的那個隱層是把上下文累加起來的一個詞向量,然後有一個矩陣R,是在訓練過程中用到的臨時矩陣,這個矩陣連接隱層與所有輸出節點,但是這個矩陣在使用這個網絡的時候不怎麼用得到,這裏也是沒弄清楚的一個地方。每個輸出節點代表一個詞向量。
同樣如(二)中的例子,計算這麼一個概率,這裏的計算方法就簡單多了,就是隨機從語料庫裏面抽取c個詞,這裏假設c=3,抽中了D,E,F這三個詞,又假設“喫”這個詞的詞向量是A,那麼就計算“喫”這個詞的概率就用下面的公式

同樣如(二)中,那句話的每個詞都計算p({w_i}|Contex{t_i})後連乘起來得到聯合概率,這個概率如果大於某個閾值,就認爲是正常的話;否則就認爲不是自然語言,要排除掉。
這裏只是說明這個網絡是怎麼樣的例子,真正重要的始終是那些詞向量。

四.CBOW加抽樣的優化目標與解問題

4.1抽樣方法的意義與目標函數

爲啥要抽樣呢?目的跟(二)中的霍夫曼樹其實是一樣的,都是爲了節省計算量,這個計算量就是式(2.1.2)中計算 p(A|C)的概率,因爲這個概率實在不好算。論文《Distributed Representations of Words and Phrases and their Compositionality》中提到有一個叫NCE的方法可以來代替上面的那個hierarchical softmax方法(就是使用霍夫曼樹的方法),但是由於word2vec只關心怎麼學到高質量的詞向量,所以就用了一種簡單的NCE方法,稱爲NEG,方法的本質就是在第j個句子的第ij個詞wij處使用下面的式子代替


其中E下面的那個下標的意思是wk是符合某個分佈的,在這裏p_V (w)表示詞頻的分佈。
這個式子的第二項是求K個期望,這K個期望中的每一個期望,都是在該上下文的情況下不出現這個詞的期望。這裏出現一個特別大的偷懶,就是認爲這個期望只要抽取一個樣本就能計算出來,當然,如果說遍歷完整個語料庫,其實還可以認爲是抽取了多次實驗的,因爲每次抽取詞的時候,是按照詞頻的分佈來抽樣的,如果抽樣的次數足夠多,在總體的結果上,這裏計算的期望還是接近這個期望的真實值的,這個可以參考博文中RBM中計算梯度的時候的那個蒙特卡洛抽樣來理解。
在這裏,從代碼上體現來看,就只用一個樣本來估算這個期望的,所有式子被簡化成了下面的形式

用這個式子取代(2.2.2)中的logp\left( {{w_{{i_j}}}{\rm{|}}Contex{t_{{i_j}}}} \right),就能得到CBOW加抽樣的目標函數(去掉1/V的),這個目標函數也是極其像logistic regression的目標函數,其中wij是正類樣本,wk是負類樣本。
爲了統一表示,正類樣本設置一個label爲1,負類樣本設置label爲0,每個樣本的負對數似然都變成下面的方式

4.2CBOW加抽樣方法的解法

解法還是用SGD,所以對一個詞wij來說,這個詞本身是一個正類樣本,同時對這個詞,還隨機抽取了k個負類樣本,那麼每個詞在訓練的時候都有k+1個樣本,所以要做k+1次SGD。
對於每個樣本求兩個梯度



兩個梯度都有這麼相似的形式實在太好了,然後開始迭代,代碼裏面有個奇怪的地方,就是一開的網絡結構中的那個V*m的矩陣,用來保存的是每次抽中的負類樣本的詞向量,每一行代表一個詞向量,剛好是所有詞的詞向量。每次抽樣抽中一個詞後,拿去進行迭代的(就是計算梯度什麼的),就是這個矩陣中對應的那個詞向量,而且這個矩陣還參與更新,就是第一個梯度實際更新的是這個矩陣裏面的詞向量。但總的看來,這個矩陣在迭代計算完了就丟棄了,因爲最終更新的詞向量,每次只有一個,就是公式一直出現的那個詞wij,最終輸出的,也是輸入裏面的詞向量(在圖中是最下面的輸出層的那些詞向量),當然這個矩陣可以認爲是隱藏層跟輸出層的連接矩陣。

其中w代表每個樣本對應的詞向量,包括wij和抽中的詞向量,注意更新的是R這個連接矩陣。詞向量的更新公式如下

注意每個梯度的值的計算都是拿連接矩陣R中對應的那一行來算的,這樣看起來可以避免每次都更新輸出層的詞向量,可能是怕搞亂了吧。

4.3CBOW加抽樣方法代碼中的trick

隨機數是自己產生的,代碼裏面自己寫了隨機數程序。
每個詞都要執行negative次抽樣的,如果遇到了當前詞(就是label爲1的詞)就提前退出抽樣,這個步驟就提前完成了,這個也是一個比較費解的trick。
其中前面說的R矩陣在代碼中用syn1neg表示,C_(i_j )在代碼中用neu1表示,同樣的,葉子節點裏面的每個詞向量在代碼中用syn0表示,利用下標移動去讀取。

其中442-446就是抽樣的代碼了,是作者自己寫的模塊,然後label這個變量跟上文的label意思是一樣的,f就表示σ(w∙C_(i_j ) )的值,syn1neg就保存了矩陣R每一行的值,neu1e還是累積誤差,直到一輪抽樣完了後再更新輸入層的詞向量。。
對輸入層的更新模塊和上面的(二)中一樣的,都是更新所有的輸入詞。


五.Skip-gram加層次的優化目標與解問題

5.1網絡結構與使用說明

網絡結構如下圖

其中的Wi是相應的詞,詞Wi與huffman樹直接連接,沒有隱藏層的。使用方法依然與cbow加層次的相似。
在判斷“大家 喜歡 喫 好喫 的 蘋果”這句話是否自然語言的時候,是這麼來的,同樣比如計算到了“喫”這個詞,同樣隨機抽到的c=2,對喫這個詞需要計算的東西比較多,總共要計算的概率是p(大家|喫),p(喜歡|喫),p(好喫|喫)和p(的|喫)總共四個,在計算p(大家|喫)這個概率的時候,要用到上面圖中的二叉樹,假設“大家”這個詞在huffman樹根節點的右孩子的最左邊的那個節點,就是圖中右數第三個葉子節點。再假設從根節點開始到這個葉子節點的路徑上的三個非葉節點分別爲A,B,C(從高到低排列的),“喫”這個詞的詞向量設爲D,那麼p(大家|喫)這個概率可以用下面的公式算概率
p(大家│喫)=(1-σ(A∙D))∙σ(B∙D)∙σ(C∙D)
同樣的方法計算p(喜歡|喫),p(好喫|喫)和p(的|喫),再把這四個概率連乘,得到了“喫”這個詞的上下文概率,注意這只是一個詞的概率。
把一整句話的所有詞的概率都計算出來後進行連乘,得到的就是這句話是自然語言的概率。這個概率如果大於某個閾值,就認爲是正常的話;否則就認爲不是自然語言,要排除掉。
再聲明一下,這裏只是說明這個網絡是怎麼樣的例子,真正重要的始終是那些詞向量。

5.2目標函數

假設語料庫是有S個句子組成的一個句子序列(順序不重要),整個語料庫有V個詞,似然函數就會構建成下面的樣子
        (5.2.1)

其中T_j表示第j個句子的詞個數,w_(u_ij+i_j )表示詞w_(i_j )左右的各c_ij個詞的其中一個,注意c_ij對每個w_(i_j )都不一樣的。極大似然要對整個語料庫去做的。

但是,Google這公司,爲了代碼風格的統一,用了一個trick,我舉例說明吧。
對於一開始的那句話:大家 喜歡 喫 好喫 的 蘋果,總共6個詞,假設每次的cij都抽到了2,按照上面的公式中的部分按每個詞作爲條件w_(i_j )展開,看到得到什麼吧。
大家:P(喜歡|大家)*p(喫|大家)
喜歡:p(大家|喜歡)*p(喫|喜歡)*p(好喫|喜歡)
喫: p(大家|喫) *p(喜歡|喫)*p(好喫|喫)*p(的|喫)
好喫:p(喜歡|好喫)*p(喫|好喫)*p(的|好喫)*p(蘋果|好喫)
的: p(喫|的) *p(好喫|的)*p(蘋果|的)
蘋果:p(好喫|蘋果)*p(的|蘋果)
把結果重新組合一下,得到下面的組合方式。
大家:p(大家|喜歡)*p(大家|喫)
喜歡:P(喜歡|大家)*p(喜歡|喫)*p(喜歡|好喫)
喫: p(喫|大家) *p(喫|喜歡)*p(喫|好喫)*p(喫|的)
好喫:p(好喫|喜歡)*p(好喫|喫)*p(好喫|的)*p(好喫|蘋果)
的: p(的|喫) *p(的|好喫)*p(的|蘋果)
蘋果:p(蘋果|好喫)* p(蘋果|的)
不證明,不推導,直接得到下面的結論

這個是網易有道的那個資料給出的結論,這裏是變成了本文的方式來描述,具體參考網易有道的原文。
這個變化倒是莫名其妙的,不過也能理解,Google公司的代碼是要求很優美的,這樣做能把代碼極大地統一起來。
對數似然就會是下面的樣子

       (5.2.2)
其中的V表示整個語料庫的詞沒有去重的總個數,整個目標函數也可以叫交叉熵,但是這裏對這也不感興趣,一般去掉。
這就涉及到計算某個詞的概率了,如p({w_{{u_{ij}} + {i_j}}}|{w_{{i_j}}}),這個概率變了,條件變成輸入中要考察的那個詞,計算條件概率的詞變成了上下文的詞。當然,計算方法沒有變,前面介紹的huffman樹的計算方法到這裏是一摸一樣的。

其中I表示輸入的那個詞,也就是(5.1)的例子中的那個詞“喫”,那麼w就表示例子中的“大家”;qk表示從根節點下來到“大家”這個詞所在的葉子節點的路徑上的非葉節點,dk就是編碼了,也可以說是分類,當w在某個節點如qk的左子樹的葉子節點上時dk=0,否則dk=1。
用這個式子代替掉上面的(5.2.1)中的似然函數中的p({w_{{u_{ij}} + {i_j}}}|{w_{{i_j}}}),當然每個變量都對號入座,就能得到總的似然函數了。
再對這個式子求個對數,得到


再利用這個式子替換掉(5.2.2)中的{{\rm{log}}p({w_{{u_{ij}} + {i_j}}}|{w_{{i_j}}})}就能得到總的對數似然函數,也就是目標函數,剩下的就是怎麼解了。
可以注意的是,計算每個詞(例中的“喫”)上下文概率的時候都要計算好幾個條件概率的(例子中p(大家|喫),p(喜歡|喫),p(好喫|喫)和p(的|喫)),這每個條件概率又是需要在huffman樹上走好幾個非葉節點的,每走到一個非葉節點,都需要計算一個{\left( {1 - {d_k}} \right)log\sigma \left( {{q_k} \cdot {\rm{I}}} \right) + {d_k} \cdot \left( {1 - \sigma \left( {{q_k} \cdot I} \right)} \right)}的。可以看到,走到每一個非葉節點,在總的對數似然函數中,都類似logistic regression的一個樣本,爲了方便描述,就用樣本和label的方式在稱呼這些東西。
跟一般的logistic regression一樣,每走到一個非葉節點,如果是向左走的,就定義label爲1,爲正樣本;否則label就是0,是負樣本。這樣label=1-dk,每一個非葉節點都爲整個問題產生了一個樣本。

5.3解法

解法選用的是SGD,在處理每個樣本時,對總目標函數的貢獻是

計算梯度



更新


5.4代碼中的trick

對輸入詞I的更新是走完整個huffman樹後對整個誤差一起計算的,這個誤差保存在neu1e這個數組裏面。

其中480-483行是計算\sigma \left( {{q_k} \cdot I} \right)的值,保存在f中,vocab[word].code[d]表示的就是dk的值,neu1e就保存了從根節點到葉子節點的路徑上的所有非葉節點的累積誤差。

這個誤差反向傳播就簡單多了,每次都是對一個詞進行更新的,就是p(w|I)中的那個w。

六.Skip-gram加抽樣的優化目標與解問題

這個就簡單說說吧,不清楚的看上面的。

6.1網絡結構與使用說明

網絡結構如下

使用說明就不說的,同樣是抽樣的。
如(四)中,有一個矩陣R,是在訓練過程中用到的臨時矩陣,這個矩陣連接隱層與所有輸出節點,但是這個矩陣在使用這個網絡的時候不怎麼用得到,這裏也是沒弄清楚的一個地方。每個輸出節點代表一個詞向量。
同樣如(五)中的例子,計算p(大家│喫)這麼一個概率,這裏的計算方法就簡單多了,就是隨機從語料庫裏面抽取c個詞,這裏假設c=3,抽中了D,E,F這三個詞,又假設“喫”這個詞的詞向量是A,那麼就計算“喫”這個詞的概率就用下面的公式

同樣如(五)中,那句話的每個詞都計算與上下文幾個詞的概率(p(大家|喫),p(喜歡|喫),p(好喫|喫)和p(的|喫))後連乘起來得到詞“喫”的概率,所有詞的概率計算出來再連乘就是整句話是自然語言的概率了。剩下的同上。

6.2目標函數與解法

似然函數跟(5.2.1)一樣的,對數似然函數跟(5.2.2)是一樣的,但是計算{\rm{logp}}({w_{{u_{ij}} + {i_j}}}|{w_{{i_j}}})也就是logp(w|I)的的時候不一樣,論文《Distributed Representations of Words and Phrases and their Compositionality》中認爲logp(w|I)可以用下面的式子

代替。
同樣可以和(四)中一樣,設定正負樣本的概念。爲了統一表示,正類樣本設置一個label爲1,負類樣本設置label爲0,每個樣本的負對數似然都變成下面的方式

梯度



更新



6.3代碼

還是每個詞都要執行negative次抽樣的,如果遇到了當前詞(就是label爲1的詞)就提前退出抽樣。

其中493-502就是抽樣的代碼,505-508是計算σ(w∙I)的值,保存在f中,syn1neg就是保存了矩陣R中的每一行的值。而neu1e還是累積這誤差,直到一輪抽樣完了後再更新輸入層的詞向量。

更新輸入層還是一樣。

七.一些總結

從代碼看來,word2vec的作者Mikolov是個比較實在的人,那種方法效果好就用哪種,也不糾結非常嚴格的理論證明,代碼中的trick也是很實用的,可以參考到其他地方使用。


致謝

多位Google公司的研究員無私公開的資料。
多位博主的博客資料,包括@peghoty,就是deeplearning學習羣裏面的皮果提。


參考文獻

[1] http://techblog.youdao.com/?p=915      Deep Learning實戰之word2vec,網易有道的pdf
[2] http://www.zhihu.com/question/21661274/answer/19331979                @楊超在知乎上的問答《Word2Vec的一些理解》
[3] http://xiaoquanzi.net/?p=156                  hisen博客的博文
[4] Hierarchical probabilistic neural network language model. Frederic Morin and Yoshua Bengio.
[5] Distributed Representations of Words and Phrases and their Compositionality T. Mikolov, I. Sutskever, K. Chen, G. Corrado, and J. Dean.
[6] A neural probabilistic language model Y. Bengio, R. Ducharme, P. Vincent.
[7] Linguistic Regularities in Continuous Space Word Representations. Tomas Mikolov,Wen-tau Yih,Geoffrey Zweig

[8] Efficient Estimation of Word Representations in Vector Space. Tomas Mikolov,Kai Chen,Greg Corrado,Jeffrey Dean.

               深度學習word2vec筆記之應用篇

聲明:

1)該博文是Google專家以及多位博主所無私奉獻的論文資料整理的。具體引用的資料請看參考文獻。具體的版本聲明也參考原文獻

2)本文僅供學術交流,非商用。所以每一部分具體的參考資料並沒有詳細對應,更有些部分本來就是直接從其他博客複製過來的。如果某部分不小心侵犯了大家的利益,還望海涵,並聯系老衲刪除或修改,直到相關人士滿意爲止。

3)本人才疏學淺,整理總結的時候難免出錯,還望各位前輩不吝指正,謝謝。

4)閱讀本文需要機器學習、概率統計算法等等基礎(如果沒有也沒關係了,沒有就看看,當做跟同學們吹牛的本錢),基礎篇url:http://blog.csdn.net/mytestmy/article/details/26961315 。

5)此屬於第一版本,若有錯誤,還需繼續修正與增刪。還望大家多多指點。請直接回帖,本人來想辦法處理。

6)本人手上有word版的和pdf版的,有必要的話可以上傳到csdn供各位下載。



好不容易學了一個深度學習的算法,大家是否比較爽了?但是回頭想想,學這個是爲了什麼?吹牛皮嗎?寫論文嗎?參加競賽拿獎嗎?

不管哪個原因,都顯得有點校園思維了。

站在企業的層面,這樣的方式顯然是不符合要求的,如果只是學會了,公式推通了,但是沒有在工作中應用上,那會被老大認爲這是沒有產出的。沒有產出就相當於沒有幹活,沒有幹活的話就……呃……不說了。

下面就給大家弄些例子,說說在互聯網廣告這一塊的應用吧。

 

一.對廣告主的輔助

1.1基本概念

互聯網廣告的廣告主其實往往有他們的困惑,他們不知道自己的目標人羣在哪裏。所謂目標人羣,就是廣告主想向他們投廣告的那幫人。就像互聯網廣告的一個大牛的一句名言——我知道互聯網廣告有一半是浪費的,問題是我不知道是哪一半。

這個困惑就給媒體帶來一個義務——要幫助廣告主定向他們的目標人羣。

對於普通的廣告主來說,比如說一個化妝品廣告的廣告主,它的目標人羣很明顯就是年輕的女性。注意關鍵詞“年輕”和“女性”,這是決定媒體這邊能否賺到錢的關鍵詞。要知道對於媒體來說,廣告主是它們的客戶,滿足客戶的要求,客戶就給它們錢,不滿足客戶的要求,就沒有人爲媒體買單;沒有人爲媒體買單,媒體就沒有錢養它們的員工和機器,也弄不來新聞和互聯網的其他內容,那樣媒體公司就垮了……

那麼在媒體這邊,需要做的的工作就很明確了——滿足它們的客戶(也就是廣告主)的需求。怎麼滿足呢?這工作說容易也容易,說簡單也簡單,就是把喜歡這個廣告主的廣告的人找出來,然後幫這個廣告主把他們的廣告投放給這些人,讓這些人看到這個廣告主的廣告。

這個工作帶來的問題就真多了,媒體又不是什麼神人,比如說一個新聞網站,瀏覽這個網站的每天有100萬人,這個新聞網站的員工不可能一個個去訪問他們的用戶(瀏覽這個網站的人),整天問他們你喜不喜歡化妝品啊,喜不喜歡體育啊之類的問題。

那怎麼辦呢?媒體的員工只好猜了,但是哪怕是猜都很費勁,想想都頭疼,一百萬人啊,一個個猜也得喫力不討好啊。這時候計算機的作用就來了,用計算機猜嘛,而且不一定需要全部瞎猜的,因爲用戶如果註冊了的話,還有一些用戶的個人信息可以參考的。一般的網站註冊的時候都要求提供年齡性別之類的個人信息,有時候要要求寫一些個人的興趣什麼的標籤。這個時候這些數據就用上大用處了。

網站可以把註冊用戶的個人信息保存下來,然後提供廣告主選擇。如上面的那個化妝品的廣告主,它就可以跟媒體提它的要求——我要向年輕的女性投放廣告。媒體這個時候就可以提供一些條件給這個廣告主選擇,如媒體說我有很多用戶,18到80歲的都有,然後男性女性用戶都有。廣告主就可以根據這些條件選擇自己的目標用戶,如選擇了18到30歲的女性用戶作爲目標人羣。選中了目標人羣后,廣告主和媒體就可以談價錢了,談好了價錢廣告主就下單,然後媒體就幫廣告主投廣告,然後媒體的錢就賺到了。

 

1.2興趣挖掘的必要性

上面多次提到的“目標人羣”,就是廣告主最關心的事情。客戶最關心的事情自然也是媒體最關心的事情。所以媒體會盡力幫助它們的客戶去定向它們的目標人羣。

一般所謂的定向也不是媒體親自有一個人來跟廣告主談的,是媒體建立好一個頁面,這個頁面上有一些選項,比如年齡,性別,地域什麼的,都是條件。廣告主在上面把自己的目標人羣符合的條件輸入,然後下單購買向這些人投放廣告的機會。

媒體爲了更好地賺錢,肯定是願意把這個頁面上的條件做得更加豐富一點,讓更多的廣告主覺得這個網站的用戶裏面有它們的目標人羣,從而讓更多的廣告主願意過來下單。

廣告主的定向其實有粗細之分的,有些廣告主粗放點,它們有錢,選的定向條件比較寬,就說女性的用戶,全部都投放;有些就定向得比較窄,比如說,北京的20到25歲的女性,並且要喜歡羽毛球的用戶。對於定向寬的廣告主好處理,問題就是這些定向窄的廣告主,它們還希望知道用戶的興趣所在,這就麻煩了。

爲啥麻煩呢?一個用戶的興趣鬼才知道呢。就算當面問,人家也不樂意回答,何況就憑藉一點點東西瞎猜。但是爲了賺錢,瞎猜也得上的了,工業界爲了賺這個錢,誕生了整整一個行業——數據挖掘,甚至在學術界還有一個更加生猛的名字——機器學習。學術界的那個名字和解釋都是相當大氣的:讓機器學會像人一樣思考。工業界就務實一點,只是對數據內容本身做一個挖掘,獲取到啥呢?一般就是用戶的興趣啊,愛好啊什麼的。這些東西供誰使用呢?暫時看來只有廣告主願意爲這些掏錢,其他的就有些媒體做來讓自己推薦的內容不至於讓用戶那麼反感而已。

上面有個名詞“數據”,沒錯了,這個詞是互聯網廣告業,甚至是數據挖掘行業的核心的東西。所謂數據,這裏簡單點說就可以認爲是用戶的年齡、性別、地域等用戶的基本屬性;複雜點說可以說是用戶興趣、愛好,瀏覽記錄等;更高級的有用戶的交易數據(當然這個高級的數據很少媒體能搞得到)等。

解釋完“數據”這個詞,結合一下廣告這個場景,就可以得到活在媒體公司裏面的互聯網廣告行業數據挖掘工程師的工作是什麼了。他們的工作就是:根據用戶自身的基本屬性和用戶流量的網頁記錄以及內容,想方設法讓計算機猜出用戶的興趣愛好。用戶的興趣愛好“挖掘”出來後,就可以作爲定向條件放到上面說的那個網頁上面供廣告主選擇了。這事情整好了,廣告投了有人點擊,公司的錢就賺到了;沒整好,廣告沒人點擊,廣告主不樂意下單了,公司就賺不到錢……怎麼着?炒這些工程師的魷魚去。

上面可以看到了,輔助廣告主定位它們的目標人羣是很重要的。

經過一番的探索,word2vec在互聯網廣告上面也是可以輔助廣告主定向他們的目標人羣的,下面就講講這個算法在互聯網廣告的應用吧。

1.3利用word2vec給廣告主推薦用戶

爲了用上word2vec,把場景轉換到一個新聞媒體如A公司。

在A公司的多個頁面中,電商公司B有他們的一個主頁,專門介紹他們公司一些產品促銷,搶購和發佈會什麼的。

公司A目前有很多用戶的瀏覽數據,如用戶u瀏覽了公司A的頁面a1,a2,a3等。

把這些數據處理一下,整合成word2vec能處理的數據,如下

U1  a1,a2,a3……

U2  a2,a3,a5,……

U3  a1,a3,a6,……

其中u1,u2,u3表示不同的用戶,後面的一串表示這些用戶的瀏覽記錄,如U1  a1,a2,a3表示用戶u1先瀏覽了頁面a1,再瀏覽a2,然後瀏覽了a3,……

這些數據還不符合word2vec的輸入數據格式,把第一列去掉,變成下面的樣子

a1,a2,a3……

a2,a3,a5,……

a1,a3,a6,……

這些數據就可以作爲word2vec的輸入數據了。

就把這些數據作爲word2vec的訓練數據,詞向量維度爲3,進行訓練,完成後得到下面的輸出

A1  (0.3,-0.5,0.1)

A2  (0.1,0.4,0.2)

A3  (-0.3,0.7,0.8)

……

An  (0.7,-0.1,0.3)

就得到了每個頁面的向量。

這些向量有啥意義呢?其實單個向量的意義不大,只是用這些向量可以計算一個東西——距離,這個距離是頁面之間的距離,如頁面a1和a2可以用歐式距離或者cos距離計算公式來計算一個距離,這個距離是有意義的,表示的是兩個網頁在用戶瀏覽的過程中的相似程度(也可以認爲是這兩個頁面的距離越近,被同一個人瀏覽的概率越大)。注意這個距離的絕對值本身也是沒有意義的,但是這個距離的相對大小是有意義的,意思就是說,假設頁面a1跟a2、a3、a4的距離分別是0.3、0.4、0.5,這0.3、0.4、0.5沒啥意義,但是相對來說,頁面a2與a1的相似程度就要比a3和a4要大。

那麼這裏就有玄機了,如果頁面a1是電商公司B的主頁,頁面a2、a3、a4與a1的距離在所有頁面裏面是最小的,其他都比這三個距離要大,那麼就可以認爲同一個用戶u瀏覽a1的同時,瀏覽a2、a3、a4的概率也比較大,那麼反過來,一個用戶經常瀏覽a2、a3、a4,那麼瀏覽a1的概率是不是也比較大呢?從實驗看來可以這麼認爲的。同時還可以得到一個推論,就是用戶可能會喜歡a1這個頁面對應的廣告主的廣告。

這個在實驗中實際上也出現過的。這裏模擬一個例子吧,如a1是匹克體育用品公司在媒體公司A上的官網,a2是湖人隊比賽數據頁,a3是熱火隊的灌水討論區,a4是小牛隊的球員討論區。這個結果看起來是相當激動人心的。

根據這樣的一個結果,就可以在廣告主下單的那個頁面上增加一個條件——經常瀏覽的相似頁面推薦,功能就是——在廣告主過來選條件的時候,可以選擇那些經常瀏覽跟自己主頁相似的頁面的用戶。舉個例子就是,當匹克體育用品公司來下單的時候,頁面上給它推薦了幾個經常瀏覽頁面的粉絲:湖人隊比賽數據頁,熱火隊的灌水討論區,小牛隊的球員討論區。意思是說,目標人羣中包括了經常瀏覽這三個頁面的人。

這個功能上線後是獲得過很多廣告主的好評的。

這樣word2vec這個算法在這裏就有了第一種用途。

 

二. 對ctr預估模型的幫助

根據另一篇博文《互聯網廣告綜述之點擊率系統》,裏面需要計算的用戶對某廣告的ctr。在實際操作的時候,這個事情也是困難重重的,其中有一個冷啓動問題很難解決。冷啓動問題就是一個廣告是新上線的,之前沒有任何的歷史投放數據,這樣的廣告由於數據不足,點擊率模型經常不怎麼湊效。

但是這個問題可以使用同類型廣告點擊率來緩解,意思就是拿一個同行的廣告的各種特徵作爲這個廣告的特徵,對這個新廣告的點擊率進行預估。

同行往往太粗糙,那麼怎麼辦呢?可以就利用跟這個廣告主比較相似的廣告的點擊率來預估一下這個廣告的點擊率。

上面說過,可以得到每個頁面的詞向量。這裏的方法比較簡單,如在媒體公司A上面有1000個廣告主,它們的主頁分別是a1、a2、……、a1000。

根據上面的方法,得到了這1000個詞向量,然後運行kmean或者其他聚類算法,把這1000個廣告主聚成100個簇,然後每個簇裏面的廣告主看成是一個。

這裏可以模擬一個例子,聚類完成後,某個簇c裏面包含了幾個廣告主的主頁,分別是京東商城,天貓,唯品會,噹噹,聚美優品,1號店,蘑菇街,卓越,亞馬遜,淘寶這10個,這10個的目標人羣看起來基本是一致的。

這裏的看成是一個簇是有意義的,比如說第一個簇c1,c1這個簇裏面的所有歷史投放數據和實時數據可以做特徵,來預估這個流量對這個簇的ctr。得到這個ctr後,就很有用了,如果某廣告投放數據比較充分,就直接預估這個廣告的ctr;如果某廣告的歷史投放數據很少,就用這個廣告主所在的簇的ctr來代替這個廣告,認爲對簇的ctr就是這個廣告的ctr,這樣能讓一個新廣告也能得到相對靠譜的預估ctr,保證不至於亂投一番。

 

三.一些總結

如何應用好一個算法,確實是很多算法工程師的一個重大課題。

數據挖掘算法工程師經常要面對的一個難題就是:這個算法怎麼用到我們的數據上面來?有不少同學會認爲是:我到了公司,就發明一個很牛逼的算法,把公司的原來的問題解決掉,然後大大增加了效果,獲得了領導的好評。這個天真爛漫的想法就不評價了,免得被說打擊人。互聯網企業裏面的真實情況是算法工程師面對那一團亂遭的數據,得想盡辦法去把數據整合成能用的格式。

拿上面的(1.3)中的例子,那個把數據組合成a1,a2,a3……這樣一行行的,然後進入word2vec去進行訓練是最難想到的而且是最核心的東西,雖然明着說是word2vec這個算法厲害,實際上面是“把數據整合成合適的方式交給word2vec進行訓練”這個想法重要,因爲嘗試了很多想法,做了很多實驗才能想到這樣的一招的。

還有數據的整合其實也費了很多功夫的,比如說媒體有些用戶是一些機器的賬號,人家亂搞的,要想辦法排除掉的,而“想辦法排除”這麼簡單一句話,真正要做的工作真是多多的有。

哪怕結果都訓練出來了,怎麼解釋這個結果是好的?這個問題也是得想了一段時間的,後來是實驗發現了利用詞向量的距離來評價相似性這個東西最靠譜,然後才用上的。

一個數據挖掘的過程其實不簡單,這個博客也沒辦法一一體現做的過程裏面的那些各種折騰,各種不順暢。

數據挖掘工程師經常要面對的另一個難題就是:明明理論上推得槓槓的,算法性能也是槓槓的,但是對於互聯網廣告的效果,怎麼就那麼不鹹不淡的呢?

這個問題真沒有什麼統一的答案,這種現象多了去了。經常遇到的原因有:數據本身處理的方式不對和算法不合適。

所謂數據本身處理的方式,可以參看博文《互聯網廣告綜述之點擊率特徵工程》,裏面說的那些方法不是從哪本書上面看到的,是經過比較長時間實踐,然後各種折騰,各種特徵取捨,各種胡思亂想,各種坑踩出來的。可能志在學術的人看起來都簡單,實際上課本那些東西,學生們吹起牛皮來不眨眼的那些東西,一跟真實應用場景結合起來就各種坑要踩的了。

拿上面的(二)中的例子來看。方法簡單得不得了,但是可以想象一下,word2vec牛逼啊,kmeans牛逼啊,第一次聚類出來的結果也不過如此。後來又加入了每個廣告主的行業和地域作爲特徵,而且這個加特徵,就是直接把行業和地域處理一下,連接到廣告主的詞向量後面的。如a1的詞向量是(0.3,-0.5,0.1),然後假設只有兩個行業,體育和化妝品,處理成二值特徵,佔據第4和5兩個index,第4個特徵爲1,第5個特徵爲0表示體育類廣告主,反過來,第4個特徵爲0,第5個特徵爲1表示化妝品;再對地域的下標做了一下處理,成爲二值特徵,比如說佔據了6到10這5個位置(假設第6個位置爲1,其餘7到10爲0表示北京;第7個位置爲1,其餘爲0表示廣東,以此類推)。

經過了上面的處理,再用kmeans進行聚類,從聚類後一個個簇去看,結果看起來才順眼了很多。上面的行業和地域特徵的加入,也是用了比較多的經驗的,不是憑空亂整出來的一個吹牛皮的東西,當然誰有更好的方法,也可以提出來試試看。另外還希望大家注意關鍵字“一個個簇去看”,這個工作真是費時費力,比較辛苦的。

以上舉了一些例子,也把互聯網廣告的數據挖掘算法工程師的一些工作中的成功和不成功的地方都說出來了,基本上算是實話實說,希望對大家有點幫助吧。有過類似經歷的人能看懂,沒啥興趣的就呵呵吧。

 

 

致謝

多位同事提供的建議與指導。

多位google研究員有關word2vec的資料。


ref:  http://blog.csdn.net/han____shuai/article/details/50882135

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章