日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

玩转Keras之Seq2Seq自动生成标题 | 附开源代码

發(fā)布時(shí)間:2024/10/8 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 玩转Keras之Seq2Seq自动生成标题 | 附开源代码 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.


作者丨蘇劍林

單位丨廣州火焰信息科技有限公司

研究方向丨NLP,神經(jīng)網(wǎng)絡(luò)

個(gè)人主頁丨kexue.fm



話說自稱搞了這么久的 NLP,我都還沒有真正跑過 NLP 與深度學(xué)習(xí)結(jié)合的經(jīng)典之作——Seq2Seq。這兩天興致來了,決定學(xué)習(xí)并實(shí)踐一番 Seq2Seq,當(dāng)然最后少不了 Keras 實(shí)現(xiàn)了。


Seq2Seq?可以做的事情非常多,我這挑選的是比較簡單的根據(jù)文章內(nèi)容生成標(biāo)題(中文),也可以理解為自動(dòng)摘要的一種。選擇這個(gè)任務(wù)主要是因?yàn)椤拔恼?標(biāo)題”這樣的語料對比較好找,能快速實(shí)驗(yàn)一下。


Seq2Seq簡介


所謂 Seq2Seq,就是指一般的序列到序列的轉(zhuǎn)換任務(wù),比如機(jī)器翻譯、自動(dòng)文摘等等,這種任務(wù)的特點(diǎn)是輸入序列和輸出序列是不對齊的,如果對齊的話,那么我們稱之為序列標(biāo)注,這就比 Seq2Seq 簡單很多了。所以盡管序列標(biāo)注任務(wù)也可以理解為序列到序列的轉(zhuǎn)換,但我們在談到 Seq2Seq 時(shí),一般不包含序列標(biāo)注。?


要自己實(shí)現(xiàn) Seq2Seq,關(guān)鍵是搞懂 Seq2Seq 的原理和架構(gòu),一旦弄清楚了,其實(shí)不管哪個(gè)框架實(shí)現(xiàn)起來都不復(fù)雜。早期有一個(gè)第三方實(shí)現(xiàn)的 Keras 的 Seq2Seq 庫 [1],現(xiàn)在作者也已經(jīng)放棄更新了,也許就是覺得這么簡單的事情沒必要再建一個(gè)庫了吧??梢詤⒖嫉馁Y料還有去年 Keras 官方博客中寫的 A ten-minute introduction to sequence-to-sequence learning in Keras [2]。?


基本結(jié)構(gòu)


假如原句子為 X=(a,b,c,d,e,f),目標(biāo)輸出為 Y=(P,Q,R,S,T),那么一個(gè)基本的 Seq2Seq?就如下圖所示。


?基本的Seq2Seq架構(gòu)


盡管整個(gè)圖的線條比較多,可能有點(diǎn)眼花,但其實(shí)結(jié)構(gòu)很簡單。左邊是對輸入的 encoder,它負(fù)責(zé)把輸入(可能是變長的)編碼為一個(gè)固定大小的向量,這個(gè)可選擇的模型就很多了,用 GRU、LSTM 等 RNN 結(jié)構(gòu)或者 CNN+Pooling、Google 的純 Attention 等都可以,這個(gè)固定大小的向量,理論上就包含了輸入句子的全部信息。


而 decoder 負(fù)責(zé)將剛才我們編碼出來的向量解碼為我們期望的輸出。與 encoder 不同,我們在圖上強(qiáng)調(diào) decoder 是“單向遞歸”的,因?yàn)榻獯a過程是遞歸進(jìn)行的,具體流程為:


1. 所有輸出端,都以一個(gè)通用的<start>標(biāo)記開頭,以<end>標(biāo)記結(jié)尾,這兩個(gè)標(biāo)記也視為一個(gè)詞/字;


2. 將<start>輸入 decoder,然后得到隱藏層向量,將這個(gè)向量與 encoder 的輸出混合,然后送入一個(gè)分類器,分類器的結(jié)果應(yīng)當(dāng)輸出 P;


3. 將 P 輸入 decoder,得到新的隱藏層向量,再次與 encoder 的輸出混合,送入分類器,分類器應(yīng)輸出 Q;


4. 依此遞歸,直到分類器的結(jié)果輸出<end>。


這就是一個(gè)基本的 Seq2Seq 模型的解碼過程,在解碼的過程中,將每步的解碼結(jié)果送入到下一步中去,直到輸出<end>位置。


