在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ 人工智能/ 機(jī)器翻譯
識(shí)別數(shù)字
線性回歸
情感分析
詞向量
個(gè)性化推薦
圖像分類
語義角色標(biāo)注
機(jī)器翻譯

機(jī)器翻譯

本教程源代碼目錄在book/machine_translation, 初次使用請(qǐng)參考PaddlePaddle安裝教程。

背景介紹

機(jī)器翻譯(machine translation, MT)是用計(jì)算機(jī)來實(shí)現(xiàn)不同語言之間翻譯的技術(shù)。被翻譯的語言通常稱為源語言(source language),翻譯成的結(jié)果語言稱為目標(biāo)語言(target language)。機(jī)器翻譯即實(shí)現(xiàn)從源語言到目標(biāo)語言轉(zhuǎn)換的過程,是自然語言處理的重要研究領(lǐng)域之一。

早期機(jī)器翻譯系統(tǒng)多為基于規(guī)則的翻譯系統(tǒng),需要由語言學(xué)家編寫兩種語言之間的轉(zhuǎn)換規(guī)則,再將這些規(guī)則錄入計(jì)算機(jī)。該方法對(duì)語言學(xué)家的要求非常高,而且我們幾乎無法總結(jié)一門語言會(huì)用到的所有規(guī)則,更何況兩種甚至更多的語言。因此,傳統(tǒng)機(jī)器翻譯方法面臨的主要挑戰(zhàn)是無法得到一個(gè)完備的規(guī)則集合[1]。

為解決以上問題,統(tǒng)計(jì)機(jī)器翻譯(Statistical Machine Translation, SMT)技術(shù)應(yīng)運(yùn)而生。在統(tǒng)計(jì)機(jī)器翻譯技術(shù)中,轉(zhuǎn)化規(guī)則是由機(jī)器自動(dòng)從大規(guī)模的語料中學(xué)習(xí)得到的,而非我們?nèi)酥鲃?dòng)提供規(guī)則。因此,它克服了基于規(guī)則的翻譯系統(tǒng)所面臨的知識(shí)獲取瓶頸的問題,但仍然存在許多挑戰(zhàn):
  1)人為設(shè)計(jì)許多特征(feature),但永遠(yuǎn)無法覆蓋所有的語言現(xiàn)象;
  2)難以利用全局的特征;
  3)依賴于許多預(yù)處理環(huán)節(jié),如詞語對(duì)齊、分詞或符號(hào)化(tokenization)、規(guī)則抽取、句法分析等,而每個(gè)環(huán)節(jié)的錯(cuò)誤會(huì)逐步累積,對(duì)翻譯的影響也越來越大。

近年來,深度學(xué)習(xí)技術(shù)的發(fā)展為解決上述挑戰(zhàn)提供了新的思路。將深度學(xué)習(xí)應(yīng)用于機(jī)器翻譯任務(wù)的方法大致分為兩類:
  1)仍以統(tǒng)計(jì)機(jī)器翻譯系統(tǒng)為框架,只是利用神經(jīng)網(wǎng)絡(luò)來改進(jìn)其中的關(guān)鍵模塊,如語言模型、調(diào)序模型等(見圖1的左半部分);
  2)不再以統(tǒng)計(jì)機(jī)器翻譯系統(tǒng)為框架,而是直接用神經(jīng)網(wǎng)絡(luò)將源語言映射到目標(biāo)語言,即端到端的神經(jīng)網(wǎng)絡(luò)機(jī)器翻譯(End-to-End Neural Machine Translation, End-to-End NMT)(見圖1的右半部分),簡稱為NMT模型。

http://wiki.jikexueyuan.com/project/deep-learning/images/08-01.png" alt="png" />
圖1. 基于神經(jīng)網(wǎng)絡(luò)的機(jī)器翻譯系統(tǒng)

本教程主要介紹NMT模型,以及如何用PaddlePaddle來訓(xùn)練一個(gè)NMT模型。

效果展示

以中英翻譯(中文翻譯到英文)的模型為例,當(dāng)模型訓(xùn)練完畢時(shí),如果輸入如下已分詞的中文句子:

這些 是 希望 的 曙光 和 解脫 的 跡象 .

如果設(shè)定顯示翻譯結(jié)果的條數(shù)(即柱搜索算法的寬度)為3,生成的英語句子如下:

