這篇文章是im2latex系列的第一篇,希望能夠講清楚基於attention的Sequence-to-Sequence和Beam Search的一些基本概念。從公式圖片直接到latex代碼已經有好些解決方案了,比如這個網站,用戶評價還不錯:

如果你對Seq2Seq很熟悉了,想直接跳到tensorflow

代碼部分的話。

直接看代碼吧

介紹

在上一篇命名實體識別中,博主介紹了一個相對簡單的任務:如何去預測一個單詞的屬性。如果是翻譯之類的任務就需要設計比較複雜的系統了。我們知道最近神經機器翻譯已經取得了很大的突破---(幾乎)可以達到人類的水平了(比如Google翻譯已經被大量應用在生活中,具體參考文章Googles Multilingual Neural Machine Translation System: Enabling Zero-Shot Translation)。這些新的結構依賴於一種稱為Encoder-Decoder的的結構,可以用於產生特定實體的目標序列。

閱讀這篇文章前,假定你對深度學習的基礎知識(卷積CNN,長短時記憶LSTM…)之類的基本概念已經很熟悉了。如果還對這些CV和NLP方面的知識不是很熟悉,建議可以先看看大名鼎鼎的斯坦福公開課CS231n和CS224n。

Sequence to Sequence 基本概念

先介紹我們使用的模型中最重要的Sequence to Sequence框架。先從翻譯任務中最簡單的版本說起。

舉個??,翻譯」how are you「成中文「幹哈呢」.(法語:comment vas tu)

普通Seq2Seq

Seq2Seq模型依賴於encoder-decoder結構。Encoder端對輸入序列編碼,然後Decoder端產生解碼後的目標序列。

編碼器

上個例子中我們的輸入序列是「how are U」。每個輸入序列的單詞被轉化為了一個向量? Win R^{d} (這一過程通過速查表實現)。上個例子中有3個單詞,這樣輸入將會被轉化為? [W_{0}, W_{1},W_{2}] in R^{d	imes3} .之後,輸入向量序列進入LSTM,存儲下LSTM輸出的最後一層隱藏層狀態:這就是編碼器的編碼結果 e 了。寫下這裡的隱藏層狀態: [ e_{0},e_{1},e_{2} ?] (本例中是? e=e_{2} )。

解碼器

現在有了向量 e 捕獲了輸入序列的信息,下面使用它來一個單詞一個單詞的產生目標單詞序列。隱層狀態 e ?和特殊的開始標記 ? W_{sos} 向量作為輸入來送入LSTM單元。LSTM計算了下一個隱藏層狀態 h_{0}in R^{h} ?。然後應用函數  g : R^{h}Rightarrow R^{V} ? ,這樣? s_{0} := g(h_{0}) 是辭彙表中同樣大小的向量。

h_{0} = LSTM(e, w_{sos}),

   s_{0} = g(h{_0}) ,

  p_{0} = softmax(s_{0})  ,

  i_{0} = argmax(p_{0})

之後,? s_{0} 經過softmax後進入概率矩陣? p_{0}in R^{V} 。每個實體的 p_{0} ? 用來衡量它和單詞表中的單詞的相似度。可以說「幹」(「你幹啥?」中的「幹」)具有最高的概率(也就說? i_{0} = argmax(p_{0}) 對應「幹」的索引)。得到對應的向量 W_{i_{0}} = W_{幹} ?,然後重複這個過程:繼續將隱藏層狀態? h_{0}W_{幹} 輸入LSTM,LSTM再輸出對應第二個詞的概率矩陣 p_{1} ?...

 h_{1} = LSTM(h_{0}, w_{i_{0}}) ,

  s_{1} = g(h{_1})  ,

   p_{1} = softmax(s_{1})  ,

 i_{1} = argmax(p_{1})

當解碼器遇到特殊停止符(往往是"<eos>")的時候,解碼過程就會停止。

直覺上說,隱藏層向量就是還未被解碼的信息。