訓(xùn)練過程


事實(shí)上,上圖也表明了一般的 Seq2Seq 的訓(xùn)練過程。由于訓(xùn)練的時(shí)候我們有標(biāo)注數(shù)據(jù)對,因此我們能提前預(yù)知 decoder 每一步的輸入和輸出,因此整個(gè)結(jié)果實(shí)際上是“輸入 X 和 Y,預(yù)測 Y[1:],即將目標(biāo) Y 錯(cuò)開一位來訓(xùn)練。?


而 decoder 同樣可以用 GRU、LSTM 或 CNN 等結(jié)構(gòu),但注意再次強(qiáng)調(diào)這種“預(yù)知未來”的特性僅僅在訓(xùn)練中才有可能,在預(yù)測階段是不存在的,因此 decoder 在執(zhí)行每一步時(shí),不能提前使用后面步的輸入。


所以,如果用 RNN 結(jié)構(gòu),一般都只使用單向 RNN;如果使用 CNN 或者純 Attention,那么需要把后面的部分給 mask 掉(對于卷積來說,就是在卷積核上乘上一個(gè) 0/1 矩陣,使得卷積只能讀取當(dāng)前位置及其“左邊”的輸入,對于 Attention 來說也類似,不過是對 query 的序列進(jìn)行 mask 處理)。?


敏感的讀者可能會(huì)察覺到,這種訓(xùn)練方案是“局部”的,事實(shí)上不夠端到端。比如當(dāng)我們預(yù)測 R 時(shí)是假設(shè) Q 已知的,即 Q 在前一步被成功預(yù)測,但這是不能直接得到保證的。一般前面某一步的預(yù)測出錯(cuò),那么可能導(dǎo)致連鎖反應(yīng),后面各步的訓(xùn)練和預(yù)測都沒有意義了。?


有學(xué)者考慮過這個(gè)問題,比如文章 Sequence-to-Sequence Learning as Beam-Search Optimization?[3] 把整個(gè)解碼搜索過程也加入到訓(xùn)練過程,而且還是純粹梯度下降的(不用強(qiáng)化學(xué)習(xí)),是非常值得借鑒的一種做法。不過局部訓(xùn)練的計(jì)算成本比較低,一般情況下我們都只是使用局部訓(xùn)練來訓(xùn)練 Seq2Seq。


Beam Search?


前面已經(jīng)多次提到了解碼過程,但還不完整。事實(shí)上,對于 Seq2Seq 來說,我們是在建模:



顯然在解碼時(shí),我們希望能找到最大概率的 Y,那要怎么做呢??


如果在第一步 p(Y1|X) 時(shí),直接選擇最大概率的那個(gè)(我們期望是目標(biāo) P),然后代入第二步 p(Y2|X,Y1),再次選擇最大概率的 Y2,依此類推,每一步都選擇當(dāng)前最大概率的輸出,那么就稱為貪心搜索,是一種最低成本的解碼方案。但是要注意,這種方案得到的結(jié)果未必是最優(yōu)的,假如第一步我們選擇了概率不是最大的 Y1,代入第二步時(shí)也許會(huì)得到非常大的條件概率 p(Y2|X,Y1),從而兩者的乘積會(huì)超過逐位取最大的算法。?


然而,如果真的要枚舉所有路徑取最優(yōu),那計(jì)算量是大到難以接受的(這不是一個(gè)馬爾可夫過程,動(dòng)態(tài)規(guī)劃也用不了)。因此,Seq2Seq 使用了一種折中的方法:Beam Search。?


這種算法類似動(dòng)態(tài)規(guī)劃,但即使在能用動(dòng)態(tài)規(guī)劃的問題下,它還比動(dòng)態(tài)規(guī)劃要簡單,它的思想是:在每步計(jì)算時(shí),只保留當(dāng)前最優(yōu)的 topk 個(gè)候選結(jié)果。比如取 topk=3,那么第一步時(shí),我們只保留使得 p(Y1|X) 最大的前 3 個(gè) Y1,然后分別代入 p(Y2|X,Y1),然后各取前三個(gè) Y2,這樣一來我們就有個(gè)組合了,這時(shí)我們計(jì)算每一種組合的總概率,然后還是只保留前三個(gè),依次遞歸,直到出現(xiàn)了第一個(gè)<end>。顯然,它本質(zhì)上還屬于貪心搜索的范疇,只不過貪心的過程中保留了更多的可能性,普通的貪心搜索相當(dāng)于 topk=1。


