生成式對話seq2seq:從rnn到transformer

一、前言

最近因爲做對話機器人的原因,看了一下seq2seq。不禁感慨,自由對話機器人的水好深呀。

查閱了一些市面上能看到資料,工業上的做法,普遍是 基礎模板(例如 aiml)+IR閒聊庫(例如 小黃雞語料QA)+爬蟲(百度、搜狗)+知識圖譜(wiki百科)+對話生成模型。

aiml模板就不說了,網上有很多的資料,效果上來說,比較智障。人工編寫模板的工作量也大,也不能覆蓋很多的回答。

IR閒聊庫的方法,理論上來說,面對單輪閒聊的話,能產生流暢的回覆,通俗的說就是能說人話,畢竟是從正常的對話記錄中去檢索的。實現上的話,方式就很多了,詞面上的編輯距離,tfidf,bm25等等。模型上就是Response Selection in Retrieval-Based Chatbots這類的。不過後面出現了多輪的Retrieval-Based Chatbots,諸如:SMN(Sequential Matching Network)、DAM(Deep Attention Matching Network)、IMN(Interactive Matching Network)和MRFN(Multi-Representation Fusion Network)這些多輪檢索式對話。因爲,不是本文所要討論的話題,所以,具體的大家去看論文吧。

參考:https://zhuanlan.zhihu.com/p/65062025

https://zhuanlan.zhihu.com/p/46366940

https://www.jianshu.com/p/01a0ec0370c4

爬蟲類的,就不說了,具體的大家可以看一下:QA-Snake(https://github.com/SnakeHacker/QA-Snake)

圖譜的話,網上資料很多,我這裏簡單說一下我知道的一般的實現方案:

1)NER,獲取需要的實體詞,具體可以分爲非監督的實現(模板,詞典),監督的實現(lstm+crf,crf)。

2)將得到的實體詞,送入圖譜檢索到可能三元組集合。

3)將三元組集合的屬性和問句進行打分(其實就是做一個2分類),選出合適的三元組。

 

二、seq2seq

接下來,就是本文主要說的內容了seq2seq。seq2seq也就是encoder2decoder。

Seq2Seq(Sequence to Sequence), 就是一種能夠根據給定的序列,通過特定的方法生成另一個序列的方法。它被提出於2014年,最早由兩篇文章獨立地闡述了它主要思想,分別是Google Brain團隊的《Sequence to Sequence Learning with Neural Networks》(https://arxiv.org/pdf/1409.3215.pdf)和Yoshua Bengio團隊的《Learning Phrase Representation using RNN Encoder-Decoder for Statistical Machine Translation》(https://arxiv.org/pdf/1406.1078.pdf)。

同年9月,隨着Bahdanau的《Neural Machine Translation by Jointly Learning to Align and Translate》(https://arxiv.org/pdf/1409.0473.pdf)橫空出世,也就是大名鼎鼎的NMT模型,隨着attention被引入到seq2seq模型,從而解決原來rnn長序列的long-term問題,模型準確度隨之得到提升。

下面,我們根據Pytorch的官方文檔https://pytorch.org/tutorials/beginner/chatbot_tutorial.html,通過GRU+Attention的樣例來熟悉一下seq2seq的模型吧。

 seq2seq模型的輸入是一個變長的序列,而輸出也是一個變長的序列。而且這兩個序列的長度並不相同。一般我們使用RNN來處理變長的序列,一般來說兩個RNN可以解決這類問題。

 

Encoder是一個RNN,它會遍歷輸入的每一個Token(詞),每個時刻的輸入是上一個時刻的隱狀態和輸入,然後會有一個輸出和新的隱狀態。這個新的隱狀態會作爲下一個時刻的輸入隱狀態。每個時刻都有一個輸出,對於seq2seq模型來說,我們通常只保留最後一個時刻的隱狀態,認爲它編碼了整個句子的語義。Encoder處理結束後會把最後一個時刻的隱狀態作爲Decoder的初始隱狀態。

但是後面我們會用到Attention機制,它還會用到Encoder每個時刻的輸出。

官方文檔中採用的是雙向Gated Recurrent Unit(GRU)作爲Encoder。

這裏需要說一下一般都會說的小知識點:

1)因爲RNN機制實際中存在長程梯度消失的問題,seq2seq引入attention

2)使用擁有gate的lstm避免RNN的梯度消失問題

