神經機器翻譯(seq2seq RNN)實現詳解

http://c.biancheng.net/view/1947.htmlhtml

seq2seq 是一類特殊的 RNN,在機器翻譯、文本自動摘要和語音識別中有着成功的應用。本節中,咱們將討論如何實現神經機器翻譯,獲得相似於谷歌神經機器翻譯系統獲得的結果(https://research.googleblog.com/2016/09/a-neural-network-for-machine.html)。

關鍵是輸入一個完整的文本序列,理解整個語義,而後輸出翻譯結果做爲另外一個序列。閱讀整個序列的想法與之前的架構大相徑庭,在該架構中,一組固定詞彙從一種源語言翻譯成目標語言。

本節受到 Minh-Thang Luong 於 2016 年所寫的博士論文「Neural Machine Translation」的啓發。第一個關鍵概念是編碼器–解碼器架構,其中編碼器將源語句轉換爲表示語義的向量,而後這個向量經過解碼器產生翻譯結果。

編碼器和解碼器都是 RNN,它們能夠捕捉語言中的長距離依賴關係,例如性別一致性和語法結構,而沒必要事先知道它們,也不須要跨語言進行 1:1 映射。它可以流利地翻譯而且具備強大的功能。python



圖 1 編碼器–解碼器示例


來看一個 RNN 例子:將 She loves cute cats 翻譯成 Elle aime les chats mignons。有兩個 RNN:一個充當編碼器,一個充當解碼器。源語句 She loves cute cats 後面跟着一個分隔符「-」和目標語句 Elle aime les chats mignon。這兩個關聯語句被輸入給編碼器用於訓練,而且解碼器將產生目標語句 Elle aime les chats mignon。固然,須要大量相似例子來得到良好的訓練。git



圖 2 NMT的序列模型示例

NUM序列模型,一個深度循環結構示例,用於將源語句「She loves cute cats」 翻譯成目標語句「Elle aimel les chats mignons」。解碼器側,前面時序中產生的單詞做爲輸出下一個單詞的輸入,「_」表明語句的結束。github

如今有一些可使用的 RNN 變體,具體介紹其中的一些:算法

  • RNN 能夠是單向的或雙向的,後者將捕捉雙向的長時間依賴關係。
  • RNN 能夠有多個隱藏層,層數的選擇對於優化來講相當重要...更深的網絡能夠學到更多知識,另外一方面,訓練須要花費很長時間並且可能會過分擬合。
  • RNN 能夠有多個隱藏層,層數的選擇對於優化來講相當重要...更深的網絡能夠學到更多知識,另外一方面,訓練須要花費很長時間並且可能會過分擬合。
  • RNN 能夠具備嵌入層,其將單詞映射到嵌入空間中,在嵌入空間中類似單詞的映射剛好也很是接近。
  • RNN 可使用簡單的重複性單元、LSTM、窺孔 LSTM 或者 GRU。


仍然考慮博士論文「Neural Machine Translation」,可使用嵌入層將輸入的句子映射到一個嵌入空間。而後,存在兩個鏈接在一塊兒的 RNN——源語言的編碼器和目標語言的解碼器。以下圖所示,有多個隱藏層和兩個流動方向:前饋垂直方向鏈接隱藏層,水平方向是將知識從上一步轉移到下一步的循環部分。api



圖 3 神經機器翻譯示例


本節使用 NMT(Neural Machine Translation,神經機器翻譯),這是一個在 TensorFlow 上在線可得的翻譯演示包。網絡

NMT 可經過https://github.com/tensorflow/nmt/ 獲取,具體代碼可經過 GitHub 獲取。架構

具體實現過程

  1. 從 GitHub 克隆 NMT:


     
  2. 下載一個訓練數據集。在這個例子中,使用訓練集將越南語翻譯成英語,其餘數據集能夠在https://nlp.stanford.edu/projects/nmt/上得到,如德語和捷克語:


     
  3. 參考https://github.com/tensorflow/nmt/,這裏將定義第一個嵌入層,嵌入層將輸入、詞彙量尺寸 V 和指望的輸出尺寸嵌入到空間中。詞彙量尺寸 V 中只有最頻繁的單詞才考慮被嵌入,全部其餘單詞則被打上 unknown 標籤。在本例中,輸入是 time-major,這意味着 max time 是第一個輸入參數(https://www.tensorflow.org/api_docs/python/tf/nn/dynamic_rnn):


     
  4. 仍然參考 https://github.com/tensorflow/nmt/,這裏定義一個簡單的編碼器,它使用 tf.nn.rnn_cell.BasicLSTMCell(num_units) 做爲基本的 RNN 單元。雖然很簡單,但要注意給定基本 RNN 單元,咱們利用 tf.nn.dynamic_rnn 構建了 RNN 的(見https://www.tensorflow.org/api_docs/python/tf/nn/dynamic_rnn):


     
  5. 定義解碼器。首先要有一個基本的 RNN 單元:tf.nn.rnn_cell.BasicLSTMCell,以此來建立一個基本的採樣解碼器 tf.contrib.seq2seq.BasicDecoder,將結果輸入到解碼器 tf.contrib.seq2seq.dynamic_decode 中進行動態解碼。


     
  6. 網絡的最後一個階段是 softmax dense 階段,將最高隱藏狀態轉換爲 logit 向量:


     
  7. 定義在訓練階段使用的交叉熵函數和損失:


     
  8. 定義反向傳播所需的步驟,並使用適當的優化器(本例中使用 Adam)。請注意,梯度已被剪裁,Adam 使用預約義的學習率:


     
  9. 運行代碼並理解不一樣的執行步驟。首先,建立訓練圖,而後開始迭代訓練。評價指標是 BLEU(bilingual evaluation understudy),這個指標是評估將一種天然語言機器翻譯爲另外一種天然語言的文本質量的標準,質量被認爲是算法的結果和人工操做結果的一致性。正如你所看到的,指標值隨着時間而增加:

解讀分析

全部上述代碼已經在 https://github.com/tensorflow/nmt/blob/master/nmt/model.py 上給出。關鍵是將兩個 RNN 打包在一塊兒,第一個是嵌入空間的編碼器,將類似的單詞映射得很接近,編碼器理解訓練樣例的語義,併產生一個張量做爲輸出。而後經過將編碼器的最後一個隱藏層鏈接到解碼器的初始層能夠簡單地將該張量傳遞給解碼器。函數

請注意,學習可以進行是由於損失函數基於交叉熵,且labels=decoder_outputs。學習

以下圖所示,代碼學習如何翻譯,並經過BLEU指標的迭代跟蹤進度:


下面咱們將源語言翻譯成目標語言。這個想法很是簡單:一個源語句做爲兩個組合的 RNN(編碼器+解碼器)的輸入。一旦句子結束,解碼器將發出 logit 值,採用貪婪策略輸出與最大值相關的單詞。

例如,單詞 moi 做爲來自解碼器的第一個標記被輸出,由於這個單詞具備最大的 logit 值。此後,單詞 suis 輸出,等等:

圖 5 帶機率分佈的NMT序列模型示例


解碼器的輸出有多種策略:

  1. 貪婪:輸出對應最大logit值的單詞。
  2. 採樣:經過對衆多logit值採樣輸出單詞。
  3. 集束搜索:有多個預測,所以建立一個可能結果的擴展樹。

翻譯實現過程

  1. 制定解碼器採樣的貪婪策略。這很簡單,由於可使用 tf.contrib.seq2seq.GreedyEmbeddingHelper 中定義的庫,因爲不知道目標句子的準確長度,所以這裏使用啓發式方法將其限制爲源語句長度的兩倍。


     
  2. 如今能夠運行網絡,輸入一個從未見過的語句(inference_input_file=/tmp/my_infer_file),並讓網絡轉換結果(inference_output_file=/tmp/nmt_model/output_infer):


兩個 RNN 封裝在一塊兒造成編碼器–解碼器 RNN 網絡。解碼器發出的 logits 被貪婪策略轉換成目標語言的單詞。做爲一個例子,下面顯示了一個從越南語到英語的自動翻譯的例子:

相關文章
相關標籤/搜索