0 -5.36816   These are signs of hope and relief . <e>
1 -6.23177   These are the light of hope and relief . <e>
2 -7.7914  These are the light of hope and the relief of hope . <e>

  左起第一列是生成句子的序號(hào);左起第二列是該條句子的得分(從大到?。?,分值越高越好;左起第三列是生成的英語句子。
  另外有兩個(gè)特殊標(biāo)志:<e>表示句子的結(jié)尾,<unk>表示未登錄詞(unknown word),即未在訓(xùn)練字典中出現(xiàn)的詞。

模型概覽

本節(jié)依次介紹GRU(Gated Recurrent Unit,門控循環(huán)單元),雙向循環(huán)神經(jīng)網(wǎng)絡(luò)(Bi-directional Recurrent Neural Network),NMT模型中典型的編碼器-解碼器(Encoder-Decoder)框架和注意力(Attention)機(jī)制,以及柱搜索(beam search)算法。

GRU

我們已經(jīng)在情感分析一章中介紹了循環(huán)神經(jīng)網(wǎng)絡(luò)(RNN)及長短時(shí)間記憶網(wǎng)絡(luò)(LSTM)。相比于簡單的RNN,LSTM增加了記憶單元(memory cell)、輸入門(input gate)、遺忘門(forget gate)及輸出門(output gate),這些門及記憶單元組合起來大大提升了RNN處理遠(yuǎn)距離依賴問題的能力。

GRU[2]是Cho等人在LSTM上提出的簡化版本,也是RNN的一種擴(kuò)展,如下圖所示。GRU單元只有兩個(gè)門:
  重置門(reset gate):如果重置門關(guān)閉,會(huì)忽略掉歷史信息,即歷史不相干的信息不會(huì)影響未來的輸出。
  更新門(update gate):將LSTM的輸入門和遺忘門合并,用于控制歷史信息對(duì)當(dāng)前時(shí)刻隱層輸出的影響。如果更新門接近1,會(huì)把歷史信息傳遞下去。

http://wiki.jikexueyuan.com/project/deep-learning/images/08-02.png" alt="png" />
圖2. GRU(門控循環(huán)單元)

一般來說,具有短距離依賴屬性的序列,其重置門比較活躍;相反,具有長距離依賴屬性的序列,其更新門比較活躍。另外,Chung等人[3]通過多組實(shí)驗(yàn)表明,GRU雖然參數(shù)更少,但是在多個(gè)任務(wù)上都和LSTM有相近的表現(xiàn)。

雙向循環(huán)神經(jīng)網(wǎng)絡(luò)

我們已經(jīng)在語義角色標(biāo)注一章中介紹了一種雙向循環(huán)神經(jīng)網(wǎng)絡(luò),這里介紹Bengio團(tuán)隊(duì)在論文[2,4]中提出的另一種結(jié)構(gòu)。該結(jié)構(gòu)的目的是輸入一個(gè)序列,得到其在每個(gè)時(shí)刻的特征表示,即輸出的每個(gè)時(shí)刻都用定長向量表示到該時(shí)刻的上下文語義信息。

具體來說,該雙向循環(huán)神經(jīng)網(wǎng)絡(luò)分別在時(shí)間維以順序和逆序——即前向(forward)和后向(backward)——依次處理輸入序列,并將每個(gè)時(shí)間步RNN的輸出拼接成為最終的輸出層。這樣每個(gè)時(shí)間步的輸出節(jié)點(diǎn),都包含了輸入序列中當(dāng)前時(shí)刻完整的過去和未來的上下文信息。下圖展示的是一個(gè)按時(shí)間步展開的雙向循環(huán)神經(jīng)網(wǎng)絡(luò)。該網(wǎng)絡(luò)包含一個(gè)前向和一個(gè)后向RNN,其中有六個(gè)權(quán)重矩陣:輸入到前向隱層和后向隱層的權(quán)重矩陣($W_1, W_3$),隱層到隱層自己的權(quán)重矩陣($W_2,W_5$),前向隱層和后向隱層到輸出層的權(quán)重矩陣($W_4, W_6$)。注意,該網(wǎng)絡(luò)的前向隱層和后向隱層之間沒有連接。

http://wiki.jikexueyuan.com/project/deep-learning/images/08-03.png" alt="png" />
圖3. 按時(shí)間步展開的雙向循環(huán)神經(jīng)網(wǎng)絡(luò)

編碼器-解碼器框架

編碼器-解碼器(Encoder-Decoder)[2]框架用于解決由一個(gè)任意長度的源序列到另一個(gè)任意長度的目標(biāo)序列的變換問題。即編碼階段將整個(gè)源序列編碼成一個(gè)向量,解碼階段通過最大化預(yù)測序列概率,從中解碼出整個(gè)目標(biāo)序列。編碼和解碼的過程通常都使用RNN實(shí)現(xiàn)。

http://wiki.jikexueyuan.com/project/deep-learning/images/08-04.png" alt="png" />
圖4. 編碼器-解碼器框架

編碼器

編碼階段分為三步:

  1.one-hot vector表示:將源語言句子$x=\left { x_1,x_2,...,x_T \right }$的每個(gè)詞$x_i$表示成一個(gè)列向量$w_i\epsilon \left { 0,1 \right }^{\left | V \right |},i=1,2,...,T$。這個(gè)向量$w_i$的維度與詞匯表大小$\left | V \right |$ 相同,并且只有一個(gè)維度上有值1(該位置對(duì)應(yīng)該詞在詞匯表中的位置),其余全是0。

  2.映射到低維語義空間的詞向量:one-hot vector表示存在兩個(gè)問題:
    1)生成的向量維度往往很大,容易造成維數(shù)災(zāi)難;
    2)難以刻畫詞與詞之間的關(guān)系(如語義相似性,也就是無法很好地表達(dá)語義)。
  因此,需再one-hot vector映射到低維的語義空間,由一個(gè)固定維度的稠密向量(稱為詞向量)表示。記映射矩陣為$C\epsilon R^{K\times \left | V \right |}$,用$s_i=Cw_i$表示第$i$個(gè)詞的詞向量,$K$為向量維度。

  3.用RNN編碼源語言詞序列:這一過程的計(jì)算公式為$h_i=\varnothing _\theta \left ( h_{i-1}, s_i \right )$,其中$h_0$是一個(gè)全零的向量,$\varnothing _\theta$是一個(gè)非線性激活函數(shù),最后得到的$\mathbf{h}=\left { h_1,..., h_T \right }$就是RNN依次讀入源語言$T$個(gè)詞的狀態(tài)編碼序列。整句話的向量表示可以采用$\mathbf{h}$在最后一個(gè)時(shí)間步$T$的狀態(tài)編碼,或使用時(shí)間維上的池化(pooling)結(jié)果。