3)GRU因爲使用更少的門,模型參數更小,因爲比lstm效率好

Decoder也是一個RNN,它每個時刻輸出一個詞。每個時刻的輸入是上一個時刻的隱狀態和上一個時刻的輸出。一開始的隱狀態是Encoder最後時刻的隱狀態,輸入是特殊的。然後使用RNN計算新的隱狀態和輸出第一個詞,接着用新的隱狀態和第一個詞計算第二個詞,...,直到遇到EOS,結束輸出。

 

三、attention

因爲上面小知識點第一個所說的問題,是當輸入句子很長的時候,encoder的效果會很差,利用隱狀態(context向量)來編碼輸入句子的語義實際上是很困難的。爲了解決這個問題,Bahdanau等人提出了注意力機制(attention mechanism)。於是在Decoder進行t時刻計算的時候,除了t-1時刻的隱狀態,當前時刻的輸入,注意力機制還可以參考Encoder所有時刻的輸入。

attention是一個值得聊一下的話題,下面來仔細說一下。

Attention函數的本質可以被描述爲一個查詢(query)到一系列(鍵key-值value)對的映射,如下圖。

在計算attention時主要分爲三步,第一步是將query和每個key進行相似度計算得到權重,常用的相似度函數有點積,拼接,感知機等;然後第二步一般是使用一個softmax函數對這些權重進行歸一化;最後將權重和相應的鍵值value進行加權求和得到最後的attention。

上面所說的score函數中,dot就是簡單的hidden*encoder outputs,注意這裏是用的dot點乘,就是對應位置元素相乘再求和,所以兩個向量點乘的結果是一個數。general將encoder output用一個全連接編碼後再和hidden點乘。concat是將hidden和outputs連接後再點乘一個隨機生成的向量。

 

簡而言之,attention實際上就是一種取權重求和的過程。結果是使得 跟 當前詞 有關的 前文的 部分詞 具有較強的權重。

attention有很多種形態,大家通常會說5種:hard attention,soft attention,Global Attention,local attention,self attention。

hard attention

Hard Attention不會選擇整個encoder的隱層輸出做爲其輸入,它在t時刻會依多元伯努利分佈來採樣輸入端的一部分隱狀態來進行計算,而不是整個encoder的隱狀態。在 hard attention 裏面,每個時刻 t 模型的序列 [ St1,…,StL ] 只有一個取 1,其餘全部爲 0,是 one-hot 形式。也就是說每次只focus 一個位置。

soft attention

對於hard attention,soft attention 每次會照顧到全部的位置,只是不同位置的權重不同罷了。

global attention

global attention 顧名思義,forcus 全部的 position。它 和 local attention 的主要區別在於 attention 所 forcus 的 source positions 數目的不同。

Local Attention:

Local Attention只 focus 一部分 position,則爲 local attention

global attention 的缺點在於每次都要掃描全部的 source hidden state,計算開銷較大,爲了提升效率,提出 local attention,每次只 focus 一小部分的 source position。

self attention

因爲transformer現在已經在nlp領域大放異彩,所以,我這裏打算詳細的說一下transformer的核心組件self-attention,雖然網上關於self-attention的描述已經很多了。

說起self-attention的提出,是因爲rnn存在非法並行計算的問題,而cnn存在無法捕獲長距離特徵的問題,因爲既要又要的需求,當看到attention的巨大優勢,《Attention is all you need》的作者決定用attention機制代替rnn搭建整個模型,於是Multi-headed attention,橫空出世。

Self-attention的意思就是自己和自己做 attention,即K=V=Q,例如輸入一個句子,那麼裏面的每個詞都要和該句子中的所有詞進行attention計算。目的是學習句子內部的詞依賴關係,捕獲句子的內部結構。

而Multi-head Attention其實就是多個Self-Attention結構的結合,每個head學習到在不同表示空間中的特徵。

 

multi-head attention 由多個 scaled dot-product attention 這樣的基礎單元經過 stack 而成。那什麼是scaled dot-product attention,字面意思:放縮點積注意力。使用點積進行相似度計算的attention,只是多除了一個(爲K的維度)起到調節作用,使得內積不至於太大。scaled dot-product attention跟使用點積進行相似度計算的attention差不多,只是多除了一個(爲K的維度)起到調節作用,使得內積不至於太大,有利於訓練的收斂。

 

