文章整理:藝飯飯
內(nèi)容來(lái)源:DataFunTalk
導(dǎo)讀:隨著用戶規(guī)模和產(chǎn)品的發(fā)展, 知乎搜索面臨著越來(lái)越大的 query 長(zhǎng)尾化挑戰(zhàn),query 理解是提升搜索召回質(zhì)量的關(guān)鍵。本次分享將介紹知乎搜索在 query term weighting,同義詞擴(kuò)展,query 改寫,以及語(yǔ)義召回等方向上的實(shí)踐方法和落地情況。
▌知乎搜索的歷史
首先回顧下知乎搜索的歷史?,F(xiàn)有的知乎搜索16年開(kāi)始內(nèi)部研發(fā),17年中完全替換外部支持的系統(tǒng)。算法團(tuán)隊(duì)從 18 年初開(kāi)始成立,規(guī)模5人左右,之后開(kāi)始了快速的迭代過(guò)程。
主要進(jìn)展有: 18年 4 月份上線 Term Weight;6 月份上線自研的 Rust 引擎并已對(duì)外開(kāi)源;后續(xù)上線一系列的算法模型如糾錯(cuò)、語(yǔ)義相關(guān)性,以及今天會(huì)重點(diǎn)分享的語(yǔ)義索引和 query 改寫;今年下半年工作主要集中在排序側(cè),主要為用 DNN 替換了樹(shù)排序模型,并在此基礎(chǔ)上繼續(xù)上線了若干項(xiàng)收益不錯(cuò)的優(yōu)化。由于今天分享的內(nèi)容主要是在 NLP 范圍,排序側(cè)的內(nèi)容可以后續(xù)有機(jī)會(huì)再分享。
知乎是一個(gè)問(wèn)答類型的社區(qū)平臺(tái),內(nèi)容以用戶生產(chǎn)的問(wèn)題和回答為主。問(wèn)答網(wǎng)站的屬性導(dǎo)致了知乎搜索 query 詞的長(zhǎng)尾化。實(shí)際上在大搜領(lǐng)域中問(wèn)答類 query 也是相對(duì)滿意度比較差的一類,而目前各類垂搜分流了原來(lái)大搜的流量,當(dāng)中知乎搜索承擔(dān)了一部分相對(duì)比較難處理的 query。
從我們內(nèi)部實(shí)際數(shù)據(jù)來(lái)看,近一年知乎搜索的長(zhǎng)尾化趨勢(shì)也越來(lái)越明顯。如上圖右上部分是頭腰尾部搜索比例,可以看到長(zhǎng)尾 query 增長(zhǎng)趨勢(shì)明顯。但在我們搜索團(tuán)隊(duì)的努力下,用戶的搜索滿意度并沒(méi)有隨著 query 難度的增加而下降。
▌長(zhǎng)尾 query 特點(diǎn)
長(zhǎng)尾 query 的多樣性對(duì)于搜索系統(tǒng)來(lái)說(shuō)是一個(gè)很大的挑戰(zhàn),原因有:
? 存在輸入錯(cuò)誤。例如上圖中的錯(cuò)誤 query '塞爾維雅' ( 塞爾維亞 ),對(duì)于這種錯(cuò)誤我們希望系統(tǒng)能夠自動(dòng)的糾錯(cuò);
? 存在表達(dá)冗余。例如輸入 '孫子兵法智慧的現(xiàn)代意義',在這個(gè)語(yǔ)境下,'智慧' 是一個(gè)無(wú)關(guān)緊要的詞。如果強(qiáng)制去匹配 '智慧' 的話,反而匹配不出真正想要的結(jié)果;
? 存在語(yǔ)義鴻溝。比如 '高跟鞋消音',其中 '消音' 這個(gè)詞的表達(dá)較少見(jiàn),使得同時(shí)包含 '高跟鞋' 和 '消音' 文檔較少。而類似的表達(dá)如 '高跟鞋聲音大如何消除'、'高跟鞋消聲' 等可能較多。用戶輸入的 query 和用戶生產(chǎn)內(nèi)容之間存在了語(yǔ)義鴻溝。其他類型的難點(diǎn)還有表達(dá)不完整,意圖不明等等。
我們先通過(guò)圖右邊這個(gè)query:'iPhone 手機(jī)價(jià)格多少' 來(lái)介紹如何解決上述問(wèn)題:
? 對(duì)于輸入錯(cuò)誤,比如說(shuō)用戶輸入的 query 是 iPhone,但是這個(gè)詞輸錯(cuò)了,會(huì)通過(guò)糾錯(cuò)模塊將其糾正為正確的 query;
? 對(duì)于表達(dá)冗余,通過(guò)計(jì)算每一個(gè)詞的重要程度也就是 term weight,來(lái)確定參與倒排索引求交操作的詞。先對(duì) query 進(jìn)行分詞,切成 iPhone、手機(jī)、價(jià)格、多少,之后判斷各詞對(duì)于表達(dá)意圖更重要,重要的詞會(huì)在檢索時(shí)參與倒排索引的求交操作,不那么重要的詞不嚴(yán)格要求一定在文檔中出現(xiàn);
? 解決語(yǔ)義鴻溝的問(wèn)題。需要對(duì)原始 query 做同義詞擴(kuò)展,比如 'iPhone' 和 '蘋果' 是同義詞,'價(jià)格' 和 '售價(jià)' 是同義詞。
所以在傳統(tǒng)的搜索領(lǐng)域中的查詢模塊,往往包含這些子任務(wù):糾錯(cuò)、分詞、緊密度、同義詞、詞權(quán)重,以及其他的如實(shí)體詞識(shí)別、意圖識(shí)別等等。這些查詢理解會(huì)生成一個(gè)結(jié)構(gòu)化的數(shù)據(jù),檢索模塊就可以通過(guò)結(jié)構(gòu)化的查詢串去召回相關(guān)的文檔。
▌知乎搜索的召回和排序
知乎的召回系統(tǒng)主要分為兩部分:
? 基于詞的傳統(tǒng)的倒排索引召回;
? 基于向量的向量索引的召回機(jī)制。
如圖所示,實(shí)際召回中有三個(gè)隊(duì)列,基于倒排索引的隊(duì)列占兩個(gè),分別是原始 Query 隊(duì)列和改寫 Query 隊(duì)列。改寫隊(duì)列是用翻譯模型去生成一個(gè)表達(dá)更適合檢索的 query,然后再去做 query 理解和索引召回。而第三個(gè)隊(duì)列是基于 embedding 的索引。首先把所有 doc、原始 query 都轉(zhuǎn)為向量,再通過(guò)空間最近鄰的 KNN-Search,找到與 query 最相似的文檔。
最終參與排序的就是這三個(gè)隊(duì)列,并進(jìn)行合并和精排,在精排之后會(huì)進(jìn)行上下文排序。下面來(lái)介紹下各個(gè)模塊具體的實(shí)現(xiàn)方法。
▌Query Term Weight
對(duì)于 term weight,最簡(jiǎn)單的實(shí)現(xiàn)方式是用 IDF 逆文檔頻率算出,即看這個(gè)詞在語(yǔ)料里的出現(xiàn)次數(shù),如果次數(shù)較少,則認(rèn)為其包含的信息量是相對(duì)較多。
這個(gè)方法的局限是無(wú)法根據(jù) query 上下文語(yǔ)境動(dòng)態(tài)適應(yīng),因?yàn)槠湓诓煌纳舷挛闹?weight 是一致的。所以我們?cè)偻ㄟ^(guò)統(tǒng)計(jì)點(diǎn)擊數(shù)據(jù)中進(jìn)行調(diào)整。如圖,如果用戶的 query 包含 a,b 兩個(gè) term,并且點(diǎn)擊了 Doc1 和 Doc4,其中 Doc1 包含 a,b, Doc4 只包含a,即 a 出現(xiàn)2次,b 出現(xiàn)1次。一個(gè)樸素的想法就是 a 的權(quán)重就是1,b 是0.5,這樣就可以從歷史日志里把每個(gè) query 里的 term 權(quán)重統(tǒng)計(jì)出來(lái)。
這個(gè)方法對(duì)于從未出現(xiàn)過(guò)的 query 就無(wú)法從歷史數(shù)據(jù)中統(tǒng)計(jì)得到。所以我們從 query 粒度泛化到 gram 粒度,按 ngram 來(lái)聚合。比如 a,b 就是一個(gè) bigram,類似于 mapreduce 的 map 過(guò)程,首先會(huì)把 query 中的 ngram 先 map 出來(lái),再發(fā)送到 reduce 里面統(tǒng)計(jì)。這樣就能統(tǒng)計(jì)出每個(gè) ngram 下較置信的權(quán)重。
對(duì)于 ngram,在實(shí)際操作中需要注意以下幾點(diǎn):
? 詞表較大,往往在十億量級(jí)以上;
? 字典更新較慢;
? 無(wú)法處理長(zhǎng)距離依賴?;咀疃嗟?3gram,多 gram 詞不僅會(huì)使詞表更加膨脹,詞與詞的依賴關(guān)系也將更難捕捉到;
? 無(wú)法解決過(guò)于稀疏的詞,過(guò)于長(zhǎng)尾的詞會(huì)退化成 idf。
我們的解法是把 ngram 基于詞典的泛化方法變?yōu)榛?embedding 的模型泛化方法。目標(biāo)是想得到根據(jù) query 語(yǔ)境動(dòng)態(tài)自適應(yīng)的 term weight。如果可以獲取跟 query 上下文相關(guān)的動(dòng)態(tài)詞向量,那么在詞向量的基礎(chǔ)上再接 MLP 就可以預(yù)測(cè)出詞權(quán)重了。目前的方法是通過(guò) term 詞本身的詞向量減去 query 所有詞 pooling 之后的詞向量獲得,今后也會(huì)嘗試替換成 ELMo 或者 Transformer 的結(jié)構(gòu)以獲得更好的效果。
▌同義詞擴(kuò)展
對(duì)于同義詞擴(kuò)展策略,首先需要一個(gè)同義詞詞表?,F(xiàn)在有可以直接應(yīng)用的公開(kāi)數(shù)據(jù)集。但是數(shù)據(jù)集的詞與知乎搜索里的詞可能由于分詞粒度不一致而不匹配,并且同義詞無(wú)法保證更新。所以我們主要用內(nèi)部語(yǔ)料進(jìn)行數(shù)據(jù)挖掘,主要方向?yàn)椋?/p>
Word2vec 這一類的 embedding 計(jì)算方法,核心假設(shè)是擁有相似上下文的詞相似。需要注意該方法無(wú)法區(qū)分同義詞和反義詞/同位詞,例如最大/最小,蘋果/香蕉。我們這里利用監(jiān)督學(xué)習(xí)的信號(hào),對(duì)訓(xùn)練完成的詞向量空間進(jìn)行微調(diào)。
▌Query 改寫
接下來(lái)分享的是 query 改寫部分。為什么要做 query 改寫?
在傳統(tǒng)搜索里,一個(gè) query 進(jìn)來(lái)需要做多個(gè)子任務(wù)的處理。假如每個(gè)任務(wù)只能做到90%,那么積累起來(lái)的損失會(huì)非常大。我們需要一個(gè)方法一次性完成多個(gè)任務(wù)去減小損失,比如把 '蘋果手機(jī)價(jià)格多少' 直接改寫為 '蘋果手機(jī)售價(jià)'。
用翻譯方法可以實(shí)現(xiàn)這個(gè)需求,即把改寫問(wèn)題看成 src 和 target 語(yǔ)言為同一種語(yǔ)言的翻譯問(wèn)題,翻譯模型用的是谷歌的 NMT 結(jié)構(gòu)。
對(duì)于這個(gè)任務(wù)來(lái)說(shuō),訓(xùn)練語(yǔ)料的挖掘比修改模型結(jié)構(gòu)更為重要,我們通過(guò)用戶行為日志來(lái)挖掘訓(xùn)練語(yǔ)料。比如從 query 到 title,點(diǎn)擊同一 doc 的不同 query,都可形成平行語(yǔ)料。
最后我們用來(lái)訓(xùn)練模型的語(yǔ)料用的是 Query -> Query 的平行語(yǔ)料,因?yàn)閮烧咴谕粋€(gè)語(yǔ)義空間,長(zhǎng)度也基本接近。如果 query 翻譯成 title,則會(huì)因?yàn)?title 長(zhǎng)度通常過(guò)長(zhǎng)而加大訓(xùn)練復(fù)雜度。
具體方法是:
▌Query 改寫 – 強(qiáng)化學(xué)習(xí)
具體來(lái)說(shuō),改寫模型是拿共現(xiàn)數(shù)據(jù)做訓(xùn)練語(yǔ)料,但不能保證改寫出來(lái)的結(jié)果一定可以召回有用的文檔。我們參考了谷歌 2018 ICLR 的工作,為了將用戶輸入的 query 改寫為更容易檢索出答案的 query,把 QA 系統(tǒng)當(dāng)做一個(gè) environment,改寫模型當(dāng)做 agent,CNN 是對(duì)所有召回結(jié)果做選擇的模塊。
在我們的場(chǎng)景中,將圖中灰色框里的 QA 對(duì)應(yīng)一套倒排索引,CNN 對(duì)應(yīng)在線排序服務(wù)模塊。
首先會(huì)把原始 query 的召回結(jié)果和改寫 query 的召回結(jié)果一并送入排序服務(wù)模塊,然后得到 topK 的排序;之后統(tǒng)計(jì)這 topK 結(jié)果里有多少是改寫 query 召回隊(duì)列里的結(jié)果,將其作為 reward。
接下來(lái),我們用強(qiáng)化學(xué)習(xí) policy gradient 方法來(lái) finetune 改寫模型。利用強(qiáng)化學(xué)習(xí)的一個(gè)好處是,不再需要對(duì)齊文本語(yǔ)料,只需要隨機(jī)的 query 即可。
在利用強(qiáng)化學(xué)習(xí)訓(xùn)練時(shí)遇到的問(wèn)題之一是 reward 稀疏問(wèn)題。我們發(fā)送了很多 NMT 模型的結(jié)果給線上系統(tǒng),但在返回來(lái)的 topK 列表里并不包含改寫隊(duì)列的召回。這導(dǎo)致了訓(xùn)練的過(guò)程非常的緩慢,也對(duì)線上系統(tǒng)造成了很大的開(kāi)銷。
為了緩解 reward 稀疏問(wèn)題,參照 alphago 里面的模式,即由策略網(wǎng)絡(luò),價(jià)值網(wǎng)絡(luò)和蒙特卡洛樹(shù)搜索三個(gè)組件完成。我們可以把 NMT 當(dāng)成是一個(gè)策略網(wǎng)絡(luò),然后這里主要添加了價(jià)值網(wǎng)絡(luò)。價(jià)值網(wǎng)絡(luò)用來(lái)評(píng)估一次改寫完成以后,其實(shí)際能從系統(tǒng)當(dāng)中拿到多少 reward。他的輸入是兩個(gè)拼接在一起的 query,輸出是一個(gè)浮點(diǎn)值。用強(qiáng)化學(xué)習(xí)的經(jīng)驗(yàn)來(lái)學(xué)習(xí)這個(gè)價(jià)值網(wǎng)絡(luò),然后將其后面的訓(xùn)練過(guò)程中來(lái)加速訓(xùn)練。
最后的優(yōu)化效果非常明顯,在加入價(jià)值網(wǎng)絡(luò)以后 reward 比例提升了50%以上。
同時(shí),這個(gè)價(jià)值網(wǎng)絡(luò)還可以用于在線改寫觸發(fā) rerank。如下圖所示,線上覆蓋率有了明顯提升, top20 包含 rewrite 比例的 query 數(shù)量占到了24%,query doc 數(shù)量占到了4%。
在改寫中我們還訓(xùn)練了從 title 到 query 的模型,解決了檢索中的重要字段 clicked query 的覆蓋率有限和展現(xiàn)偏置兩個(gè)問(wèn)題。Clicked query 字段是記錄點(diǎn)擊過(guò)這個(gè)文檔的 query,就是說(shuō)盡管這個(gè) doc 不含 query 里的詞,但如果有別的用戶搜了類似的 query 所點(diǎn)擊的 doc,也會(huì)將其召回。
記錄 clicked query 會(huì)遇到點(diǎn)擊噪音和展示偏置的問(wèn)題。因?yàn)橛悬c(diǎn)擊的文檔比沒(méi)有點(diǎn)擊的文檔要多一個(gè)字段,使得在召回時(shí)有一定優(yōu)勢(shì),從而形成正向循環(huán),導(dǎo)致了展示偏置。
通過(guò)訓(xùn)練從 title 到 query 的模型,替換掉了 clicked query。這樣把每個(gè)文檔都寫有這個(gè)字段。雖然模型的效果沒(méi)有 query 到 query 的模型好,但因?yàn)檫@個(gè)模型建在索引里所以容錯(cuò)率會(huì)更高。
以上就是基于詞的一些算法階段的過(guò)程,最后分享一下語(yǔ)義召回。
▌語(yǔ)義召回
語(yǔ)義召回就是把 query 和 doc 都表示為向量,然后在向量空間中做最近鄰的搜索。相對(duì)于圖像領(lǐng)域,在 NLP 領(lǐng)域還不夠成熟,因?yàn)橛脩糨斎氲谋磉_(dá)可能差一個(gè)字含義完全不同提高了語(yǔ)義召回難度。
在模型上需要訓(xùn)練深度語(yǔ)義模型,主要分為兩種:
? 基于 interaction 的深度語(yǔ)義模型
Interaction based 用于判斷兩個(gè)文檔的相似性。該方法提前算出 query 里每個(gè)詞和 titile 里每個(gè)詞的相似性,得到相似性矩陣。之后直接用例如 CNN 圖像卷積的方法處理該矩陣,計(jì)算相似度。
? 基于 representation 的深度語(yǔ)義模型
Representation 的意思是先分別將 query 和 title 進(jìn)行網(wǎng)絡(luò)的處理,分別得到向量,再預(yù)測(cè)兩者相似度的分?jǐn)?shù)。
按照經(jīng)驗(yàn)來(lái)說(shuō),interaction based model 效果會(huì)好于 representation based model。但是在向量召回這個(gè)任務(wù)當(dāng)中,我們需要離線計(jì)算好所有文檔的 embedding 并建成向量索引,所以語(yǔ)義召回采用的的是 representation based 模型。
▌語(yǔ)義召回 – BERT 模型
在 NLP 領(lǐng)域,做 embedding 召回難度大,原因?yàn)椋?/p>
? Query 長(zhǎng)尾,難以捕捉細(xì)粒度的差異
? 需要泛化
? 過(guò)多誤召回傷害用戶體驗(yàn)
目前BERT 模型帶領(lǐng) NLP 進(jìn)入了新的時(shí)代,借鑒經(jīng)典的孿生網(wǎng)絡(luò)結(jié)構(gòu),我們用 BERT 模型分別做 query 和 doc 的 encoder,接著用 pooling 之后的 query doc cosine 距離當(dāng)做輸出,最后通過(guò) pairwise 損失函數(shù)訓(xùn)練模型。在 pooling 方法上,我們也嘗試過(guò)不同層 pooling,或者在多層上增加 attention 聚合 BERT 多層結(jié)果,效果和最后一層所有 token 做 average pooling 相當(dāng)。損失函數(shù)方面,因?yàn)槲覀兪亲稣倩仉A段的模型,所以參考過(guò)雅虎的方法,他們認(rèn)為在一輪排序階段使用 pointwise 損失函數(shù)的效果會(huì)更好,但是在我們的數(shù)據(jù)上 pairwise 還是會(huì)稍好一些。
在 BERT 模型的基礎(chǔ)上,我們還做了兩項(xiàng)優(yōu)化:
? 優(yōu)化預(yù)訓(xùn)練模型, mask token pretrain
這里主要是參考 百度 ernie 的做法,在知乎的語(yǔ)料上,用中文的分詞粒度的數(shù)據(jù)繼續(xù)做了 mask token pretrain,使得預(yù)訓(xùn)練模型能夠更好的適應(yīng)中文的詞關(guān)系
? 數(shù)據(jù)增強(qiáng),增加一些對(duì)于模型來(lái)說(shuō)更難區(qū)分的負(fù)樣本
具體采樣方法為:
用原始的腳本數(shù)據(jù)去微調(diào)一個(gè)模型,計(jì)算 doc 的 embedding 和 query 的 embedding。對(duì) doc embedding 進(jìn)行聚類,此時(shí) doc 和 query 的 embedding 就在同一空間里,所以 query embedding 就可以對(duì)應(yīng)到某一個(gè)類別。這時(shí)候即可從 doc 里直接采樣一些負(fù)樣本了。
向量召回上線以后效果提升明顯。如圖右上方的 case,雖然 query 錯(cuò)誤,但仍召回了正確結(jié)果。
▌后續(xù)方向
以上是知乎搜索最近一年在召回側(cè)的一些工作,后續(xù)的其他方向有:
? GAN 在 query 改寫的應(yīng)用
因?yàn)橹坝玫氖钦鎸?shí)系統(tǒng)計(jì)算 reward,代價(jià)較高,所以考慮用 gan 來(lái)代替真實(shí)系統(tǒng)去計(jì)算 reward,這樣樣本數(shù)據(jù)的計(jì)算會(huì)速度非常快。
? 預(yù)訓(xùn)練方面
嘗試把預(yù)訓(xùn)練模型做小以便用于更多場(chǎng)景中。目前由于參數(shù)規(guī)模大,時(shí)間開(kāi)銷大,導(dǎo)致無(wú)法廣泛運(yùn)用。
? 進(jìn)一步探索強(qiáng)化學(xué)習(xí)在其他場(chǎng)景的應(yīng)用
如應(yīng)用于 Query 的 term weight 中。
聯(lián)系客服