本篇是 Word Vector Embeddings的實(shí)現(xiàn)部分。
該章節(jié)位于Tensroflow For Machine Inteligence這本書的自然語(yǔ)言處理部分。
在第六章的翻譯中把6.2 分為了上下兩部分,上半部分相當(dāng)于前言,先半部分是實(shí)現(xiàn)。
6.2.1Preparing the Wikipedia Corpus
在準(zhǔn)備去詳細(xì)介紹skip-gram模型之前,需要先準(zhǔn)備數(shù)據(jù)集---在本案中使用英文維基百科數(shù)據(jù)集。默認(rèn)的數(shù)據(jù)集含所有頁(yè)面的完整修訂歷史記錄,當(dāng)前頁(yè)面版本的文本大約有100GB,但已經(jīng)有足夠了。這次的練習(xí)也使用其他的語(yǔ)言可以用,您可以在Wikimedia下載網(wǎng)站上查看可用轉(zhuǎn)儲(chǔ)的概述:https://dumps.wikimedia.org/backup-index.html.
為了可以將獲取的數(shù)據(jù)中轉(zhuǎn)化成正確的格式,這里需要有兩部操作。正如你之前在本書中看到的,數(shù)據(jù)收集和數(shù)據(jù)的清洗都是必須且重要的任務(wù)。最終,我們要遍歷維基百科頁(yè)面,將他們表示為one-hot編碼詞。采用一下步驟:
1.???????? 下載數(shù)據(jù)集,提取頁(yè)面和單詞。
2.????????? 統(tǒng)計(jì)單詞形成最常用單詞的vocabulary
3.????????? 使用vocabulary對(duì)提取的頁(yè)面編碼。
在主存上對(duì)整個(gè)文集(維基數(shù)據(jù)集)修改做起來(lái)不太容易,所以我們必須使用數(shù)據(jù)流(data stream)一行一行的讀取文件,并把中間(intermediate)結(jié)果寫入到磁盤上。如果這樣照做,我們?cè)谶@些步驟之間就有檢查點(diǎn),如果有什么出現(xiàn)崩潰的話,不必從頭開始。我們使用以下類來(lái)處理維基百科。在Init()上對(duì)文件是否存在進(jìn)行檢查。
注意,我們還不得不去實(shí)現(xiàn)Wclass的兩個(gè)重要函數(shù)。第一個(gè)是_read_pages() 會(huì)下載Wikipedia數(shù)據(jù)庫(kù),并從該數(shù)據(jù)庫(kù)中解壓出XML文件,然后迭代頁(yè)面并提取純文本以擺脫任何格式。為了讀取壓縮文件,我們需要bz2模塊提供的open()方法,它的工作方式與其標(biāo)準(zhǔn)的等效工具類似,但是即使在流式傳輸文件時(shí)也需要處理壓縮和解壓縮。我們節(jié)約存儲(chǔ)空間,我們會(huì)對(duì)中間結(jié)果壓縮。用于提取單詞的正則表達(dá)式僅捕獲連續(xù)字母的序列和個(gè)別出現(xiàn)的某些特殊字符。
我們需要一個(gè)用于one-hot 編碼的vocabulary. 然后我們可以用詞匯表中的intex來(lái)對(duì)每個(gè)單詞進(jìn)行編碼。為了移除拼寫錯(cuò)誤的和未知的單詞,vocabulary中只包含vocabulary-1個(gè)最常用的單詞以及一個(gè) 符號(hào)用于替代vocabulary中不存在的單詞。這個(gè)符號(hào)也會(huì)在word-vector中給出,以后我們可以用它來(lái)代表未曾見過(guò)的單詞。
由于我們提取到的是純文本,并為單詞定義了編碼,我們可以現(xiàn)場(chǎng)形成以訓(xùn)練實(shí)例。(one the fly應(yīng)該是俚語(yǔ),大意是隨后,現(xiàn)場(chǎng))這樣的做法很棒,因?yàn)榇鎯?chǔ)示例需要大量的存儲(chǔ)空間。由于大部分時(shí)間都會(huì)花在訓(xùn)練上,所以這對(duì)性能影響不大。我們也希望將所得到的樣本分批分組,以便更有效地進(jìn)行訓(xùn)練。由于分類器并不需要太多的內(nèi)存,我們可以使用很大的批次。
那么我們?nèi)绾涡纬捎?xùn)練實(shí)例呢?請(qǐng)記住,skip-gram模型預(yù)測(cè)的是當(dāng)前單詞的上下文單詞。在遍歷文本的時(shí)候,將當(dāng)前單詞作為數(shù)據(jù)將它周圍的單詞作為target,用這種方式創(chuàng)建訓(xùn)練樣本。假設(shè)上下文距離是R=5, 我們可以對(duì)每個(gè)單詞產(chǎn)生10個(gè)訓(xùn)練樣本,左右五個(gè)單詞作為目標(biāo)。然而,有人可能會(huì)認(rèn)為近鄰比遠(yuǎn)鄰更重要的語(yǔ)義語(yǔ)境。因此,我們通過(guò)隨機(jī)選擇一個(gè)上下文大小來(lái)創(chuàng)建較少的帶有遠(yuǎn)端語(yǔ)境的訓(xùn)練樣例,對(duì)于每個(gè)單詞來(lái)說(shuō),上下文的大小在[1,D=10]中隨機(jī)產(chǎn)生。
6.2.2 Model structure
現(xiàn)在,Wikipedia 數(shù)據(jù)集已經(jīng)準(zhǔn)備好了,開始定義模型來(lái)計(jì)算word embeddings.
每個(gè)單詞開始由一個(gè)隨機(jī)向量表示。從單詞的中間表示中,分類器將嘗試預(yù)測(cè)其上下文單詞之一的當(dāng)前表示。然后,我們將傳播錯(cuò)誤來(lái)調(diào)整輸入詞的權(quán)重和表示。因此,使用tf.Variabale表達(dá)表示。如下圖
使用MomentumOptimizer并不是太好,但這種優(yōu)化器的優(yōu)勢(shì)是可以很快的收斂。這使得它在龐大的維基百科語(yǔ)料庫(kù)上表現(xiàn)的很好,Skip-gram背后的思想是可以在更聰明的算法上使用更多的數(shù)據(jù)。
我們模型中現(xiàn)在唯一缺少的就是分類器了。這是skip-gram模型成功的關(guān)鍵,下面我們會(huì)介紹這個(gè)分類器如何工作。
6.2.3 Noise Contrastive Classifier
對(duì)于skip-gram模型來(lái)說(shuō),可以使用很多種代價(jià)函數(shù)(cost function), 但是noise-constrastive estimation loss代價(jià)函數(shù)被認(rèn)為是效果最好的。理想情況下(ideallly),我們不僅要讓預(yù)測(cè)接近目標(biāo),而且還要遠(yuǎn)離當(dāng)前單詞不是目標(biāo)的單詞。雖然都可以很好地模擬為softmax分類器,但我們不希望每次都計(jì)算和訓(xùn)練字母表中所有單詞的輸出。總是使用一些新的隨機(jī)向量作為負(fù)面的例子的方法,也被稱為對(duì)比的樣本。雖然需要幾十個(gè)類,平均到softmax分類器需要經(jīng)過(guò)足夠的訓(xùn)練迭代。為此,Tensorflow 提供了一個(gè)較為方便的函數(shù)tf.nn.nce_loss函數(shù)。
?
6.2.4 Training the model
如今已經(jīng)準(zhǔn)備好數(shù)據(jù)庫(kù),也定義好了模型。還剩一些代碼需要把所有的東西連在一起。訓(xùn)練過(guò)后,我們將最后的embeddings存儲(chǔ)到另一個(gè)文件中。下面的示例是在普通CPU下,使用Wikipedia的子集訓(xùn)練需要5個(gè)小時(shí)左右。如果要使用全集,只需要將URL切換成https://dumps.wikimedia.org/enwiki/20160501/enwiki-20160501-pages-meta-current.xml.bz2即可。
正如你所看到的,我們會(huì)使用一個(gè)AttrDict類。它相當(dāng)于一個(gè)python的dict, 只不過(guò)我們?cè)谠L問(wèn)關(guān)鍵字(key)的時(shí)候,可以得到其屬性(attributes)。更多細(xì)節(jié),請(qǐng)參閱代碼結(jié)構(gòu)和實(shí)用程序一章(the chapter Code Structure and Utilities )。
經(jīng)過(guò)大約5個(gè)小時(shí)的訓(xùn)練以后,我們將把學(xué)習(xí)的embeddings作為一個(gè)Numpy數(shù)組存儲(chǔ)。當(dāng)我們?cè)谝院蟮恼鹿?jié)中想要使用這個(gè)embeddings的時(shí)候就沒(méi)有必要在計(jì)算了。直接拿來(lái)使用就行。在網(wǎng)上有預(yù)先訓(xùn)練的詞語(yǔ)嵌入(pre-trained word embeddings),我們稍后會(huì)在需要時(shí)給出這些embeddings。
2018年1月2日。
下周:
第三節(jié)? 6.3 Sequence Classification