Query,Key,Value 做embedding,獲得相應的word embedding,然後輸入到放縮點積attention,注意這裏要做h次,其實也就是所謂的多頭,每一次算一個頭。而且每次Q,K,V進行線性變換的參數W是不一樣的。然後將h次的放縮點積attention結果進行拼接,再進行一次線性變換得到的值作爲多頭attention的結果。可以看到,google提出來的多頭attention的不同之處在於進行了h次計算而不僅僅算一次,論文中說到這樣的好處是可以允許模型在不同的表示子空間裏學習到相關的信息。論文裏有attention可視化的圖,可以去看看。

self-attention的特點在於無視詞之間的距離直接計算依賴關係,能夠學習一個句子的內部結構,實現也較爲簡單並行可以並行計算。

如果你還想了解更多的attention,請查看:https://zhuanlan.zhihu.com/p/73357761

 

四、transformer

講到transformer,我就想到張俊林老師《放棄幻想,全面擁抱Transformer》(https://zhuanlan.zhihu.com/p/54743941)的一句話:“Transformer考上了北京大學;CNN進了中等技術學校,希望有一天能夠考研考進北京大學;RNN在百貨公司當售貨員:我們都有看似光明的前途。”

 

網上關於transformer的解讀已經很多了,我就不詳細說了,具體的細節推薦大家看《NLP預訓練模型:從transformer到albert》(https://zhuanlan.zhihu.com/p/85221503),我就說一說一些需要注意的點吧。

1)結構上transformer由encoder和decoder組成,decoder比encoder多了一個Multi-headed attention層。同時,這個Multi-headed attention的k,v來自encoder的輸出,而q來自於前一級的decoder層的輸出。

2)Self-Attention則利用了Attention機制,計算每個單詞與其他所有單詞之間的關聯。但是沒有recurrence或convolution操作,所以沒有明確的關於單詞在源句子中位置的相對或絕對的信息,爲了更好的讓模型學習位置信息,所以添加了position encoding並將其疊加在word embedding上。

3)Add代表了Residual Connection,是爲了解決多層神經網絡訓練困難的問題,通過將前一層的信息無差的傳遞到下一層,可以有效的僅關注差異部分。解決網絡退化問題。

4)Norm則代表了Layer Normalization,通過對層的激活值的歸一化,可以加速模型的訓練過程,使其更快的收斂

5)在multi-head attention後面加一個ffn,可以提高整個block的非線性變換的能力。

比單獨使用multi-head attention的效果更好。

 

 

五、bert和gpt之後的seq2seq

5.1 bert

2018年10月底,google的bert公佈,bert一舉打破11項nlp任務,並且大幅提升效果,成爲nlp的highlight時刻,並被人稱爲nlp界的Restnet。於是nlp界開始關注語言模型預訓練+少量數據下游任務調優的開發模式。

關於bert的解讀和後續發展,世面上已經有很多的解讀了,這裏就不浪費大家時間重複描述了,如果你有興趣可以閱讀:https://zhuanlan.zhihu.com/p/68295881https://zhuanlan.zhihu.com/p/68362016。我這裏就簡單說一下可能需要關注的點吧。

bert的優點和缺點

1)bert使用的是transformer的encoder部分。

2)bert的Embeding由三種Embedding求和而成,其中Position Embeddings和之前文章中的Transformer不一樣,不是三角函數而是學習出來的,而是一個大小爲 (512, 768)的lookup表。

3)bert比transformer多了Segment Embeddings,因爲預訓練不光做LM還要做以兩個句子爲輸入的分類任務

4)預訓練使用mask LM,就是在訓練過程中作者隨機mask 15%的token,最終的損失函數只計算被mask掉那個token。

5)Next Sentence Prediction,不過後來被證明效果不行,所以就不說了。

在bert大放異彩之後,後來出現了很多模型。如xlnet,spanbert,roberta,T5,除了帶來了更巧妙的tricks還有就是繼續着大力出奇跡的故事。

 

5.2 bert的壓縮提速

雖然bert之後,bert的後繼者還在續寫着SOTA,但是bert們的大計算量,顯存消耗,訓練消耗卻讓工業界望而卻步,無法及時的享受bert們的紅利。於是乎,bert模型的壓縮和提速被安排上了日程。

針對bert的壓縮主要有3個方向,Pruning,Distill,Quantization。而我這裏,主要說一下DistilBERT,ALBERT,TinyBERT3個模型。

首先需要說的是:DistilBERT