Seq2Seq提升


前面所示的 Seq2Seq 模型是標(biāo)準(zhǔn)的,但它把整個(gè)輸入編碼為一個(gè)固定大小的向量,然后用這個(gè)向量解碼,這意味著這個(gè)向量理論上能包含原來輸入的所有信息,會(huì)對 encoder 和 decoder 有更高的要求,尤其在機(jī)器翻譯等信息不變的任務(wù)上。因?yàn)檫@種模型相當(dāng)于讓我們“看了一遍中文后就直接寫出對應(yīng)的英文翻譯”那樣,要求有強(qiáng)大的記憶能力和解碼能力,事實(shí)上普通人完全不必這樣,我們還會(huì)反復(fù)翻看對比原文,這就導(dǎo)致了下面的兩個(gè)技巧。?


Attention


Attention 目前基本上已經(jīng)是 Seq2Seq 模型的“標(biāo)配”模塊了,它的思想就是:每一步解碼時(shí),不僅僅要結(jié)合 encoder 編碼出來的固定大小的向量(通讀全文),還要往回查閱原來的每一個(gè)字詞(精讀局部),兩者配合來決定當(dāng)前步的輸出。?


?帶Attention的Seq2Seq


至于 Attention 的具體做法,筆者之前已經(jīng)撰文介紹過了,請參考一文讀懂「Attention is All You Need」| 附代碼實(shí)現(xiàn)。Attention 一般分為乘性和加性兩種,筆者介紹的是 Google 系統(tǒng)介紹的乘性的 Attention,加性的 Attention 讀者可以自行查閱,只要抓住 query、key、value 三個(gè)要素,Attention 就都不難理解了。


先驗(yàn)知識(shí)


回到用?Seq2Seq?生成文章標(biāo)題這個(gè)任務(wù)上,模型可以做些簡化,并且可以引入一些先驗(yàn)知識(shí)。比如,由于輸入語言和輸出語言都是中文,因此 encoder 和 decoder 的 Embedding 層可以共享參數(shù)(也就是用同一套詞向量)。這使得模型的參數(shù)量大幅度減少了。?


此外,還有一個(gè)很有用的先驗(yàn)知識(shí):標(biāo)題中的大部分字詞都在文章中出現(xiàn)過(注:僅僅是出現(xiàn)過,并不一定是連續(xù)出現(xiàn),更不能說標(biāo)題包含在文章中,不然就成為一個(gè)普通的序列標(biāo)注問題了)。這樣一來,我們可以用文章中的詞集作為一個(gè)先驗(yàn)分布,加到解碼過程的分類模型中,使得模型在解碼輸出時(shí)更傾向選用文章中已有的字詞。


具體來說,在每一步預(yù)測時(shí),我們得到總向量 x(如前面所述,它應(yīng)該是 decoder 當(dāng)前的隱層向量、encoder 的編碼向量、當(dāng)前 decoder 與 encoder 的 Attention 編碼三者的拼接),然后接入到全連接層,最終得到一個(gè)大小為 |V| 的向量 y=(y1,y2,…,y|V|),其中 |V| 是詞表的詞數(shù)。y 經(jīng)過 softmax 后,得到原本的概率:



這就是原始的分類方案。引入先驗(yàn)分布的方案是,對于每篇文章,我們得到一個(gè)大小為 |V| 的 0/1 向量 χ=(χ1,χ2,…,χ|V|),其中 χi=1 意味著該詞在文章中出現(xiàn)過,否則 χi=0。將這樣的一個(gè) 0/1 向量經(jīng)過一個(gè)縮放平移層得到:



其中 s,t 為訓(xùn)練參數(shù),然后將這個(gè)向量與原來的 y 取平均后才做 softmax:



經(jīng)實(shí)驗(yàn),這個(gè)先驗(yàn)分布的引入,有助于加快收斂,生成更穩(wěn)定的、質(zhì)量更優(yōu)的標(biāo)題。


Keras參考


又到了快樂的開源時(shí)光~?


基本實(shí)現(xiàn)


基于上面的描述,我收集了 80 多萬篇新聞的語料,來試圖訓(xùn)練一個(gè)自動(dòng)標(biāo)題的模型。簡單起見,我選擇了以字為基本單位,并且引入了 4 個(gè)額外標(biāo)記,分別代表 mask、unk、start、end。而 encoder 我使用了雙層雙向 LSTM,decoder 使用了雙層單向 LSTM。具體細(xì)節(jié)可以參考源碼:?


