bert中的sep_基于向量的深层语义相似文本召回?你需要BERT和Faiss
文章來源于微信公眾號:每天都要機器學習
原文鏈接:請點擊
文章僅用于學習交流,如有侵權請聯系刪除
智能客服系統利用FAQ問答庫做自動問答,也就是基于信息檢索的自動問答系統。它的一般做法流程是:
整個流程可以簡化成粗召回和精排序兩個步驟,可以看到如果在粗召回階段沒有召回到真正和 query 意思相同的 question 的話,那么精排序再怎么排也不會排出能回答用戶問題的 answer 了;
因此我們在做粗召回的時候應該盡量多召回一些相關的 question,這叫寧錯召一千,不漏放一個。但是如果真的召回太多的話,那么在精排序階段的計算量就比較大了,這在系統中體現的是計算時間超時,用戶已經等得不耐煩了。因此我們需要在粗召回的數量和質量里面做一些折中。
對于有選擇困難癥的人來說,做這樣的折中總是很困難的,那么有沒有方法避免折中情況呢?答案當然是有的,比如你把召回算法進行改進,讓召回的 question 的質量總是比較好,那就大可不必實行“寧錯召一千,不漏放一個”策略了。
本文要講的就是如何提升召回質量的問題。
我們知道一般的文本召回其實就是通過關鍵詞進行召回的,通過對 query 進行分詞,然后再和 FAQ 庫中的 question 進行一一匹配,看和哪些question的匹配度最高,然后將其召回就好。
為了提升召回速度,工作中一般借助 elstiscsearch 這個數據庫來存儲 FAQ,然后再進行索引召回。elstiscsearch使用的其實就是倒排索引技術,它事先把所有 question 進行分詞,然后建立詞-文檔 矩陣,最終實現根據單詞快速獲取包含這個單詞的文檔列表之目的;倒排索引我就不做具體介紹了,有興趣的自行去搜索資料了解。使用該方法做相似文檔召回的優勢很明顯,實現簡單、不需要訓練模型、低資源需求、檢索速度快,深受各大小公司喜愛。
然而它的缺點也很明顯,文本是具有語義的、是有語法結構的,倒排索引忽略了語句的語法結構,同時也無法解決一詞多義和同義詞的問題,也就它無法對 query 進行語義層面的召回。
那么如何做到從語義層面對相似文本進行召回呢?在深度學習沒有流行的時候,研究人員使用主題模型來進行計算文本的語義信息,常見的有LDA、LSI、PLSA等,這些都是基于概率和統計的算法,他們通過文檔中詞語的共現情況來對文檔、詞語進行向量化表達,能夠做到一定的語義層面的相似度計算。
而且也有開源工具來方便進行建模學習,以 LSI 模型為例,我們可以使用gensim 來對所有(question,answer)中的 question 進行主題建模,但是這面臨著一個問題,即我們需要選擇一個主題數量 k 作為訓練參數,這個參數的選擇完全看運氣;另外這類模型對長尾分布的question不能很好的進行表示,在語義層面也只能做淺層的語義表達。LSI是個無監督算法,這是它的優勢,我們通常將其作為文本分類或文本相似性任務中給數據打標簽的輔助工具。
在文章Deep text matching--盤點11個文本匹配模型 中我介紹過可以使用表示型文本匹配模型(孿生網絡、雙塔網絡)進行有監督訓練,得到語義表示模型,然后使用該模型對所有 question 進行向量化編碼,進而使用向量檢索工具進行深層語義層的相似question召回。但同時文章中的實驗數據也說明了,這類模型在文本匹配的效果上是比不上交互式模型的。那么有沒有辦法把這種孿生網絡變得更強,以進行高質量的相似 question 召回呢?
答案當然是使用bert嘛!所謂效果不行,使用bert。但是使用一般的 bert 是不行的,如下圖所示
在做文本匹配任務時,通常是將兩個句子進行拼接輸入,然后將其作為一個二分類任務來微調。拼接方式是[CLS] sent_a [SEP] sent_b。
之所以說這樣是不行的,因為模型無法單獨獲取 sent_a 和 sent_b 的句向量表達。原因在于多頭 attention 會把 sent_b 的信息編碼到 sent_a 之中,把sent_a 的信息編碼到 sent_b 之中,也就是這種做法不適合用來對(question,answer)中的question進行單獨編碼存儲。于是有研究人員自然想到使用 bert 來來搭建孿生網絡[1],如下圖所示,使用兩個bert分別對sent_a 和 sent_b 進行編碼,然后得到句子向量之后計算余弦相似度。
這樣訓練出來的模型就可以單獨對一句話進行向量表達了,比如我要得到sent_a 的向量,那么就把 sent_b 置為空字符串就行,因為不管 sent_b 是什么都不影響模型對 sent_a 的最終表達。然而,這個模型明顯太復雜了,平時訓練一個 bert 機器就很吃勁了,這還訓練兩個 bert?而且在推理階段我們也不能忍受多余的一個bert帶來的時間消耗。那么有沒有更好的模型呢!?
我們看看 UniLM 模型[2],它是一個融合 NLU 和 NLG 能力的 Transformer 模型,是微軟在2019年5月份提出來。下圖是該模型的主體框架。
下文借鑒蘇建林大佬的文章中[3]相關內容。UniLM的核心是通過特殊的Attention Mask 機制來賦予模型具有 Seq2Seq 的能力。假如輸入是“你想吃啥”,目標句子是“白切雞”,那 UNILM 將這兩個句子拼成一個:[CLS] 你 想 吃 啥 [SEP] 白 切 雞 [SEP],然后接如圖的Attention Mask:
換句話說,[CLS] 你 想 吃 啥 [SEP]這幾個 token 之間是雙向的 Attention,而白 切 雞 [SEP]這幾個token則是單向 Attention,從而允許遞歸地預測白 切 雞 [SEP]這幾個token,所以它具備文本生成能力。
因為UniLM特殊的Attention Mask,所以[CLS] 你 想 吃 啥 [SEP]這6個token 只在它們之間相互做Attention,而跟白 切 雞 [SEP]完全沒關系,這就意味著,盡管后面拼接了白 切 雞 [SEP],但這不會影響到前6個編碼向量。再說明白一點,那就是前6個編碼向量等價于只有[CLS] 你 想 吃 啥 [SEP]時的編碼結果,如果[CLS]的向量代表著句向量,那么它就是你 想 吃 啥的句向量,而不是加上白 切 雞后的句向量。
我們可以看到,雖然UniLM的輸入也是兩個句子,但是卻通過特殊的Attention Mask機制,使得模型能單獨得到 sent_a 的向量表達,從而能夠使得模型能對所有 question 進行事先編碼成向量進行保存,從而使得使用向量進行深層語義相似性檢索成為可能。我使用該模型在螞蟻金服的數據上進行微調后,將測試集中的數據進行了向量編碼,然后借助 faiss 向量檢索工具進行問句的向量相似性召回,下圖展示了召回的效果。
可以看到召回的相似 question 質量是相當高的。如果你對這個工作感興趣,可以去這里看看蘇大佬的開源代碼[4];當然如果你想看看我的代碼也行,我會在適當的時候把我的代碼提交到這個倉庫[5](可以提前點個星或者watch)。我的代碼大部分都源于[4],但是因為使用的訓練數據不同,且也增加了faiss做向量檢索召回,所以還是有稍微不同的。
參考資料:
[1]https://arxiv.org/pdf/1908.10084.pdf
[2]https://arxiv.org/pdf/1905.03197.pdf
[3]https://kexue.fm/archives/7427
[4]https://github.com/ZhuiyiTechnology/simbert
[5]https://github.com/wangle1218/deep_text_matching
「華來知識」成立于2017年,孵化于清華大學智能技術與系統國家重點實驗室,是一家技術領先的人工智能企業。公司專注于提供新一代人工智能人機交互解決方案,利用自身技術為企業打造由人工智能驅動的知識體系,借此改善人類生活。「華來知識」將持續為企業客戶提供優質服務,助力企業在專業領域的人工智能應用,提供完善可靠高效的產品解決方案。
總結
以上是生活随笔為你收集整理的bert中的sep_基于向量的深层语义相似文本召回?你需要BERT和Faiss的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: android开发岗_android应用
- 下一篇: dump java崩溃自动 不生成_Gi