編者按:Kushal Chauhan分享了他在Jatana.ai的NLP研究實習(xí)期間基于句嵌入進行無監(jiān)督文本總結(jié)的經(jīng)驗。
什么是文本總結(jié)?
文本總結(jié)是從一個或多個來源提取最重要的信息,生成一個針對某個或某群特定讀者或任務(wù)的簡化版本的過程。——Advances in Automatic Text Summarization, 1999, 第1頁
一般來說,人類相當(dāng)擅長這一任務(wù),因為我們具有理解文檔含義,使用自己的語言總結(jié)要點的能力。然而,由于當(dāng)今世界信息過載,缺乏人力和時間解讀數(shù)據(jù),自動文本總結(jié)技術(shù)十分關(guān)鍵。自動文本總結(jié)的價值在于:
減少閱讀時間。
簡化研究的篩選過程。
提高索引的有效性。
在問答系統(tǒng)中,個性化總結(jié)提供了個性化信息。
自動總結(jié)系統(tǒng)或半自動總結(jié)系統(tǒng)的應(yīng)用讓商業(yè)摘要服務(wù)提高了處理文檔的吞吐量。
文本總結(jié)方法的類型
根據(jù)不同的標(biāo)準(zhǔn),文本總結(jié)方法可以分為不同類型。
基于輸入類型
單文檔許多早期的總結(jié)系統(tǒng)只能處理單文檔。
多文檔支持任意數(shù)量的文檔作為輸入。
基于目的
通用模型對要總結(jié)的文本內(nèi)容的領(lǐng)域不作任何假定,并將所有輸入作為同構(gòu)文本處理。文本總結(jié)領(lǐng)域的大部分工作都屬于這類。
領(lǐng)域特定模型使用領(lǐng)域特定知識以形成更精確的總結(jié)。例如,總結(jié)特定領(lǐng)域的研究論文,生物醫(yī)學(xué)文檔,等等。
基于查詢總結(jié)僅僅包括回答關(guān)于輸入文本的自然語言提問的信息。
基于輸出類型
提取從輸入文本中選取最重要的句子,組成總結(jié)?,F(xiàn)在大多數(shù)總結(jié)方法本質(zhì)上都是提取式的。
摘要模型用自己的詞組和句子提供一份更連貫的總結(jié),類似人類所做的總結(jié)。這類方法無疑更有吸引力,但比提取式總結(jié)要困難得多。
我的任務(wù)
我的任務(wù)是在電子郵件上應(yīng)用文本總結(jié),郵件以英語、丹麥語、法語等多種語言撰寫。大多數(shù)公開的文本總結(jié)數(shù)據(jù)集面向的是長文檔和文章。由于長文檔和文章的結(jié)構(gòu)和短郵件有很大的不同,以監(jiān)督方法訓(xùn)練的模型可能在領(lǐng)域自適應(yīng)方面表現(xiàn)很差。因此,我選擇探索無監(jiān)督方法,期望得到總結(jié)的無偏預(yù)測。
現(xiàn)在,讓我們嘗試了解構(gòu)成模型流程的多個步驟。
文本總結(jié)模型流程
我所用的文本總結(jié)方法借鑒了Aishwarya Padmakumar和Akanksha Saran的論文Unsupervised Text Summarization Using Sentence Embeddings。這一方法可以分解為以下步驟:
第一步:清洗郵件
讓我們先來看下典型的郵件看起來是什么樣的:
英文郵件樣本:
HiJane,
Thank you for keeping me updated on this issue. I'm happy to hear that the issue got resolved after all and you can now use the app in its full functionality again.
Also many thanks for your suggestions. We hope to improve this feature in the future.
In case you experience any further problems with the app, please don't hesitate to contact me again.
Best regards,
JohnDoe
CustomerSupport
1600AmphitheatreParkway
MountainView, CA
UnitedStates
挪威語郵件樣本:
Hei
Grunnet manglende dekning p? deres kort for m?nedlig trekk, blir dere n? overf?rt til ?rlig fakturering.
I morgen vil dere motta faktura for hosting og drift av nettbutikk for perioden 05.03.2018-05.03.2019.
Ta gjerne kontakt om dere har sp?rsm?l.
Med vennlig hilsen
JohnDoe - SomeCompany.no
04756 | johndoe@somecompany.no
Husk ? sjekk v?rt hjelpesenter, kanskje du finner svar der: https://support.somecompany.no/
意大利語郵件樣本:
CiaoJohn,
Grazie mille per averci contattato! Apprezziamo molto che abbiate trovato il tempo per inviarci i vostri commenti e siamo lieti che vi piaccia l'App.
Sentitevi liberi di parlare di con i vostri amici o di sostenerci lasciando una recensione nell'AppStore!
Cordiali saluti,
JaneDoe
CustomerSupport
OneInfiniteLoop
Cupertino
CA 95014
如你所見,郵件開頭的稱呼語和末尾的簽名對總結(jié)生成任務(wù)毫無貢獻。所以,有必要從郵件中移除這些應(yīng)該不會影響總結(jié)的行。這簡化了輸入,使模型表現(xiàn)可以更佳。
由于不同郵件和不同語言的稱呼語和簽名不一樣,移除它們需要使用正則表達式匹配。如果只處理英文郵件,那么我們可以直接使用Mailgun的talon庫:
from talon.signature.bruteforce import extract_signature
cleaned_email, _ = extract_signature(email)
不過我需要處理多種語言的郵件,所以我修改了extract_signature函數(shù),以支持英語之外的其他語言。我還順便移除了換行符。
上面三個郵件樣本經(jīng)過清洗后,是這樣的:
清洗過的英語郵件:
Thank you for keeping me updated on this issue. I'm happy to hear that the issue got resolved after all and you can now use the app in its full functionality again. Also many thanks for your suggestions. We hope to improve this feature in the future. In case you experience any further problems with the app, please don't hesitate to contact me again.
清洗過的挪威語郵件:
Grunnet manglende dekning p? deres kort for m?nedlig trekk, blir dere n? overf?rt til ?rlig fakturering. I morgen vil dere motta faktura for hosting og drift av nettbutikk for perioden 05.03.2018-05.03.2019.Ta gjerne kontakt om dere har sp?rsm?l.
清洗過的意大利語郵件:
Grazie mille per averci contattato! Apprezziamo molto che abbiate trovato il tempo per inviarci i vostri commenti e siamo lieti che vi piaccia l'App. Sentitevi liberi di parlare di con i vostri amici o di sostenerci lasciando una recensione nell'AppStore.
完成這一預(yù)處理步驟之后,我們可以進一步探索總結(jié)流程剩下的部分。
第二步:檢測語言
由于要總結(jié)的郵件可能使用任何語言,我們首先需要做的就是判定郵件的語言。有很多使用機器學(xué)習(xí)技術(shù)識別文本語言的Python庫,例如polyglot、langdetect、textblob。我使用了langdetect,它支持55種不同的語言。只需一個簡單的函數(shù)調(diào)用就可以檢測語言:
from langdetect import detect
lang = detect(cleaned_email) # 如果是英語郵件,那么lang = 'en'
第三步:句子分割
識別了每封郵件的語言后,我們就可以根據(jù)不同語言的規(guī)則(標(biāo)點符號)將郵件分割成句子。我們將使用NLTK:
from nltk.tokenize import sent_tokenize
sentences = sent_tokenize(email, language = lang)
第四步:Skip-Thought編碼器
我們需要找到一種方式,為郵件中的每句話生成固定長度的向量表示。該表示應(yīng)當(dāng)編碼句子的內(nèi)在語義和含義。知名的Skip-Gram Word2Vec詞嵌入生成方法可以為模型詞匯表收錄的詞提供詞嵌入(FastText這樣更酷炫的方法能夠基于子詞信息為模型詞匯表外的單詞生成嵌入)。
有了詞嵌入,只需對每句話包含的詞嵌入進行加權(quán)求和,即可得到句嵌入。之所以要加權(quán),是因為“and”、“to”、“the”等一些頻繁出現(xiàn)的單詞完全沒有或幾乎沒有提供任何關(guān)于句子的信息。而只在個別句子中出現(xiàn)的一些罕見詞,代表性要高很多。因此,權(quán)重的取值和詞頻逆相關(guān)。具體細節(jié)可以參考Sanjeev Arora等的論文(ICLR17/SyK00v5xx)
然而,這樣的無監(jiān)督方法沒有考慮句子中單詞的順序。這可能對模型的表現(xiàn)造成不利影響。所以我選擇在維基百科數(shù)據(jù)上訓(xùn)練一個Skip-Thought句編碼器。Skip-Thoughts模型包括兩部分:
編碼器網(wǎng)絡(luò):編碼器通常是一個GRU循環(huán)神經(jīng)網(wǎng)絡(luò),為輸入中的每個句子Si生成固定長度的向量表示hi。將GRU單元的最終隱藏狀態(tài)(即,在它見過整個句子之后得到的隱藏狀態(tài))傳給多個密集層,得到編碼表示hi。
解碼器網(wǎng)絡(luò):解碼器網(wǎng)絡(luò)接受向量表示hi作為輸入,并嘗試生成兩個句子——Si-1和Si+1,分別為可能出現(xiàn)在輸入句子之前和之后的句子。生成前句和后句的是獨立的解碼器,均為GRU循環(huán)神經(jīng)網(wǎng)絡(luò)。向量表示hi作為解碼器網(wǎng)絡(luò)GRU的初始隱藏狀態(tài)。
給定包含句子序列的數(shù)據(jù)集,解碼器的目標(biāo)是逐詞生成前句和后句。訓(xùn)練編碼器-解碼器網(wǎng)絡(luò)以最小化句子的重建損失,在此過程中,編碼器學(xué)習(xí)生成能為解碼器編碼足夠信息的向量表示,以便解碼器生成相鄰句子。這些學(xué)習(xí)到的表示滿足語義上相似的句子在向量空間中的嵌入互相接近,因此適合用于聚類。在我們的例子中,郵件中的句子作為編碼器網(wǎng)絡(luò)的輸入,以得到所需向量表示。獲得句嵌入的Skip-Thoughts方法的細節(jié)請參考原論文(arXiv:1506.06726)。
給定一個句子(灰點),模型嘗試預(yù)測前句(紅點)和后句(綠點)
至于實現(xiàn),我使用了論文作者開源的代碼。該實現(xiàn)基于Theano,可以通過GitHub倉庫ryankiros/skip-thoughts獲取。這個實現(xiàn)很容易使用,只需幾行代碼就可以獲取一封郵件的句嵌入:
import skipthoughts
# 你首先需要下載預(yù)訓(xùn)練模型
model = skipthoughts.load_model()
encoder = skipthoughts.Encoder(model)
encoded = encoder.encode(sentences)
第五步:聚類
為郵件中的每個句子生成句嵌入后,我們將這些高維向量空間中的嵌入聚類為數(shù)量預(yù)定義的一組聚類。聚類的數(shù)目將等于總結(jié)所需的句數(shù)。我為總結(jié)選擇的句數(shù)等于郵件總句數(shù)的平方根。另一種可能的方案是等于總句數(shù)的某個百分比,比如30%. 下面是聚類的代碼:
import numpy as np
from sklearn.cluster importKMeans
n_clusters = np.ceil(len(encoded)**0.5)
kmeans = KMeans(n_clusters=n_clusters)
kmeans = kmeans.fit(encoded)
第六步:總結(jié)
句嵌入的每個聚類可以看成一組語義上相似的句子,其含義可以通過其中的一個候選句子表達。我們選取向量表示最接近聚類中心的句子作為候選句子。每個聚類選出的候選句子經(jīng)過排序構(gòu)成郵件總結(jié)??偨Y(jié)中候選句子的順序取決于其所在聚類中的句子在原郵件中的位置。例如,如果某個候選句子所在聚類中的大多數(shù)句子出現(xiàn)在郵件開始,那么該句就被選為總結(jié)的第一句。下面幾行代碼實現(xiàn)了這一算法:
from sklearn.metrics import pairwise_distances_argmin_min
avg = []
for j in range(n_clusters):
idx = np.where(kmeans.labels_ == j)[0]
avg.append(np.mean(idx))
closest, _ = pairwise_distances_argmin_min(kmeans.cluster_centers_, encoded)
ordering = sorted(range(n_clusters), key=lambda k: avg[k])
summary = ' '.join([email[closest[idx]] for idx in ordering])
由于這一方法本質(zhì)上是從文本中提取一些候選句子以形成總結(jié),因此屬于提取式總結(jié)。
之前我們列出的郵件樣本,最終提取出的總結(jié)為:
英語郵件:
I'm happy to hear that the issue got resolved after all and you can now use the app in its full functionality again. Also many thanks for your suggestions. In case you experience any further problems with the app, please don't hesitate to contact me again.
挪威語郵件:
Grunnet manglende dekning p? deres kort for m?nedlig trekk, blir dere n? overf?rt til ?rlig fakturering. I morgen vil dere motta faktura for hosting og drift av nettbutikk for perioden 05.03.2018-05.03.2019.Ta gjerne kontakt om dere har sp?rsm?l.
意大利語郵件:
Apprezziamo molto che abbiate trovato il tempo per inviarci i vostri commenti e siamo lieti che vi piaccia l'App. Sentitevi liberi di parlare di con i vostri amici o di sostenerci lasciando una recensione nell'AppStore.
訓(xùn)練
前面提到的Skip-Thought的代碼倉庫已經(jīng)提供了針對英語的預(yù)訓(xùn)練模型。其他一些語言需要自行訓(xùn)練。我們使用了維基百科作為語料,從維基媒體基金會網(wǎng)站下載了.bz2壓縮文件,解壓縮得到.xml文件。接著解析.xml文件,去除html標(biāo)記,只剩下純文本。有很多解析維基百科文件的工具,沒有一個是完美的。取決于使用的解析方法,解析可能要花大量時間。我使用的是GitHub上的attardi/wikiextractor,不算最好的,不過是免費的,而且可以在合理的時間內(nèi)完成解析任務(wù)。我還對得到的純文本進行了一些簡單的預(yù)處理,比如移除換行符。這樣我就得到了大量的訓(xùn)練數(shù)據(jù),可以讓Skip-Thoughts模型慢慢訓(xùn)練了。
Skip-Thoughts的訓(xùn)練過程還要用到預(yù)訓(xùn)練的詞向量,我使用了Facebook的FastText預(yù)訓(xùn)練詞嵌入。由于這些詞嵌入也是在維基百科上訓(xùn)練的,所以極少遇到詞匯表外的單詞。
實現(xiàn)細節(jié)
我把實現(xiàn)的模型的一個簡化版本放到了GitHub上(jatana-research/email-summarization)。這一簡化版只支持英語郵件,但是實現(xiàn)了上面提及的所有步驟,效果也很不錯。
結(jié)果
你也許已經(jīng)注意到了,模型在只包含三兩句話的郵件上表現(xiàn)要差不少。例如,只包含3句話的郵件的總結(jié)會有2句話,而原本的3句話可能各自表達完全不同的事情,漏掉任何一句都是不可接受的。這正是為什么通常情況下在短輸入上不使用提取式方法進行總結(jié)的原因。序列到序列的監(jiān)督模型更適合這一任務(wù)。不過在我們的例子中,郵件一般沒有這么短,所以提取式方法的效果驚人得好。
使用Skip-Thoughts向量的一個劣勢是模型需要花很多時間訓(xùn)練。盡管2-3天的訓(xùn)練之后就可以得到可接受的結(jié)果,但為了得到較好的結(jié)果,我還是訓(xùn)練了大約一周。由于損失被句長歸一化了,在迭代過程中損失波動得很厲害。
我們可以看下數(shù)據(jù)集中最相似的句對,看看Skip-Thoughts模型表現(xiàn)得有多好:
I can assure you that our developers are already aware of the issue and are trying to solve it as soon as possible.
AND
I have already forwarded your problem report to our developers and they will now investigate this issue with the login page in further detail in order to detect the source of this problem.
--------------------------------------------------------------------I am very sorry to hear that.
AND
We sincerely apologize for the inconvenience caused.
--------------------------------------------------------------------Therefore, I would kindly ask you to tell me which operating system you are using the app on.
AND
Can you specify which device you are usingas well as the Androidor iOS version it currently has installed?
從上面的句子來看,這個模型的效果驚人地好,可以找出相似的句子,即使這些句子的長度很不一樣,使用的詞匯也大不相同。
可能的改進
本文介紹的方法效果相當(dāng)不錯,但還不夠完美。通過增加模型復(fù)雜度,有很多可以改進的地方:
Quick-Thought向量,Skip-Thoughts的改進版,可能降低訓(xùn)練時間,提升表現(xiàn)。
Skip-Thoughts編碼表示的維度為4800。由于維度詛咒,這樣的高維向量不是很適合聚類。我們也許可以使用自動編碼器或LSTM自動編碼器在聚類前降低這些向量的維度。
我們不一定要使用提取式方法。我們可以訓(xùn)練一個解碼器網(wǎng)絡(luò),讓它轉(zhuǎn)換聚類中心的編碼表示為自然語言句子,從而實現(xiàn)摘要式總結(jié)。Skip-Thoughts編碼器生成的數(shù)據(jù)可以用來訓(xùn)練這一解碼器。然而,如果我們希望解碼器生成看上去合理的、語法正確的句子,那么需要非常小心地調(diào)整超參數(shù)和設(shè)計架構(gòu)。
機器配置
所有這些試驗都是在一個n1-highmem-8的Google云主機上進行的:十核Intel Xeon CPU,Nvidia Tesla K80 GPU,52GB 內(nèi)存。
特別感謝我的指導(dǎo)者Rahul Kumar全程給出的意見和建議,沒有他我不可能完成這一切。我也很感激Jatana.ai給我提供機會和資源完成這項工作。
-
編碼器
+關(guān)注
關(guān)注
44文章
3555瀏覽量
133814 -
數(shù)據(jù)集
+關(guān)注
關(guān)注
4文章
1199瀏覽量
24594
原文標(biāo)題:基于句嵌入的無監(jiān)督文本總結(jié)
文章出處:【微信號:jqr_AI,微信公眾號:論智】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論