醫(yī)院網(wǎng)站建設(shè)目的萬網(wǎng)域名查詢接口
基于句子嵌入的文本摘要算法實(shí)現(xiàn)
人們?cè)诶斫饬宋谋镜暮x后,很容易用自己的話對(duì)文本進(jìn)行總結(jié)。但在數(shù)據(jù)過多、缺乏人力和時(shí)間的情況下,自動(dòng)文本摘要?jiǎng)t顯得至關(guān)重要。一般使用自動(dòng)文本摘要的原因包括:
- 減少閱讀時(shí)間
- 根據(jù)摘要,選擇自己想研究的文檔
- 提高索引的有效性
- 自動(dòng)摘要算法比人工摘要算法的偏差更小
- 問答系統(tǒng)中的個(gè)性化摘要
- 能有效增加處理的文本數(shù)量
1.方法分類
- 基于輸入
- 單個(gè)文檔
- 多文檔
- 基于目的
- 通用型。模型不對(duì)文本的所屬領(lǐng)域或內(nèi)容做出任何假設(shè),所有輸入被視為同質(zhì)。目前,大部分研究的工作都是圍繞這種方法展開的。
- 特定領(lǐng)域。模型使用特定領(lǐng)域的知識(shí)來形成更準(zhǔn)確的摘要。例如,總結(jié)特定領(lǐng)域的研究論文、生物醫(yī)學(xué)文獻(xiàn)等。
- 基于查詢。對(duì)相關(guān)問題的回答進(jìn)行摘要。
- 基于輸出
- 抽取。從輸入文本中選擇重要的句子形成摘要。目前,大多數(shù)摘要方法本質(zhì)上都是抽取式的。
- 生成。模型生成短語和句子來提供更連貫的摘要。
2.Pipeline
本次任務(wù)是 對(duì)英語、丹麥語、法語等語言的電子郵件進(jìn)行文本摘要。大多數(shù)公開可用的文本摘要數(shù)據(jù)集都是針對(duì)長文檔的。由于長文檔的結(jié)構(gòu)與電子郵件的結(jié)構(gòu)明顯不同,因此使用監(jiān)督方法訓(xùn)練的模型可能會(huì)出現(xiàn)領(lǐng)域適應(yīng)性差的問題。因此,我們選擇無監(jiān)督方法來提取摘要。
本文使用的方法主要來自論文《Unsupervised Text Summarization Using Sentence Embeddings
》。
2.1 Email Cleaning
英文郵件示例:
Hi Jane,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,John Doe
Customer Support1600 Amphitheatre Parkway
Mountain View, CA
United States
挪威語郵件示例:
HeiGrunnet 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
John Doe - SomeCompany.no
04756 | johndoe@somecompany.noHusk ? sjekk v?rt hjelpesenter, kanskje du finner svar der: https://support.somecompany.no/
意大利語郵件示例:
Ciao John, 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'App Store!Cordiali saluti, Jane Doe
Customer SupportOne Infinite Loop
Cupertino
CA 95014
電子郵件開頭和結(jié)尾的稱呼和簽名對(duì)摘要生成任務(wù)沒有任何價(jià)值。為了使模型可以執(zhí)行更簡單的輸入,可以從電子郵件中刪除這些無意義的信息。
稱呼和簽名因電子郵件以及語言而異,因此需要通過正則表達(dá)式進(jìn)行刪除。代碼的簡短版本如下所示(參考了 Mailgun Talon 在 GitHub 中的代碼):
# clean() is a modified version of extract_signature() found in bruteforce.py in the GitHub repository linked above
cleaned_email, _ = clean(email)lines = cleaned_email.split('\n')
lines = [line for line in lines if line != '']
cleaned_email = ' '.join(lines)
還可以通過 talon.signature.bruteforce
實(shí)現(xiàn):
from talon.signature.bruteforce import extract_signature
cleaned_email, _ = extract_signature(email)
清洗后的文本如下所示。
英文電子郵件:
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’App Store.
2.2 Language Detection
由于輸入的電子郵件可以是任何語言,因此需要確定電子郵件使用的是哪種語言。許多 Python 庫都提供的語言檢測(cè)功能,例如 polyglot
、langdetect
和 textblob
。此處使用 langdetect
,它支持 555555 種不同語言的檢測(cè)。
from langdetect import detect
lang = detect(cleaned_email) # lang = 'en' for an English email
2.3 Sentence Tokenization
不同語言的文本有不同的分割規(guī)則,在識(shí)別了每封電子郵件使用的語言后,我們可以利用 NLTK 將不同語言的文本分割成句子。
from nltk.tokenize import sent_tokenize
sentences = sent_tokenize(email, language = lang)
2.4 Skip-Thought Encoder
接下來需要為電子郵件中的每個(gè)句子生成固定長度的向量表示。例如 Word2Vec
方法可以為模型詞匯表中的每個(gè)詞提供詞嵌入(一些更高級(jí)的方法還可以使用子詞信息為不在模型詞匯表中的詞生成嵌入)。下圖是 Word2Vec
模型的 Skip-Gram
訓(xùn)練模式。
對(duì)于句子嵌入,一種簡單的方法是 對(duì)句子所包含的單詞的詞向量進(jìn)行加權(quán)和。采用加權(quán)和是因?yàn)轭l繁出現(xiàn)的詞,如 and
、to
和 the
等單詞所提供的關(guān)于句子的信息幾乎非常少甚至沒有。一些詞雖然出現(xiàn)的次數(shù)較少,但它們是少數(shù)句子所特有的,具有更強(qiáng)的代表性。因此,我們假設(shè)權(quán)重與單詞出現(xiàn)的頻率成反比。
然而無監(jiān)督方法并沒有考慮句子中單詞的順序,這可能會(huì)影響模型精度。此處,我們選擇使用維基百科轉(zhuǎn)儲(chǔ)(Wikipedia dumps
)作為訓(xùn)練數(shù)據(jù),以監(jiān)督的方式訓(xùn)練一個(gè) Skip-Thought
句子編碼器。 該模型主要由兩部分組成:
- 編碼器網(wǎng)絡(luò)(
Encoder Network
):編碼器通常是GRU-RNN
,它為輸入中的每個(gè)句子 S(i)S(i)S(i) 生成固定長度的向量表示 h(i)h(i)h(i)。h(i)h(i)h(i) 是通過將 GRU 單元的最終隱藏狀態(tài)傳遞給多個(gè)密集層來獲得的。 - 解碼器網(wǎng)絡(luò)(
Decoder Network
):解碼器網(wǎng)絡(luò)將 h(i)h(i)h(i) 作為輸入,并嘗試生成兩個(gè)句子:S(i?1)S(i-1)S(i?1) 和 S(i+1)S(i+1)S(i+1),這兩個(gè)句子可能分別出現(xiàn)在輸入句子之前和之后。每個(gè)都實(shí)施單獨(dú)的解碼器來生成上一句和下一句,兩者都是GRU-RNN
。h(i)h(i)h(i) 作為解碼器網(wǎng)絡(luò)的 GRU 的初始隱藏狀態(tài)。
給定一個(gè)包含句子序列的數(shù)據(jù)集,解碼器應(yīng)該逐字生成上一句和下一句。編碼器-解碼器(encoder-decoder
)網(wǎng)絡(luò)通過訓(xùn)練使句子重建損失(sentence reconstruction loss
)最小化。在此過程中,編碼器學(xué)習(xí)生成向量表示,編碼足夠的信息供解碼器使用,以便它可以生成相鄰的句子。這些學(xué)習(xí)到的表示使得 語義相似的句子的嵌入在向量空間中彼此更接近,因此適用于聚類。我們把電子郵件中的句子作為編碼器網(wǎng)絡(luò)的輸入,以獲得所需的向量表示。
此處,我們可以使用 Skip-Thoughts
論文作者 開源的代碼。僅需幾行代碼就可以完成:
# The 'skipthoughts' module can be found at the root of the GitHub repository linked above
import skipthoughts# You would need to download pre-trained models first
model = skipthoughts.load_model()encoder = skipthoughts.Encoder(model)
encoded = encoder.encode(sentences)
2.5 Clustering
在為電子郵件中的每個(gè)句子生成句子嵌入后,可以對(duì)這些在高維向量空間中的嵌入進(jìn)行聚類。聚類的數(shù)量將等于摘要中所需的句子數(shù)量??梢詫⒄械木渥訑?shù)定義為電子郵件中句子總數(shù)的平方根,也可以認(rèn)為它等于句子總數(shù)的 30%30\%30%。
import numpy as np
from sklearn.cluster import KMeansn_clusters = np.ceil(len(encoded)**0.5)
kmeans = KMeans(n_clusters=n_clusters)
kmeans = kmeans.fit(encoded)
2.6 Summarization
每個(gè)聚類都可以被理解為一組語義相似的句子,其含義可以由摘要中的一個(gè)候選句子表達(dá)。候選句子是向量表示最接近聚類中心的句子。然后對(duì)每個(gè)集群對(duì)應(yīng)的候選句子進(jìn)行排序,以形成電子郵件的摘要。摘要中候選句子的順序由句子在原始電子郵件中的位置決定。
from sklearn.metrics import pairwise_distances_argmin_minavg = []
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])
最終生成的摘要結(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’App Store.
3.訓(xùn)練過程
預(yù)訓(xùn)練模型可用于編碼英語句子。對(duì)于丹麥語句子,必須自己訓(xùn)練 Skip-Thought
模型。數(shù)據(jù)取自丹麥語維基百科轉(zhuǎn)儲(chǔ)(Danish Wikipedia dumps
)。此處使用 WikiExtractor
解析維基百科轉(zhuǎn)儲(chǔ),雖然它不是最好的工具,但它是免費(fèi)的,并且可以在合理的時(shí)間內(nèi)完成這項(xiàng)工作。
由此生成的訓(xùn)練數(shù)據(jù)包括來自維基百科文章的 2,712,9352,712,9352,712,935 個(gè)丹麥語句子。訓(xùn)練過程還需要預(yù)先訓(xùn)練好的 Word2Vec
詞向量。此處使用的是 FacebookFacebookFacebook 的 FastTextFastTextFastText 的預(yù)訓(xùn)練詞向量。預(yù)訓(xùn)練模型的詞匯量為 312,956312,956312,956 個(gè)單詞。這些詞向量也是在丹麥語維基百科上進(jìn)行訓(xùn)練的,因此詞匯外的詞非常少見。
下面是該模塊的簡化版本,它僅支持英文電子郵件,但實(shí)現(xiàn)了上述所有步驟,效果非常好。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Module for E-mail Summarization
*****************************************************************************
Input Parameters:emails: A list of strings containing the emails
Returns:summary: A list of strings containing the summaries.
*****************************************************************************
"""# ***************************************************************************
import numpy as np
from talon.signature.bruteforce import extract_signature
from langdetect import detect
from nltk.tokenize import sent_tokenize
import skipthoughts
from sklearn.cluster import KMeans
from sklearn.metrics import pairwise_distances_argmin_min
# ***************************************************************************def preprocess(emails):"""Performs preprocessing operations such as:1. Removing signature lines (only English emails are supported)2. Removing new line characters."""n_emails = len(emails)for i in range(n_emails):email = emails[i]email, _ = extract_signature(email)lines = email.split('\n')for j in reversed(range(len(lines))):lines[j] = lines[j].strip()if lines[j] == '':lines.pop(j)emails[i] = ' '.join(lines)def split_sentences(emails):"""Splits the emails into individual sentences"""n_emails = len(emails)for i in range(n_emails):email = emails[i]sentences = sent_tokenize(email)for j in reversed(range(len(sentences))):sent = sentences[j]sentences[j] = sent.strip()if sent == '':sentences.pop(j)emails[i] = sentencesdef skipthought_encode(emails):"""Obtains sentence embeddings for each sentence in the emails"""enc_emails = [None]*len(emails)cum_sum_sentences = [0]sent_count = 0for email in emails:sent_count += len(email)cum_sum_sentences.append(sent_count)all_sentences = [sent for email in emails for sent in email]print('Loading pre-trained models...')model = skipthoughts.load_model()encoder = skipthoughts.Encoder(model)print('Encoding sentences...')enc_sentences = encoder.encode(all_sentences, verbose=False)for i in range(len(emails)):begin = cum_sum_sentences[i]end = cum_sum_sentences[i+1]enc_emails[i] = enc_sentences[begin:end]return enc_emailsdef summarize(emails):"""Performs summarization of emails"""n_emails = len(emails)summary = [None]*n_emailsprint('Preprecesing...')preprocess(emails)print('Splitting into sentences...')split_sentences(emails)print('Starting to encode...')enc_emails = skipthought_encode(emails)print('Encoding Finished')for i in range(n_emails):enc_email = enc_emails[i]n_clusters = int(np.ceil(len(enc_email)**0.5))kmeans = KMeans(n_clusters=n_clusters, random_state=0)kmeans = kmeans.fit(enc_email)avg = []closest = []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_,\enc_email)ordering = sorted(range(n_clusters), key=lambda k: avg[k])summary[i] = ' '.join([emails[i][closest[idx]] for idx in ordering])print('Clustering Finished')return summary
4.結(jié)果
當(dāng)郵件中包含多個(gè)句子時(shí),此種摘要方法效果較好。對(duì)于三句話的郵件,摘要可能是由兩句話組成,但三個(gè)句子傳達(dá)的意義可能完全不同,省略掉任何一個(gè)句子的信息都是不合適的。基于此,提取法通常并不適合短文本摘要。監(jiān)督式 Seq2Seq
模型更適合這項(xiàng)任務(wù)。
使用 Skip-Thought
方法進(jìn)行向量化的一個(gè)缺點(diǎn)是模型可能需要訓(xùn)練很長時(shí)間。盡管在訓(xùn)練 2?32-32?3 天后獲得了可接受的結(jié)果,但 Skip-Thought
模型在丹麥語語料上訓(xùn)練了大約一周。該模型是按句子長度歸一化的,所以成本在迭代期間波動(dòng)很大。
可以查看數(shù)據(jù)集中最相似的句子,了解 Skip-Thoughts 模型的效果。
例 111:
I can assure you that our developers are already aware of the issue and are trying to solve it as soon as possible.
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.
例 222:
I am very sorry to hear that.
We sincerely apologize for the inconvenience caused.
例 333:
Therefore, I would kindly ask you to tell me which operating system you are using the app on.
Can you specify which device you are using as well as the Android or iOS version it currently has installed?
5.優(yōu)化
通過增加模型的復(fù)雜性可以進(jìn)行一些相關(guān)的改進(jìn):
Quick-Thought Vectors
是Skip-Thoughts
方法的最新進(jìn)展,可以顯著減少訓(xùn)練時(shí)間并提高性能。Skip-Thought
編碼表示的維數(shù)為 480048004800。由于維數(shù)災(zāi)難,這些高維向量不適合聚類。在使用Autoencoder
或LSTM-Autoencoder
進(jìn)行聚類之前,可以進(jìn)行降維。- 可以通過訓(xùn)練解碼器網(wǎng)絡(luò)來實(shí)現(xiàn) 生成摘要,而不是提取摘要。解碼器網(wǎng)絡(luò)可以將聚類中心的編碼表示轉(zhuǎn)換回自然語言表示的句子。這樣的解碼器可以通過
Skip-Thoughts
編碼器生成的數(shù)據(jù)進(jìn)行訓(xùn)練。但是,如果我們希望解碼器生成合理且語法正確的句子,則需要對(duì)解碼器進(jìn)行非常仔細(xì)的超參調(diào)整和架構(gòu)決策。