第3步也可以使用雙向循環(huán)神經(jīng)網(wǎng)絡(luò)實(shí)現(xiàn)更復(fù)雜的句編碼表示,具體可以用雙向GRU實(shí)現(xiàn)。前向GRU按照詞序列$(x_1,x_2,...,x_T)$的順序依次編碼源語言端詞,并得到一系列隱層狀態(tài)$(\overrightarrow{h_1},\overrightarrow{h_2},...,\overrightarrow{h_T})$。類似的,后向GRU按照$(x_T,x_{T-1},...,x_1)$的順序依次編碼源語言端詞,得到$(\overleftarrow{h_1},\overleftarrow{h_2},...,\overleftarrow{h_T})$。最后對(duì)于詞$x_i$,通過拼接兩個(gè)GRU的結(jié)果得到它的隱層狀態(tài),即$h_i=\left [ \overrightarrow{h_i^T},\overleftarrow{h_i^T} \right ]^{T}$。

http://wiki.jikexueyuan.com/project/deep-learning/images/08-05.png" alt="png" />
圖5. 使用雙向GRU的編碼器

解碼器

機(jī)器翻譯任務(wù)的訓(xùn)練過程中,解碼階段的目標(biāo)是最大化下一個(gè)正確的目標(biāo)語言詞的概率。思路是:

  每一個(gè)時(shí)刻,根據(jù)源語言句子的編碼信息(又叫上下文向量,context vector)$c$、真實(shí)目標(biāo)語言序列的第$i$個(gè)詞$u_i$和$i$時(shí)刻RNN的隱層狀態(tài)$z_i$,計(jì)算出下一個(gè)隱層狀態(tài)$z_{i+1}$。計(jì)算公式如下:

$$z_{i+1}=\phi _{\theta '}\left ( c,u_i,z_i \right )$$

其中$\phi _{\theta '}$是一個(gè)非線性激活函數(shù);$c=q\mathbf{h}$是源語言句子的上下文向量,在不使用注意力機(jī)制時(shí),如果編碼器的輸出是源語言句子編碼后的最后一個(gè)元素,則可以定義$c=h_T$;$u_i$是目標(biāo)語言序列的第$i$個(gè)單詞,$u_0$是目標(biāo)語言序列的開始標(biāo)記<s>,表示解碼開始;$z_i$是$i$時(shí)刻解碼RNN的隱層狀態(tài),$z_0$是一個(gè)全零的向量。

  將$z_{i+1}$通過softmax歸一化,得到目標(biāo)語言序列的第$i+1$個(gè)單詞的概率分布$p_{i+1}$。概率分布公式如下:

$$p\left ( u_{i+1}|u_{<i+1},\mathbf{x} \right )=softmax(W_sz_{i+1}+b_z)$$

其中$W_sz_{i+1}+b_z$是對(duì)每個(gè)可能的輸出單詞進(jìn)行打分,再用softmax歸一化就可以得到第$i+1$個(gè)詞的概率$p_{i+1}$。

  根據(jù)$p_{i+1}$和$u_{i+1}$計(jì)算代價(jià)。
  重復(fù)步驟1~3,直到目標(biāo)語言序列中的所有詞處理完畢。

機(jī)器翻譯任務(wù)的生成過程,通俗來講就是根據(jù)預(yù)先訓(xùn)練的模型來翻譯源語言句子。生成過程中的解碼階段和上述訓(xùn)練過程的有所差異,具體介紹請(qǐng)見柱搜索算法。

注意力機(jī)制

如果編碼階段的輸出是一個(gè)固定維度的向量,會(huì)帶來以下兩個(gè)問題:1)不論源語言序列的長度是5個(gè)詞還是50個(gè)詞,如果都用固定維度的向量去編碼其中的語義和句法結(jié)構(gòu)信息,對(duì)模型來說是一個(gè)非常高的要求,特別是對(duì)長句子序列而言;2)直覺上,當(dāng)人類翻譯一句話時(shí),會(huì)對(duì)與當(dāng)前譯文更相關(guān)的源語言片段上給予更多關(guān)注,且關(guān)注點(diǎn)會(huì)隨著翻譯的進(jìn)行而改變。而固定維度的向量則相當(dāng)于,任何時(shí)刻都對(duì)源語言所有信息給予了同等程度的關(guān)注,這是不合理的。因此,Bahdanau等人[4]引入注意力(attention)機(jī)制,可以對(duì)編碼后的上下文片段進(jìn)行解碼,以此來解決長句子的特征學(xué)習(xí)問題。下面介紹在注意力機(jī)制下的解碼器結(jié)構(gòu)。

