語言生成:搜索 or 取樣,that is the question

  • 2019 年 12 月 6 日
  • 筆記

目前,文本自然語言處理任務中,大體可分為 NLU(自然語言理解)NLG (自然語言生成)兩大方向。

對於 NLU,現在已經找到了它的殺手鐧,正是時不時刷榜一次的預訓練模型,只要模型夠大,數據夠多,訓練夠長,屠榜都不是問題。在有些 NLU 任務上已毫無懸念地超過了人類,當然是否真的理解還有待探索,可參考近期博文 NLP's Clever Hans Moment has Arrived

雖然預訓練模型在 NLU 有如此大進展,但如何用 BERT 系列模型做生成仍然是一個問題,其中也有些嘗試,但都感覺有些不盡人意,特別是開放域。

現在已知預訓練模型在語言生成任務上表現好的,有比如 UniLMMASS。其中 MASS 在今年機器翻譯大賽 WMT 上還取得了冠軍。

然而機器翻譯只是語言生成的一端,在語言生成的另一端,還存在著諸如聊天機器人,故事生成這樣,現在尚未表現很好的任務。如果將這些語言生成任務放在一個坐標上就如下圖。

在坐標軸左邊可看作生成更注重準確性,一般也都有比較好的評判指標,比如 BLEU,對於這種任務,通過大模型大數據也能夠解決。而在坐標軸右邊則可看作更注重生成的創造性更加開放,也沒有合適評估指標,只能用人來評測。

對於這些創造性生成任務,我認為其中關鍵可能並不在於 bigger and more,而在於對語言以及心理的更多理解,在生成時用各種策略來迎合人類。

比如說今年 ACL 中 Facebook 一篇論文《What makes a good conversation? How controllable attributes affect human judgments》,就通過控制生成時的幾個屬性,而讓一個兩層的 LSTM seq2seq 模型在一些評判上取得了用巨大 GPT 精調出的對話系統一樣效果。

對生成進行控制也可分為訓練時與生成時,關於訓練時的策略最近有篇很有意思的論文,我也有寫相關的介紹《神經語言生成的非似然訓練》

而這裡就來介紹目前在生成時常用到的策略,首先是對坐標軸左端很有效的搜索(Search),然後是對坐標軸最右端很有效的取樣(Sample)

首先假定已經有一個訓練好的生成器,無論結構,可根據當前輸入,給出對應位置預測的概率分布

搜索

貪婪搜索

對於語言生成,最簡單的做法便是 Greedy Search(貪婪搜索),想法也便理所當然地對於每個時步(time step)直接取概率最大的預測

該方法可以作為基準線來看模型訓練是否有問題,或者要求不太高的生成。

但該方法,會因為太短視,導致容易陷入局部最優,最容易理解的例子便是俗語翻譯,比如說「鶴蚌相爭,漁翁得利」,如果用 Greedy Search,開始給「鶴蚌」這樣字的概率會比較低,只有當看到是俗語時,才會給它高概率。

束搜索

為了解決上述問題提出了 Beam Search(束搜索)。

首先理解什麼是 beam,可以把它看作是一個候選容器,放著當前探索中概率最高的一些候選,而容器容量就叫做 beam size。更簡單的理解 beam size,可以把它當作是能夠派遣出去探索的偵察兵,對可能性大的地方我們就會多派些兵力。當 beam size 等於 1 時,其實就是貪婪搜索了。

這樣能讓生成時有更多探索空間,更不易陷入局部最優。

具體做法是,假設 beam size 為 k:

  1. 選取當前分數最大的 k 個候選放入 beam
  2. 然後開始看每個候選下一步預測
  3. 從所有預測中取總分最大 k 個候選放入 beam
  4. 當候選中有生成結束符,將候選拿出,beam size 減 1
  5. 繼續下一步預測 …
  6. 直到 beam size 為 0,結束搜索,取分最高為結果。

非常推薦吳教授關於 beam search 的講解 Beam Search.

