App下載

Python實現(xiàn)簡單的機(jī)器翻譯模型

猿友 2018-08-06 18:36:35 瀏覽數(shù) (8805)
反饋

本文轉(zhuǎn)載至知乎ID:Charles(白露未晞)知乎個人專欄

下載W3Cschool手機(jī)App,0基礎(chǔ)隨時隨地學(xué)編程>>戳此了解

導(dǎo)語

好幾天沒推文的罪惡感讓我決定今天來水一篇文章。

和之前“Python玩CartPole”那篇推文一樣,這也是來自于PyTorch官方教程的一個簡單實例。

為了展示我的誠意,我依舊會由淺入深地講解本文使用到的基本模型:Seq2Seq以及Attention機(jī)制。

內(nèi)容依舊會很長~~~

希望對初入NLP/DeepLearning的童鞋有所幫助~

廢話不多說,直接進(jìn)入正題~~~


相關(guān)文件

百度網(wǎng)盤下載鏈接: https://pan.baidu.com/s/1y3KcMboz_xZJ9Afh5nRkUw

密碼: qvhd


參考文獻(xiàn)

官方英文教程鏈接:

http://pytorch.org/tutorials/intermediate/seq2seq_translation_tutorial.html

另外:

對英文文獻(xiàn)閱讀有困難的同學(xué)也不必?fù)?dān)心,我已經(jīng)把這個教程翻譯為中文放到了相關(guān)文件中。

開發(fā)工具

系統(tǒng):Windows10

Python版本:3.6.4

相關(guān)模塊:

torch模塊;

numpy模塊;

matplotlib模塊;

以及一些Python自帶的模塊。

其中PyTorch版本為:

0.3.0


環(huán)境搭建

安裝Python并添加到環(huán)境變量,pip安裝需要的相關(guān)模塊即可。

補充說明:

PyTorch暫時不支持直接pip安裝。

有兩個選擇:

(1)安裝anaconda3后在anaconda3的環(huán)境下安裝(直接pip安裝即可);

(2)使用編譯好的whl文件安裝,下載鏈接為:

https://pan.baidu.com/s/1dF6ayLr#list/path=%2Fpytorch


原理介紹

PS:

部分內(nèi)容參考了相關(guān)網(wǎng)絡(luò)博客和書籍。

(1)單層網(wǎng)絡(luò)

單層網(wǎng)絡(luò)的結(jié)構(gòu)類似下圖:

輸入的x經(jīng)過變換wx+b激活函數(shù)f得到輸出y。

相信對機(jī)器學(xué)習(xí)/深度學(xué)習(xí)有初步了解的同學(xué)都知道,這其實就是單層感知機(jī)嘛~~~

為了方便起見,我們把它畫成這樣(請忽視我拙劣的繪圖水平):

x為輸入向量,y為輸出向量,箭頭表示一次變換,也就是y=f(Wx+b)。

(2)經(jīng)典RNN

在實際中,我們會遇到很多序列形的數(shù)據(jù):

X1,X2,X3,X4...

例如我們的機(jī)器翻譯模型,X1可以看作是第一個單詞,X2可以看作是第二個單詞,以此類推。

原始的神經(jīng)網(wǎng)絡(luò)并不能很好地處理序列形的數(shù)據(jù),于是救世主RNN出現(xiàn)了,它引入了隱狀態(tài)h的概念,利用h對序列形的數(shù)據(jù)提取特征,接著再轉(zhuǎn)換為輸出。下面詳細(xì)說明一下其計算過程(下圖中的h0為初始隱藏狀態(tài),為簡單起見,我們假設(shè)它是根據(jù)具體模型而設(shè)置的一個合理值):

其中:

再重申一遍,所有的字母均為向量,箭頭代表對向量做一次變換。

h2的計算與h1類似,并且每一步使用的參數(shù)P、Q、b都是一樣的,也就是說每個步驟的參數(shù)共享:

其中:

以此類推(記住參數(shù)都是一樣的?。?!),該計算可以無限地持續(xù)下去(不限于圖中的長度4?。。?/span>)。

那么RNN的輸出又如何得到呢?

RNN的輸出值是通過h進(jìn)行計算的:

其中:

類似地,有y2、y3、y4...:

當(dāng)然,和前面一樣,這里的參數(shù)W和c也是共享的。

以上就是最經(jīng)典的RNN結(jié)構(gòu),我們可以發(fā)現(xiàn)其存在一個致命的缺點:

輸入和輸出序列必須是等長的!

這個缺點導(dǎo)致了經(jīng)典RNN的適用范圍并沒有想象中的那么大。

(3)改進(jìn)經(jīng)典RNN

情況1(輸入為N,輸出為1):

假設(shè)我們的問題要求我們輸入的是一個序列,輸出的是一個單獨的數(shù)值。那么我們只在最后一個h上進(jìn)行輸出變換就可以了:

情況2(輸入為1,輸出為N):

當(dāng)輸入只是單一數(shù)值而非序列時該怎么辦呢?

我們可以只在序列開始進(jìn)行輸入計算:

當(dāng)然你也可以把輸入信息x作為每個階段的輸入:

情況3(輸入為N,輸出為M):

這是RNN最重要的一個變種,這種結(jié)構(gòu)也被稱為:

Encoder-Decoder模型,或者說Seq2Seq模型

我們的機(jī)器翻譯模型就是以它為基礎(chǔ)的。

Seq2Seq結(jié)構(gòu)先將輸入數(shù)據(jù)編碼成一個上下文量c

其中:

即上下文量c可以直接等于最后一個隱藏狀態(tài),也可以是對最后的隱藏狀態(tài)做一個變換V得到,當(dāng)然也可以是對所有的隱藏狀態(tài)做一個變換V得到等等。

上述RNN結(jié)構(gòu)一般稱為Encoder。

得到c之后,我們需要另外一個RNN網(wǎng)絡(luò)對其進(jìn)行解碼操作,即Decoder。你可以把這個c當(dāng)作初始狀態(tài)h'0輸入到Decoder中:

當(dāng)然你也可以把c當(dāng)作Decoder每一步的輸入:

算了,補充說明一下吧:

缺少輸入的部分(比如某些藍(lán)色的方塊沒有x輸入)你完全可以把x作為0處理然后再代入經(jīng)典RNN所列出的公式中計算輸出,其他的也類似。

(4)Attention機(jī)制

在Encoder-Decoder結(jié)構(gòu)中,Encoder把所有的輸入序列都編碼成一個統(tǒng)一的語義特征c后再進(jìn)行解碼,當(dāng)輸入序列較長時,c很可能無法勝任存儲輸入序列所有信息的任務(wù)。

Attention機(jī)制很好地解決了上述問題。它在Decoder每一步輸入不同的c:

其中,c根據(jù)Encoder中的h生成:

aij代表Encoder中第j階段的hj和Decoder中第i階段的相關(guān)性。

那么這些權(quán)重aij該如何確定呢?aij自然也是從模型中學(xué)得的,我們一般認(rèn)為它與Encoder的第j個階段的隱狀態(tài)和Decoder的第i-1階段的隱狀態(tài)有關(guān)。

比如我們要計算a1j:

然后我們需要計算a2j:

以此類推。

(5)最后任務(wù):法語翻譯成英語

有了前面的鋪墊,相信大家都能看懂官網(wǎng)的教程。

在這里我們僅做簡單的介紹,詳細(xì)的建模和實現(xiàn)過程可以參考我翻譯的官方文檔。

Encoder網(wǎng)絡(luò)為:

Decoder網(wǎng)絡(luò)為:

其中,encoder最后一個隱藏狀態(tài)作為decoder的初始隱藏狀態(tài)。attention機(jī)制的權(quán)重計算類似(4)中所述。GRU網(wǎng)絡(luò)的結(jié)構(gòu)為:

GRU網(wǎng)絡(luò)結(jié)構(gòu)在此就不作詳細(xì)的介紹了,篇幅太長的話估計沒人看得下去吧,就先這樣了~~~

在相關(guān)文件中我也提供了4篇相關(guān)的論文供感興趣者閱讀與研究。(T_T純英文的~~~)

結(jié)果展示

在cmd窗口運行Translation.py文件即可。

誤差曲線:

訓(xùn)練過程中cmd窗口的輸出:

模型測試:

作為對比:

和最后一個測試結(jié)果一模一樣有木有!??!

當(dāng)然,有些翻譯結(jié)果就不怎么理想了。因為模型和訓(xùn)練數(shù)據(jù)過于簡單了(T_T這里就不舉例了)~~~

最后四句話的attention圖:

That's all~~~


更多

感興趣的同學(xué)可以進(jìn)一步修改模型來獲得更好的結(jié)果,當(dāng)然也可以找找其他數(shù)據(jù)集制作諸如中翻英之類的模型~~~

0 人點贊