與簡單的解碼器不同,這里$z_i$的計(jì)算公式為:

$$z_{i+1}=\phi _{\theta '}\left ( c_i,u_i,z_i \right )$$

可見,源語言句子的編碼向量表示為第$i$個(gè)詞的上下文片段$c_i$,即針對(duì)每一個(gè)目標(biāo)語言中的詞$u_i$,都有一個(gè)特定的$c_i$與之對(duì)應(yīng)。$c_i$的計(jì)算公式如下:

$$c_i=\sum _{j=1}^{T}a_{ij}h_j, a_i=\left[ a_{i1},a_{i2},...,a_{iT}\right ]$$

從公式中可以看出,注意力機(jī)制是通過對(duì)編碼器中各時(shí)刻的RNN狀態(tài)$h_j$進(jìn)行加權(quán)平均實(shí)現(xiàn)的。權(quán)重$a_{ij}$表示目標(biāo)語言中第$i$個(gè)詞對(duì)源語言中第$j$個(gè)詞的注意力大小,$a_{ij}$的計(jì)算公式如下:

\begin{align} a_{ij}&=\frac{exp(e_{ij})}{\sum_{k=1}^{T}exp(e_{ik})}\\ e_{ij}&=align(z_i,h_j)\\ \end{align}

其中,$align$可以看作是一個(gè)對(duì)齊模型,用來衡量目標(biāo)語言中第$i$個(gè)詞和源語言中第$j$個(gè)詞的匹配程度。具體而言,這個(gè)程度是通過解碼RNN的第$i$個(gè)隱層狀態(tài)$z_i$和源語言句子的第$j$個(gè)上下文片段$h_j$計(jì)算得到的。傳統(tǒng)的對(duì)齊模型中,目標(biāo)語言的每個(gè)詞明確對(duì)應(yīng)源語言的一個(gè)或多個(gè)詞(hard alignment);而在注意力模型中采用的是soft alignment,即任何兩個(gè)目標(biāo)語言和源語言詞間均存在一定的關(guān)聯(lián),且這個(gè)關(guān)聯(lián)強(qiáng)度是由模型計(jì)算得到的實(shí)數(shù),因此可以融入整個(gè)NMT框架,并通過反向傳播算法進(jìn)行訓(xùn)練。

http://wiki.jikexueyuan.com/project/deep-learning/images/08-06.png" alt="png" />
圖6. 基于注意力機(jī)制的解碼器

柱搜索算法

柱搜索(beam search)是一種啟發(fā)式圖搜索算法,用于在圖或樹中搜索有限集合中的最優(yōu)擴(kuò)展節(jié)點(diǎn),通常用在解空間非常大的系統(tǒng)(如機(jī)器翻譯、語音識(shí)別)中,原因是內(nèi)存無法裝下圖或樹中所有展開的解。如在機(jī)器翻譯任務(wù)中希望翻譯“<s>你好<e>”,就算目標(biāo)語言字典中只有3個(gè)詞(<s>, <e>, hello),也可能生成無限句話(hello循環(huán)出現(xiàn)的次數(shù)不定),為了找到其中較好的翻譯結(jié)果,我們可采用柱搜索算法。

柱搜索算法使用廣度優(yōu)先策略建立搜索樹,在樹的每一層,按照啟發(fā)代價(jià)(heuristic cost)(本教程中,為生成詞的log概率之和)對(duì)節(jié)點(diǎn)進(jìn)行排序,然后僅留下預(yù)先確定的個(gè)數(shù)(文獻(xiàn)中通常稱為beam width、beam size、柱寬度等)的節(jié)點(diǎn)。只有這些節(jié)點(diǎn)會(huì)在下一層繼續(xù)擴(kuò)展,其他節(jié)點(diǎn)就被剪掉了,也就是說保留了質(zhì)量較高的節(jié)點(diǎn),剪枝了質(zhì)量較差的節(jié)點(diǎn)。因此,搜索所占用的空間和時(shí)間大幅減少,但缺點(diǎn)是無法保證一定獲得最優(yōu)解。

使用柱搜索算法的解碼階段,目標(biāo)是最大化生成序列的概率。思路是:

  1.每一個(gè)時(shí)刻,根據(jù)源語言句子的編碼信息$c$、生成的第$i$個(gè)目標(biāo)語言序列單詞$u_i$和$i$時(shí)刻RNN的隱層狀態(tài)$z_i$,計(jì)算出下一個(gè)隱層狀態(tài)$z_{i+1}$。
  2.將$z_{i+1}$通過softmax歸一化,得到目標(biāo)語言序列的第$i+1$個(gè)單詞的概率分布$p_{i+1}$。
  3.根據(jù)$p_{i+1}$采樣出單詞$u_{i+1}$。
  4.重復(fù)步驟1~3,直到獲得句子結(jié)束標(biāo)記<e>或超過句子的最大生成長度為止。

注意:$z_{i+1}$和$p_{i+1}$的計(jì)算公式同解碼器中的一樣。且由于生成時(shí)的每一步都是通過貪心法實(shí)現(xiàn)的,因此并不能保證得到全局最優(yōu)解。

數(shù)據(jù)介紹

本教程使用WMT-14數(shù)據(jù)集中的bitexts(after selection)作為訓(xùn)練集,dev+test data作為測試集和生成集。

數(shù)據(jù)預(yù)處理

我們的預(yù)處理流程包括兩步:
  將每個(gè)源語言到目標(biāo)語言的平行語料庫文件合并為一個(gè)文件:
    合并每個(gè)XXX.srcXXX.trg文件為XXX
    XXX中的第$i$行內(nèi)容為XXX.src中的第$i$行和XXX.trg中的第$i$行連接,用'\t'分隔。
  創(chuàng)建訓(xùn)練數(shù)據(jù)的“源字典”和“目標(biāo)字典”。每個(gè)字典都有DICTSIZE個(gè)單詞,包括:語料中詞頻最高的(DICTSIZE - 3)個(gè)單詞,和3個(gè)特殊符號(hào)<s>(序列的開始)、<e>(序列的結(jié)束)和<unk>(未登錄詞)。

示例數(shù)據(jù)

因?yàn)橥暾臄?shù)據(jù)集數(shù)據(jù)量較大,為了驗(yàn)證訓(xùn)練流程,PaddlePaddle接口paddle.dataset.wmt14中默認(rèn)提供了一個(gè)經(jīng)過預(yù)處理的較小規(guī)模的數(shù)據(jù)集