上述方法旨在下一個單詞在句子開頭已知情況下的條件概率分佈:

P[y_{t+1}|y_{1},...,y_{t},x_{0},...,x_{n}] 簡寫為: P[y_{t+1}|y_{t},h_{t},e]

加入attention的Seq2Seq

託attention的福,這兩年上面的Seq2Seq模型已經大變樣了。Attention是一種讓模型在解碼時學習集中關注輸入序列特定部分的模型,而不再僅僅依靠解碼中LSTM隱藏層向量的部分。關於attention的詳細介紹請參閱文章Neural Machine Translation by Jointly Learning to Align and Translate。這裡我們稍微修改一下上面的公式,在LSTM的輸入部分加入一個新的向量? c_{t}

h_{t} = LSTM(h_{t-1}, [w_{i_{t-1}}, c_{t}]) ,

s_{t} = g(h_{t}) ,

p_{t} = softmax(s_{t}) ,

i_{t} = argmax(p_{t})

向量 c_{t}就是注意力(或稱上下文context)向量。每一步解碼的過程計算一個新的注意力向量。首先,使用函數? f(h_{t-1}, e_{t_{old}})Rightarrow alpha_{t_{old}} in R 計算編碼器每一個隱藏層狀態? e_{t_{old}} 的分數;之後使用softmax規範化 alpha_{t_{old}} ?,然後與? e_{t_{old}} 加權計算 c_{t} ?:

alpha_{t_{old}} = f(h_{t-1}, e_{t_{old}}) in R for all  t_{old}

overline{alpha} = softmax(alpha) ,

c_{t} = sum_{t_{old}=0}^noverline{alpha}_{t_{old}}{e_{t_{old}}}

在這裡,計算注意力向量? alpha_{t_{old}}的函數?那可就多啦,一般來說常用的也就下面幾種:

這樣子注意力權重? overline{alpha} 很容易解釋了。當產生單詞vas的時候(對應英語are),我們期望? overline{alpha}_{are} 接近1,而? overline{alpha}_{how} 和? overline{alpha}_{you} 接近0。直覺上注意力向量? c 大致接近are的隱含層向量,它有助於產生法語單詞vas

通過將注意力權重送入矩陣(行=輸入序列,列=輸出序列),我們就可以「對齊」輸入的英語單詞和輸出的法語單詞了(參見文章第六頁)。關於Seq2Seq模型還有好多可以探討的地方,比如編碼器可以雙向處理輸入序列,限於篇幅,這裡不再展開了。

訓練

如果第一次產生的序列並不太確定是comment還是vas(訓練開始很大程度都可能遇到)的話,會怎麼樣呢?那整個輸出序列就全亂了,模型也很難學到什麼東西了....

如果我們使用訓練中預測的輸出來作為下一步的輸入,錯誤就會一直累積下去,模型很難收斂到正確的輸入分佈上。這會使訓練過程很慢甚至不可訓練。為加快訓練過程,可以將真實的輸出序列 (`<sos>` `comment` `vas` `tu`)送入解碼LSTM來預測每次下一步驟產生的輸出 (comment``vas tu <eos>)。

解碼器在每一步輸出概率矩陣? p_{i}in R^{V} 。對於每一個給定的目標輸出序列 y_{1},...y_{n} ?,我們在每一步計算每個輸出的概率: P(y_{1},...y_{m}) = prodlimits_{i=1}^m p_{i}[y_{i}]

這裡? p_{i}[y_{i}] 代表在第i個解碼步驟中提取第? y_{i} 個實體的概率? p_{i} 。這樣,我們可以計算真實的目標序列概率。一個完美的系統可以輸出目標序列接近1的概率,所以我們訓練網路來最大化輸出目標序列的概率,也就是最小化這個目標:  -log P(y_{1},...,y_{m}) = -log prodlimits_{i=1}^m p_{i}[y_{i}]\                                           = -sum_{i=1}^{n}log p_{i}[y_{i}]