https://github.com/bojone/seq2seq/blob/master/seq2seq.py


我以 6.4 萬文章為一個(gè) epoch,訓(xùn)練了 50 個(gè) epoch 之后,基本就生成了看上去還行的標(biāo)題:


文章內(nèi)容:8 月 28 日,網(wǎng)絡(luò)爆料稱,華住集團(tuán)旗下連鎖酒店用戶數(shù)據(jù)疑似發(fā)生泄露。從賣家發(fā)布的內(nèi)容看,數(shù)據(jù)包含華住旗下漢庭、禧玥、桔子、宜必思等 10 余個(gè)品牌酒店的住客信息。泄露的信息包括華住官網(wǎng)注冊資料、酒店入住登記的身份 信息及酒店開房記錄,住客姓名、手機(jī)號(hào)、郵箱、身份證號(hào)、登錄賬號(hào)密碼等。賣家對這個(gè)約 5 億條數(shù)據(jù)打包出售。第三方安全平臺(tái)威脅獵人對信息出售者提供的三萬條數(shù)據(jù)進(jìn)行驗(yàn)證,認(rèn)為數(shù)據(jù)真實(shí)性非常高。當(dāng)天下午,華住集團(tuán)發(fā) 聲明稱,已在內(nèi)部迅速開展核查,并第一時(shí)間報(bào)警。當(dāng)晚,上海警方消息稱,接到華住集團(tuán)報(bào)案,警方已經(jīng)介入調(diào)查。?


生成標(biāo)題:《酒店用戶數(shù)據(jù)疑似發(fā)生泄露》

?

文章內(nèi)容:新浪體育訊 北京時(shí)間 10 月 16 日,NBA 中國賽廣州站如約開打,火箭再次勝出,以 95-85 擊敗籃網(wǎng)。姚明漸入佳境,打了 18 分 39 秒,8 投 5 中,拿下 10 分 5 個(gè)籃板,他還蓋帽 1 次。火箭以兩戰(zhàn)皆勝的戰(zhàn)績圓滿結(jié)束中國行。?


生成標(biāo)題:《直擊:火箭兩戰(zhàn)皆勝火箭再勝 廣州站姚明10分5板》


當(dāng)然這只是兩個(gè)比較好的例子,還有很多不好的例子,直接用到工程上肯定是不夠的,還需要很多“黑科技”優(yōu)化才行。


mask?


在 Seq2Seq 中,做好 mask 是非常重要的,所謂 mask,就是要遮掩掉不應(yīng)該讀取到的信息、或者是無用的信息,一般是用 0/1 向量來乘掉它。Keras 自帶的 mask 機(jī)制十分不友好,有些層不支持 mask,而普通的 LSTM 開啟了 mask 后速度幾乎下降了一半。所以現(xiàn)在我都是直接以 0 作為 mask 的標(biāo)記,然后自己寫個(gè) Lambda 層進(jìn)行轉(zhuǎn)化的,這樣速度基本無損,而且支持嵌入到任意層,具體可以參考上面的代碼。?


要注意我們以往一般是不區(qū)分 mask 和 unk(未登錄詞)的,但如果采用我這種方案,還是把未登錄詞區(qū)分一下比較好,因?yàn)槲吹卿浽~盡管我們不清楚具體含義,它還是一個(gè)真正的詞,至少有占位作用,而 mask 是我們希望完全抹掉的信息。?


解碼端


代碼中已經(jīng)實(shí)現(xiàn)了 beam search 解碼,讀者可以自行測試不同的 topk 對解碼結(jié)果的影響。?


這里要說的是,參考代碼中對解碼的實(shí)現(xiàn)是比較偷懶的,會(huì)使得解碼速度大降。理論上來說,我們每次得到當(dāng)前時(shí)刻的輸出后,我們只需要傳入到 LSTM 的下一步迭代中去,就可以得到下一時(shí)刻的輸出,但這需要重寫解碼端的 LSTM(也就是要區(qū)分訓(xùn)練階段和測試階段,兩者共享權(quán)重),相對復(fù)雜,而且對初學(xué)者并不友好。所以我使用了一個(gè)非常粗暴的方案:每一步預(yù)測都重跑一次整個(gè)模型,這樣一來代碼量最少,但是越到后面越慢,原來是

總結(jié)

以上是生活随笔為你收集整理的玩转Keras之Seq2Seq自动生成标题 | 附开源代码的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。