該數(shù)據(jù)集有193319條訓(xùn)練數(shù)據(jù),6003條測試數(shù)據(jù),詞典長度為30000。因?yàn)閿?shù)據(jù)規(guī)模限制,使用該數(shù)據(jù)集訓(xùn)練出來的模型效果無法保證。

流程說明

paddle初始化

# 加載 paddle的python包
import sys
import paddle.v2 as paddle

# 配置只使用cpu,并且使用一個(gè)cpu進(jìn)行訓(xùn)練
paddle.init(use_gpu=False, trainer_count=1)
# 訓(xùn)練模式False,生成模式True
is_generating = False

模型結(jié)構(gòu)

  首先,定義了一些全局變量。

   dict_size = 30000 # 字典維度
   source_dict_dim = dict_size # 源語言字典維度
   target_dict_dim = dict_size # 目標(biāo)語言字典維度
   word_vector_dim = 512 # 詞向量維度
   encoder_size = 512 # 編碼器中的GRU隱層大小
   decoder_size = 512 # 解碼器中的GRU隱層大小
   beam_size = 3 # 柱寬度
   max_length = 250 # 生成句子的最大長度

  其次,實(shí)現(xiàn)編碼器框架。分為三步:

    輸入是一個(gè)文字序列,被表示成整型的序列。序列中每個(gè)元素是文字在字典中的索引。所以,我們定義數(shù)據(jù)層的數(shù)據(jù)類型為integer_value_sequence(整型序列),序列中每個(gè)元素的范圍是[0, source_dict_dim)。

    src_word_id = paddle.layer.data(
        name='source_language_word',
        type=paddle.data_type.integer_value_sequence(source_dict_dim))

    將上述編碼映射到低維語言空間的詞向量$\mathbf{s}$。

    src_embedding = paddle.layer.embedding(
        input=src_word_id,
        size=word_vector_dim,
        param_attr=paddle.attr.ParamAttr(name='_source_language_embedding'))

    用雙向GRU編碼源語言序列,拼接兩個(gè)GRU的編碼結(jié)果得到$\mathbf{h}$。

    src_forward = paddle.networks.simple_gru(
        input=src_embedding, size=encoder_size)
    src_backward = paddle.networks.simple_gru(
        input=src_embedding, size=encoder_size, reverse=True)
    encoded_vector = paddle.layer.concat(input=[src_forward, src_backward])

  接著,定義基于注意力機(jī)制的解碼器框架。分為三步:

    對(duì)源語言序列編碼后的結(jié)果(見2的最后一步),過一個(gè)前饋神經(jīng)網(wǎng)絡(luò)(Feed Forward Neural Network),得到其映射。

    with paddle.layer.mixed(size=decoder_size) as encoded_proj:
        encoded_proj += paddle.layer.full_matrix_projection(
            input=encoded_vector)

    構(gòu)造解碼器RNN的初始狀態(tài)。由于解碼器需要預(yù)測時(shí)序目標(biāo)序列,但在0時(shí)刻并沒有初始值,所以我們希望對(duì)其進(jìn)行初始化。這里采用的是將源語言序列逆序編碼后的最后一個(gè)狀態(tài)進(jìn)行非線性映射,作為該初始值,即$c_0=h_T$。

    backward_first = paddle.layer.first_seq(input=src_backward)
    with paddle.layer.mixed(
            size=decoder_size, act=paddle.activation.Tanh()) as decoder_boot:
        decoder_boot += paddle.layer.full_matrix_projection(
            input=backward_first)

    定義解碼階段每一個(gè)時(shí)間步的RNN行為,即根據(jù)當(dāng)前時(shí)刻的源語言上下文向量$c_i$、解碼器隱層狀態(tài)$z_i$和目標(biāo)語言中第$i$個(gè)詞$u_i$,來預(yù)測第$i+1$個(gè)詞的概率$p_{i+1}$。
      decoder_mem記錄了前一個(gè)時(shí)間步的隱層狀態(tài)$z_i$,其初始狀態(tài)是decoder_boot。
      context通過調(diào)用simple_attention函數(shù),實(shí)現(xiàn)公式$c_i=\sum {j=1}^{T}a_{ij}h_j$。其中,enc_vec是$h_j$,enc_proj是$h_j$的映射(見3.1),權(quán)重$a_{ij}$的計(jì)算已經(jīng)封裝在simple_attention函數(shù)中。
      decoder_inputs融合了$c_i$和當(dāng)前目標(biāo)詞current_word(即$u_i$)的表示。
      gru_step通過調(diào)用gru_step_layer函數(shù),在decoder_inputs和decoder_mem上做了激活操作,即實(shí)現(xiàn)公式$z_{i+1}=\phi _{\theta '}\left ( c_i,u_i,z_i \right )$。
      最后,使用softmax歸一化計(jì)算單詞的概率,將out結(jié)果返回,即實(shí)現(xiàn)公式$p\left ( u_i|u_{<i},\mathbf{x} \right )=softmax(W_sz_i+b_z)$。

    def gru_decoder_with_attention(enc_vec, enc_proj, current_word):

        decoder_mem = paddle.layer.memory(
            name='gru_decoder', size=decoder_size, boot_layer=decoder_boot)

        context = paddle.networks.simple_attention(
            encoded_sequence=enc_vec,
            encoded_proj=enc_proj,
            decoder_state=decoder_mem)

        with paddle.layer.mixed(size=decoder_size * 3) as decoder_inputs:
            decoder_inputs += paddle.layer.full_matrix_projection(input=context)
            decoder_inputs += paddle.layer.full_matrix_projection(
                input=current_word)

        gru_step = paddle.layer.gru_step(
            name='gru_decoder',
            input=decoder_inputs,
            output_mem=decoder_mem,
            size=decoder_size)

        with paddle.layer.mixed(
                size=target_dict_dim,
                bias_attr=True,
                act=paddle.activation.Softmax()) as out:
            out += paddle.layer.full_matrix_projection(input=gru_step)
        return out

  定義解碼器框架名字,和gru_decoder_with_attention函數(shù)的前兩個(gè)輸入。注意:這兩個(gè)輸入使用StaticInput,具體說明可見StaticInput文檔。

```python
decoder_group_name = "decoder_group"
group_input1 = paddle.layer.StaticInputV2(input=encoded_vector, is_seq=True)
group_input2 = paddle.layer.StaticInputV2(input=encoded_proj, is_seq=True)
group_inputs = [group_input1, group_input2]
```

  訓(xùn)練模式下的解碼器調(diào)用:

    首先,將目標(biāo)語言序列的詞向量trg_embedding,直接作為訓(xùn)練模式下的current_word傳給gru_decoder_with_attention函數(shù)。
    其次,使用recurrent_group函數(shù)循環(huán)調(diào)用gru_decoder_with_attention函數(shù)。
    接著,使用目標(biāo)語言的下一個(gè)詞序列作為標(biāo)簽層lbl,即預(yù)測目標(biāo)詞。
    最后,用多類交叉熵?fù)p失函數(shù)classification_cost來計(jì)算損失值。

   if not is_generating:
       trg_embedding = paddle.layer.embedding(
           input=paddle.layer.data(
               name='target_language_word',  
               type=paddle.data_type.integer_value_sequence(target_dict_dim)),
           size=word_vector_dim,
           param_attr=paddle.attr.ParamAttr(name='_target_language_embedding'))
       group_inputs.append(trg_embedding)

       # For decoder equipped with attention mechanism, in training,
       # target embeding (the groudtruth) is the data input,
       # while encoded source sequence is accessed to as an unbounded memory.
       # Here, the StaticInput defines a read-only memory
       # for the recurrent_group.
       decoder = paddle.layer.recurrent_group(
           name=decoder_group_name,
           step=gru_decoder_with_attention,
           input=group_inputs)

       lbl = paddle.layer.data(
           name='target_language_next_word',
           type=paddle.data_type.integer_value_sequence(target_dict_dim))
       cost = paddle.layer.classification_cost(input=decoder, label=lbl)

  生成模式下的解碼器調(diào)用:

    首先,在序列生成任務(wù)中,由于解碼階段的RNN總是引用上一時(shí)刻生成出的詞的詞向量,作為當(dāng)前時(shí)刻的輸入,因此,使用GeneratedInput來自動(dòng)完成這一過程。具體說明可見GeneratedInput文檔。
    其次,使用beam_search函數(shù)循環(huán)調(diào)用gru_decoder_with_attention函數(shù),生成出序列id。

   if is_generating:
       # In generation, the decoder predicts a next target word based on
       # the encoded source sequence and the last generated target word.

       # The encoded source sequence (encoder's output) must be specified by
       # StaticInput, which is a read-only memory.
       # Embedding of the last generated word is automatically gotten by
       # GeneratedInputs, which is initialized by a start mark, such as <s>,
       # and must be included in generation.

       trg_embedding = paddle.layer.GeneratedInputV2(
           size=target_dict_dim,
           embedding_name='_target_language_embedding',
           embedding_size=word_vector_dim)
       group_inputs.append(trg_embedding)

       beam_gen = paddle.layer.beam_search(
           name=decoder_group_name,
           step=gru_decoder_with_attention,
           input=group_inputs,
           bos_id=0,
           eos_id=1,
           beam_size=beam_size,
           max_length=max_length)