在我們這個例子中,也就等於

 -log p_{1}[comment]-log p_{2}[vas]-log p_{3}[tu]-log p_{4}[<eos>]

這不就是標準的交叉熵嗎!我們實際上在最小化目標分佈和我們模型(概率? p_{i} )預測的輸出分佈之間的交叉熵!

解碼

上述討論中主要的問題是對於同一個模型,我們可以有不同的行為。特別在加速訓練的時候。

那在推理/測試階段呢?是不是有另外的方式來解碼(翻譯)一個句子呢?

的確,在測試階段有兩種方法來解碼(測試就是翻譯一個我們還沒有翻譯過的句子)。一種就是我們文章開始提到的解碼方式:greedy decoding。它包含了上次預測的值最可能進入下次的方式,也是最自然的解碼方式。

但你不覺得這種方式也在累積誤差嗎?

即便訓練好了模型,也可能恰巧模型出了點小毛病(可能首次預測 vas 的概率高於 comment )。那整個的解碼過程就徹底崩了!

有種更好的解碼過程,叫Beam Search:相對於僅預測最高分數的輸出,可以在預測的時候跟蹤最有可能的K個候選(比如K=5,我們就使用5作為Beam Search的大小)。在每一個新的預測(解碼)步驟,對每5個候選我們可以有V個新的輸出。這一下子就有了5V個新的候選。然後再選擇其中5個最靠譜的,這一過程繼續下去.... 上公式,定義? mathcal{H}_ t 為第t個步驟的解碼候選集合。

mathcal{H}_ t := { (w^1_1, dots, w^1_t), dots, (w^k_1, dots, w^k_t) }

再舉個??,如果k=2,這時 mathcal{H}_ 2 可能就是:

mathcal{H}_ 2 := { (	ext{comment vas}), (	ext{comment tu}) }

現在通過增加新的字元,我們考慮所有從 mathcal{H}_ t 產生的可能的候選 mathcal{C}_ {t+1} ?,: C_{t+1} := igcup^{k}_{i=1}{(w^{i}_{1},...w^{i}_{i},1),...(w^{i}_{1},...w^{i}_{i},V) }

保持K個最高的得分序列。在我們的例子中:

C_{3} = {(comment,vas,comment), (comment,vas,vas), (comment,vas,tu)}igcup {(comment,tu,comment)}

我們假設最高的兩個是:

H_{3} := { (comment, vas, tu),(comment, tu, vas) }

每次候選遇到 <eos> 標誌,就返回最高得分的候選。

如果我們使用Beam Search,因為我們保持著最優候選集合,初始步驟的小錯誤會在下一步被修正。

結論

本文介紹了Seq2Seq的幾個概念。可以看到訓練和解碼部分不太一樣。也介紹了兩種解碼方法:greedybeam search。雖然beam search可以取得較好的結果,但是它依然存在exposure bias。訓練階段,模型不會exposed到錯誤。他也會有Loss-Evaluation mismatch。模型是通過輸出字元級別的交叉熵來優化的,而我們更感興趣的是整個句子結構的重建....

下面,讓我們應用Seq2Seq來將公式圖片自動生成LaTex公式吧! 上代碼!

Seq2Seq經典論文:

  • Sequence to Sequence Learning with Neural Networks
  • Neural Machine Translation by Jointly Learning to Align and Translate
  • Effective Approaches to Attention-based Neural Machine Translation
  • Neural Machine Translation in Linear Time
  • Convolutional Sequence to Sequence Learning
  • Attention Is All You Need

試圖解決一些一些侷限性的文章:

  • An Actor-Critic Algorithm for sequence prediction
  • Sequence-to-Sequence Learning as Beam-Search Optimization
  • Six Challenges for Neural Machine Translation
  • Professor Forcing: A New Algorithm for Training Recurrent Networks

全文翻譯自Guillaume Genthial的博客。

推薦閱讀:

相關文章