DistilBERT, a distilled version of BERT: smaller, faster, cheaper and lighter

論文:https://arxiv.org/abs/1910.01108

distillbert採用傳統的蒸餾方案,並將bert的block減少到6個。

先說結論:模型大小減小了40%(66M),推斷速度提升了60%,但性能只降低了約3%。

具體做法:

1)給定原始的bert-base作爲teacher網絡。

2)在bert-base的基礎上將網絡層數減半。

3)利用teacher的軟標籤和teacher的隱層參數來訓練student網絡。

訓練時的損失函數定義爲三種損失函數的線性和,三種損失函數分別爲:

1)Lce。這是teacher網絡softmax層輸出的概率分佈和student網絡softmax層輸出的概率分佈的交叉熵。

2)Lmlm。這是student網絡softmax層輸出的概率分佈和真實的one-hot標籤的交叉熵。

3)Lcos。這是student網絡隱層輸出和teacher網絡隱層輸出的餘弦相似度值。

 

接着,我們來談一下ALBERT

ALBERT: A Lite BERT for Self-supervised Learning of Language Representations

論文:https://arxiv.org/abs/1909.11942v2

代碼:https://github.com/brightmart/albert_zh

albert從3個方面對bert進行了改造,但是很遺憾的是,沒有提升模型的運算速度。

1、對Embedding因式分解(Factorized embedding parameterization)。將embedding維度從768下降到128。

2.跨層的參數共享(Cross-layer parameter sharing)。對全連接層與attention層都進行參數共享,即共享了encoder中所有的參數。效果顯著,以base爲例,BERT的參數是108M,而ALBERT僅有12M,效果僅降低2個點。

3、句間連貫(Inter-sentence coherence loss)。在BERT中,句子間關係的任務是next sentence predict(NSP)。作者認爲NSP任務只學到了句子的主題,而主題分類是一個淺層語義的NLP任務,所以nsp沒有什麼效果。而albert 句子間關係的任務是sentence-order prediction(SOP),即句子間順序預測。這裏因爲負例中的句子都來自於同一文檔,所以通過句子的主題是無法區分正例和負例的,需要理解句子的深層語義才能區分。

 

最後是TinyBERT

TinyBERT: Distilling BERT for Natural Language Understanding

論文:https://arxiv.org/abs/1909.10351

TinyBERT提出了針對Transformer結構的知識蒸餾和針對pre-training和fine-tuning兩階段的知識蒸餾。

1.對transfomer做蒸餾,作者構造了四類損失,分別針對embedding layer,attention 權重矩陣,隱層輸出,predict layer。

2.針對pre-training和fine-tuning兩階段的知識蒸餾,對pre-training蒸餾之外,在fine-tuning時也利用teacher的知識來訓練模型可以取得在下游任務更好的效果。

本質上就是在pre-training蒸餾一個general TinyBERT,然後再在general TinyBERT的基礎上利用task-bert上再蒸餾出fine-tuned TinyBERT。

3.albert的模型是6層block。

這裏需要特別說一下的是TinyAlbert,訓練和推理預測速度提升約10倍,精度基本保留,模型大小爲bert的1/25;語義相似度數據集LCQMC測試集上達到85.4%,相比bert_base僅下降1.5個點。我已經試用過,效果確實很贊。代碼地址:https://github.com/brightmart/albert_zh

 

5.3bert和GPT的seq2seq

上面說了一大堆bert相關的內容。下面迴歸我們的正題,因爲,我們討論的還是seq2seq模型。因爲bert是使用transformer的Encoder模塊作爲block,所以bert不是一個seq2seq的結構。所以,就有一些bert+Decoder(使用lstm或者gru)的結構在做seq2seq。但是效果上很一般。那麼有沒有使用bert的優雅的方式呢?答案是有的。

 