注意:我們提供的配置在Bahdanau的論文[4]上做了一些簡化,可參考issue #1133。

訓(xùn)練模型

  參數(shù)定義

依據(jù)模型配置的`cost`定義模型參數(shù)??梢源蛴?shù)名字,如果在網(wǎng)絡(luò)配置中沒有指定名字,則默認(rèn)生成。

```python
if not is_generating:
    parameters = paddle.parameters.create(cost)
    for param in parameters.keys():
        print param
```

  數(shù)據(jù)定義

獲取wmt14的dataset reader。

```python
if not is_generating:
    wmt14_reader = paddle.batch(
        paddle.reader.shuffle(
            paddle.dataset.wmt14.train(dict_size=dict_size), buf_size=8192),
        batch_size=5)
```

  構(gòu)造trainer

根據(jù)優(yōu)化目標(biāo)cost,網(wǎng)絡(luò)拓?fù)浣Y(jié)構(gòu)和模型參數(shù)來構(gòu)造出trainer用來訓(xùn)練,在構(gòu)造時(shí)還需指定優(yōu)化方法,這里使用最基本的SGD方法。

```python
if not is_generating:
    optimizer = paddle.optimizer.Adam(
        learning_rate=5e-5,
        regularization=paddle.optimizer.L2Regularization(rate=8e-4))
    trainer = paddle.trainer.SGD(cost=cost,
                                 parameters=parameters,
                                 update_equation=optimizer)
```

  構(gòu)造event_handler