我自己畫的簡單示意圖:

關於束搜索中排序用的分數,圖中為了簡單直接用概率加和,但一般會用 logprob(也就是log(prob)) 的加和。但這樣會出現一個問題,因為 logprob 是負的,如果加和,生成結果中短句分數就會比較大,於是傾向於生成短句,而這當然不是我們想要的。

於是針對束搜索生成較長句就有好幾種策略,比較經典的包括

  1. 分數直接除以生成長度
  2. Google長度懲罰項,除以下列項(其中m是長度,alpha 為係數)
  1. 詞獎勵法,讓分數加上 r*m,其中 r 是對每個詞的獎勵,m 為句長。

一般來說 2,3 效果要比 1 好些。

雖然通過懲罰項解決束搜索輸出過短問題,但它還存在很多其他問題,特別是對像聊天機器人這樣任務。

束搜索的問題

首先因為現在訓練語言模型用的是最大似然法,當在大量對話語料上訓練,然後用束搜索這樣取最大概率方式來生成對話時,就會出現生成對話太普通了,沒有多樣性,不太像人對話

比如說研究人員通過列出束搜索和真實人類對話中詞概率分布就發現,相比起人的對話,束搜索生成的對話更缺少意外性。舉個很常見的例子,簡單束搜索的生成式對話系統總會說,「我也是」,「好的」這樣沒營養的話。

其實也理所當然,因為本身束搜索的定義就是每次只取概率最高几個。

因此就需要通過取樣來解決該問題。

取樣

為解決搜索生成太乏味,可以通過取樣來增加隨機性,也就是上面所要的意外性。但增加隨機性同時,會出現另一個問題,那就是生成可能會出現語法錯誤

舉個栗子,假如說對全體詞按照預測概率來取樣,就可能出現取樣到低概率詞,從而在語法上導致整句話出現問題。

那麼怎樣避免該情況發生呢?可以通過強化頂部詞的概率,然後只對最有可能的一些詞進行取樣,這樣就能夠在增加隨機性的同時,又保證不出現一般性的錯誤

強化頂部詞概率,可以通過對模型輸出的 logits 除以一個小於 1 的溫度(Temperature,T)。

這樣就能在過 softmax 後使得分布更加尖銳,大概率的詞概率更大。

之後根據獲得概率對頂部詞先進行挑選,然後再取樣,這樣直接杜絕了低概率詞出現的可能性。

而這裡挑選的策略,目前最主流的便是,TopKTopP.

TopK 取樣

關於 TopK 取樣,就是挑選概率最高 k 個 token,然後重新過 softmax 算概率,之後根據獲得概率進行取樣,接著進行下一步生成,不斷重複。

一個簡單的示例如下,假設 K=2:

但關於 TopK 有可能會出現一個問題,那便是,假如說遇上一種情況,模型對當前生成非常肯定,比如說概率最高的 token 的概率就有 0.9,而剩下的 token 概率都很低了。而如果這個時候,還單純的用 topk 取樣的話,就會導致之前想避免的取樣到低概率情況仍然發生。

因此我們需要對頂部 token 的累計概率進行限制,這就是 TopP 取樣

TopP(Nucleus)取樣

和 TopK 單純限制取頂部 k 個不同,TopP 是先設置一個概率界限,比如說 p=0.9,然後從最大概率的 token 往下開始取,同時將概率累加起來當取到大於等於 p 也就是 0.9 時停止

以上一節提到來說,如果最大 token 概率就已經有 0.9 了,那麼就只取最大的一個 token。

關於 TopP 簡單的示意圖如下:

最後關於 TopP 和 TopK 實際應用,還有參數設置,借鑒 GPT2 中的設置,一般設置參數為 temperature 設 0.9,TopK 和 TopP 一起使用,k 取 40,p 取 0.9,至於效果,看了 GPT2 生成的結果可能也都了解。


本文轉載自公眾號:安迪的寫作間,作者:Andy