微軟提出了一個通用預訓練模型MASS(代碼:論文:https://arxiv.org/abs/1905.02450https://github.com/microsoft/MASS),採用了聯合encoder-attention-decoder的訓練框架。

Encoder: 輸入爲被隨機mask掉連續部分token的句子,使用雙向Transformer對其進行編碼;這樣處理的目的是可以使得encoder可以更好地捕獲沒有被mask掉詞語信息用於後續decoder的預測;

Decoder: 輸入爲與encoder同樣的句子,但是mask掉的正好和encoder相反(後面試驗直接將masked tokens刪去保留unmasked tokens position embedding),使用attention機制去訓練,但只預測encoder端被mask掉的詞。該操作可以迫使decoder預測的時候更依賴於source端的輸入而不是前面預測出的token,同時減緩了傳統seq2seq結構的exposure bias問題。

但是遺憾的是,MASS雖然在多個任務上拉高了SOTA,但是在對話生成任務上效果一般。

 

微軟隨後又推出了UNILM(論文:https://arxiv.org/abs/1905.03197,代碼:https://github.com/microsoft/unilm),相比較而言,MASS的工作是將BERT整合到seq2seq框架上,而UNILM則是將seq2seq整合到BERT的框架上,利用調整mask矩陣的設置在同一個框架下訓練不同任務,可同時用於NLU和NLG任務。NLU用BERT做,NLG則把BERT的 S1 [SEP] S2 當成 encoder-decoder。

具體的UNILM模型有以下3個優點:

(1)統一的預訓練流程,使得僅僅使用一個Transformer語言模型即可。該Transformer模型在不同的LM(上述Table 2中的3個LM)上共享參數,這就無需在多個LM上分別訓練和配置。

(2)多個LM之間的參數共享使得學習到的文本表徵具有更強的泛化能力。在不同的語言模型目標上聯合優化,使得上下文在不同方式中被使用,也減緩了在單一LM上的過擬合。

(3)除了可以應用到自然語言理解任務上,本文模型還能夠作爲一個sequence-to-sequence LM來處理自然語言生成任務,如摘要生成和問題生成。

 

下面來說說在文本生成上有着驚豔的表現的OpenAI 的GPT-2,其生成的文本在上下文連貫性和情感表達上都超過了人們對目前階段語言模型的預期。我們前面說了BERT是通過transformer的encoder模塊構建的,而GPT-2是使用transformer的Decoder構建的。需要指出的是,二者一個很關鍵的不同之處在於:GPT-2 就像傳統的語言模型一樣,一次只輸出一個token (訓練時是同時輸入多個token)。

OpenAI 的 GPT-2 模型是隻包含transfomer編碼器(decoder-only)的模塊,去除了第二個自注意力層。

GPT-2 使用的帶掩模的自注意力模塊,帶掩模的自注意力模塊不允許一個位置看到它右側單詞的信息。這種模型之所以效果好是因爲在每個新單詞產生後,該單詞就被添加在之前生成的單詞序列後面,這個序列會成爲模型下一步的新輸入。這種機制叫做自迴歸(auto-regression)。

對於GPT-2在對話生成上的應用,大家可以參考一下https://zhuanlan.zhihu.com/p/96755231

當然還有微軟的DialoGPT(論文:https://arxiv.org/abs/1911.00536,代碼:https://github.com/microsoft/DialoGPT)。DialoGPT 模型基於 GPT-2 架構。它從 GPT-2 繼承了帶有層歸一化的 12 到 24 層 transformer,採用Reddit 的對話語料(作者覺得從Reddit 數據中可以學習到的豐富信息)。

 

參考:

https://zhuanlan.zhihu.com/p/53796189

https://zhuanlan.zhihu.com/p/65062025

https://blog.csdn.net/qq_32241189/article/details/81591456

http://fancyerii.github.io/2019/02/14/chatbot/

https://www.cnblogs.com/robert-dlut/p/8638283.html

https://www.sohu.com/a/242214491_164987

https://www.cnblogs.com/hellojamest/p/11128799.html

https://zhuanlan.zhihu.com/p/85221503

https://zhuanlan.zhihu.com/p/77307258

https://blog.csdn.net/qq_38343151/article/details/102993202

https://zhuanlan.zhihu.com/p/47063917

https://zhuanlan.zhihu.com/p/47282410

https://www.cnblogs.com/jiangxinyang/p/11715678.html

https://zhuanlan.zhihu.com/p/86900556

https://blog.csdn.net/u012526436/article/details/101924049

https://zhuanlan.zhihu.com/p/65346812

https://www.zhihu.com/question/324019899/answer/709577373

https://kexue.fm/archives/6933

https://zhuanlan.zhihu.com/p/68327602

https://zhuanlan.zhihu.com/p/70663422

https://www.jiqizhixin.com/articles/2019-09-03-14

https://www.jiqizhixin.com/articles/2019-08-26-12

https://zhuanlan.zhihu.com/p/92842331

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章