可以通過自定義回調(diào)函數(shù)來評(píng)估訓(xùn)練過程中的各種狀態(tài),比如錯(cuò)誤率等。下面的代碼通過event.batch_id % 2 == 0 指定每2個(gè)batch打印一次日志,包含cost等信息。

```python
if not is_generating:
    def event_handler(event):
        if isinstance(event, paddle.event.EndIteration):
            if event.batch_id % 2 == 0:
                print "\nPass %d, Batch %d, Cost %f, %s" % (
                    event.pass_id, event.batch_id, event.cost, event.metrics)
```

  啟動(dòng)訓(xùn)練

```python
if not is_generating:
    trainer.train(
            reader=wmt14_reader, event_handler=event_handler, num_passes=2)
```

  訓(xùn)練開始后,可以觀察到event_handler輸出的日志如下:

 Pass 0, Batch 0, Cost 148.444983, {'classification_error_evaluator': 1.0}
 .........
 Pass 0, Batch 10, Cost 335.896802, {'classification_error_evaluator': 0.9325153231620789}
 .........

生成模型

  加載預(yù)訓(xùn)練的模型

由于NMT模型的訓(xùn)練非常耗時(shí),我們?cè)?0個(gè)物理節(jié)點(diǎn)(每節(jié)點(diǎn)含有2顆6核CPU)的集群中,花了5天時(shí)間訓(xùn)練了一個(gè)模型供大家直接下載使用。該模型大小為205MB,[BLEU評(píng)估](#BLEU評(píng)估)值為26.92。

```python
if is_generating:
    parameters = paddle.dataset.wmt14.model()
```

  數(shù)據(jù)定義

從wmt14的生成集中讀取前3個(gè)樣本作為源語言句子。

```python
if is_generating:
    gen_creator = paddle.dataset.wmt14.gen(dict_size)
    gen_data = []
    gen_num = 3
    for item in gen_creator():
        gen_data.append((item[0], ))
        if len(gen_data) == gen_num:
            break
```

  構(gòu)造infer

根據(jù)網(wǎng)絡(luò)拓?fù)浣Y(jié)構(gòu)和模型參數(shù)構(gòu)造出infer用來生成,在預(yù)測時(shí)還需要指定輸出域`field`,這里使用生成句子的概率`prob`和句子中每個(gè)詞的`id`。

```python
if is_generating:
    beam_result = paddle.infer(
        output_layer=beam_gen,
        parameters=parameters,
        input=gen_data,
        field=['prob', 'id'])
```

  打印生成結(jié)果

根據(jù)源/目標(biāo)語言字典,將源語言句子和`beam_size`個(gè)生成句子打印輸出。

```python
if is_generating:
    # get the dictionary
    src_dict, trg_dict = paddle.dataset.wmt14.get_dict(dict_size)

    # the delimited element of generated sequences is -1,
    # the first element of each generated sequence is the sequence length
    seq_list = []
    seq = []
    for w in beam_result[1]:
        if w != -1:
            seq.append(w)
        else:
            seq_list.append(' '.join([trg_dict.get(w) for w in seq[1:]]))
            seq = []

    prob = beam_result[0]
    for i in xrange(gen_num):
        print "\n*******************************************************\n"
        print "src:", ' '.join(
            [src_dict.get(w) for w in gen_data[i][0]]), "\n"
        for j in xrange(beam_size):
            print "prob = %f:" % (prob[i][j]), seq_list[i * beam_size + j]
```

  生成開始后,可以觀察到輸出的日志如下:

  src: <s> Les <unk> se <unk> au sujet de la largeur des sièges alors que de grosses commandes sont en jeu <e>

  prob = -19.019573: The <unk> will be rotated about the width of the seats , while large orders are at stake . <e>
  prob = -19.113066: The <unk> will be rotated about the width of the seats , while large commands are at stake . <e>
  prob = -19.512890: The <unk> will be rotated about the width of the seats , while large commands are at play . <e>

總結(jié)

端到端的神經(jīng)網(wǎng)絡(luò)機(jī)器翻譯是近幾年興起的一種全新的機(jī)器翻譯方法。本章中,我們介紹了NMT中典型的“編碼器-解碼器”框架和“注意力”機(jī)制。由于NMT是一個(gè)典型的Seq2Seq(Sequence to Sequence,序列到序列)學(xué)習(xí)問題,因此,Seq2Seq中的query改寫(query rewriting)、摘要、單輪對(duì)話等問題都可以用本教程的模型來解決。

參考文獻(xiàn)

  1. Koehn P. Statistical machine translation[M]. Cambridge University Press, 2009.
  2. Cho K, Van Merri?nboer B, Gulcehre C, et al. Learning phrase representations using RNN encoder-decoder for statistical machine translation[C]//Proceedings of the 2014 Conference on Empirical Methods in Natural Language Processing (EMNLP), 2014: 1724-1734.
  3. Chung J, Gulcehre C, Cho K H, et al. Empirical evaluation of gated recurrent neural networks on sequence modeling[J]. arXiv preprint arXiv:1412.3555, 2014.
  4. Bahdanau D, Cho K, Bengio Y. Neural machine translation by jointly learning to align and translate[C]//Proceedings of ICLR 2015, 2015.
  5. Papineni K, Roukos S, Ward T, et al. BLEU: a method for automatic evaluation of machine translation[C]//Proceedings of the 40th annual meeting on association for computational linguistics. Association for Computational Linguistics, 2002: 311-318.


知識(shí)共享許可協(xié)議
本教程PaddlePaddle 創(chuàng)作,采用 知識(shí)共享 署名-相同方式共享 4.0 國際 許可協(xié)議進(jìn)行許可。

上一篇:詞向量下一篇:識(shí)別數(shù)字