知乎搜索排序模型的演進(jìn),答主必看

大家好,我是你們的躍哥。熟悉的朋友都知道,躍哥在知乎也有一段時(shí)間了,無論是問答分享,還是知乎好物,都是玩轉(zhuǎn)開了。加上鹽選里還能白嫖各類優(yōu)秀的書籍,以及一些優(yōu)秀的課程,知乎已經(jīng)成為躍哥每天必須打開N次的App。
那很多人就會(huì)納悶,知乎是如何進(jìn)行算法處理,讓你的排名在搜索之后更靠前呢?今天開始,躍哥將連續(xù)分享幾篇朋友圈里優(yōu)秀的知乎類文章,請小伙伴們持續(xù)看過來吧。

分享嘉賓:王瑞欣 知乎 算法工程師
編輯整理:郭真繼
出品平臺(tái):DataFunTalk
導(dǎo)讀:搜索,是用戶獲取信息,找答案最方便快捷的方式。一次用戶搜索會(huì)經(jīng)歷 Query 解析、召回、排序多個(gè)環(huán)節(jié),排序作為最后整個(gè)過程一環(huán),對用戶的體驗(yàn)有最直接的影響。今天分享的內(nèi)容是知乎搜索排序模型的演進(jìn)。
主要內(nèi)容包括:
知乎搜索發(fā)展歷程
排序算法的迭代升級(jí)
一些未上線的嘗試
未來方向
1.?知乎搜索
知乎作為一個(gè)大型的中文問答社區(qū),有超過四千萬的提問和超過兩億條回答,其中蘊(yùn)含了豐富的知識(shí)、經(jīng)驗(yàn)和見解,知乎搜索是幫助用戶快速獲取信息,找到答案的重要途徑,隨著媒介的升級(jí),搜索結(jié)果的形式也不在局限于圖文,視頻解答也越來越多。

2. 知乎搜索算法發(fā)展歷程
知乎的搜索算法團(tuán)隊(duì)成立于2017年底,于2018年8月上線了深度語義匹配模型。在2019年4月引入了BERT 模型,同年8月排序模型由 GBDT 升級(jí)為 DNN 模型,隨后在DNN模型的基礎(chǔ)上進(jìn)行了一系列的迭代升級(jí)。

3. 知乎搜索架構(gòu)
一次搜索流程主要包括 Query 解析、召回、排序幾個(gè)階段。用戶輸入 Query 之后,首先要進(jìn)行 Query 解析,生成查詢 Query Tree 和語義表示向量。之后進(jìn)入多隊(duì)列的召回模塊,召回階段從召回方式上說可以分為倒排召回和向量召回,在這一環(huán)節(jié)會(huì)篩選出前400的文檔進(jìn)入到排序階段。排序階段又分為精排和重排序兩個(gè)環(huán)節(jié),精排階段通過模型對多召回源的文檔進(jìn)行統(tǒng)一打分,之后將 Top16的文檔送入重排序模型進(jìn)行位置的微調(diào),最終呈現(xiàn)給用戶。本次主要分享精排和重排序階段兩部分的模型演進(jìn)。

1. 由GBDT模型升級(jí)到DNN模型
2019年8月份我們將排序模型由GBDT升級(jí)到DNN模型,這么做主要是考慮到兩點(diǎn):
數(shù)據(jù)量變大之后,DNN能夠?qū)崿F(xiàn)更復(fù)雜的模型,而GBDT的模型容量比較有限。
新的研究成果都是基于深度學(xué)習(xí)的研究,采用深度神經(jīng)網(wǎng)絡(luò)之后可以更好的應(yīng)用新的研究成果,比如后面介紹的多目標(biāo)排序。
升級(jí)到DNN模型之后,線上效果有一定的提高。

2. DNN排序模型結(jié)構(gòu)
我們的DNN排序模型整體是在谷歌開源的TF-Ranking[1] 框架的基礎(chǔ)上開發(fā)的,TF-Ranking 使用了 Estimator API,提供了排序任務(wù)常見的損失函數(shù)和指標(biāo)計(jì)算實(shí)現(xiàn),比如 Pairwise Loss 和 NDCG指標(biāo),以及通過Multi-head支持了多目標(biāo)訓(xùn)練。整體的代碼結(jié)構(gòu)根據(jù)訓(xùn)練流程可以拆分成特征輸入、特征轉(zhuǎn)化、模型打分和損失計(jì)算等幾個(gè)獨(dú)立的模塊。清晰合理的模塊劃分為后續(xù)的快速迭代提供了很大的方便和靈活性。下面簡單介紹下各個(gè)模塊:
特征輸入模塊,將 Query特征、相關(guān)性特征、文檔質(zhì)量特征和歷史點(diǎn)擊特征等輸入模型。
特征轉(zhuǎn)化模塊,做一些常見的特征處理工作,比如取 log、歸一化、onehot 和類別特征轉(zhuǎn) Embeding 等。
模型主體結(jié)構(gòu)部分包括主網(wǎng)絡(luò)部分、 End2End 部分,SeRank[5] 部分,Unbias tower 部分和 MOE 方式實(shí)現(xiàn)的多目標(biāo)排序部分,后面會(huì)做詳細(xì)介紹。

3. 多目標(biāo)排序
搜索排序任務(wù)的學(xué)習(xí)目標(biāo)首先能想到的就是預(yù)測用戶點(diǎn)擊,我們最初的排序模型也是這樣做的。但是用戶點(diǎn)擊只是第一步,單純的點(diǎn)擊行為并不能代表用戶對搜索結(jié)果的滿意,我們需要同時(shí)考慮用戶在點(diǎn)擊之后的一系列行為,比如閱讀時(shí)長、點(diǎn)贊、收藏、關(guān)注、分享、評(píng)論等等。這些行為都可以作為排序任務(wù)的訓(xùn)練目標(biāo),由于可選的目標(biāo)比較多,我們通過分析這些指標(biāo)與用戶留存的關(guān)系進(jìn)行了篩選,與點(diǎn)擊率一起構(gòu)成了排序模型的目標(biāo),開啟了我們在多目標(biāo)排序方面的探索。

① 基于 hard sharing 的第一版多目標(biāo)排序模型
第一版的多目標(biāo)排序采用的是共享參數(shù)層+任務(wù)獨(dú)立參數(shù)層的結(jié)構(gòu)。共同學(xué)習(xí)的多個(gè)目標(biāo)是有內(nèi)在聯(lián)系的,對一個(gè)目標(biāo)的訓(xùn)練會(huì)幫助到其他目標(biāo),通過共享底層參數(shù)可以實(shí)現(xiàn)這個(gè)目的。在共享參數(shù)層之上又加了任務(wù)獨(dú)立的參數(shù)層,使各個(gè)訓(xùn)練任務(wù)之間可以獨(dú)立更新參數(shù),保證互不影響。需要注意的是,不同目標(biāo)的訓(xùn)練數(shù)據(jù)是不一樣的,轉(zhuǎn)化類的目標(biāo)比如閱讀時(shí)長、點(diǎn)贊、收藏,這些要用戶點(diǎn)擊之后才能發(fā)生,所以只在有點(diǎn)擊的數(shù)據(jù)上計(jì)算 Loss。另外由于閱讀時(shí)長呈長尾分布,需要用對數(shù)時(shí)長作為訓(xùn)練目標(biāo)。在多目標(biāo)模型中每個(gè)目標(biāo)都會(huì)對應(yīng)一個(gè)模型打分,在線上預(yù)測是需要多多個(gè)分?jǐn)?shù)進(jìn)行加權(quán)融合。至于不同的目標(biāo)對應(yīng)的具體權(quán)重我們是通過 AB 實(shí)驗(yàn)確定的。

② 基于 MMOE 的第二版多目標(biāo)排序
在去年年初的時(shí)候,我們采用 MMOE[2] 結(jié)構(gòu)對多目標(biāo)排序模型進(jìn)行了升級(jí)。與 hard sharing 結(jié)構(gòu)不同,MMOE 引入了 Expert,將共享參數(shù)層替換為多個(gè) Experts 加權(quán)相加的方式,這些參數(shù)既是各個(gè)任務(wù)共享的,又通過獨(dú)立權(quán)重的方式給了各個(gè)任務(wù)一定的獨(dú)立性。這一版的更新在上線之后也是取得了一定的收益。

4. Unbias LTR
在使用用戶點(diǎn)擊日志作為訓(xùn)練數(shù)據(jù)時(shí),點(diǎn)擊日志中的一些噪聲會(huì)對訓(xùn)練帶來一定的負(fù)面影響。其中最常見的噪聲就是Position bias,由于用戶的瀏覽行為是從上到下的,所以同樣的內(nèi)容出現(xiàn)的位置越靠前越容易獲得點(diǎn)擊。以用戶搜索小兒感冒為例,比如同時(shí)給用戶展示了五條結(jié)果,用戶在點(diǎn)擊第一條之后獲得了滿足退出了這次搜索,這時(shí)就會(huì)生成一條訓(xùn)練數(shù)據(jù),第一條作為正樣本,其他的作為負(fù)樣本,但是其實(shí)后面幾條結(jié)果質(zhì)量也比較好,如果后面的結(jié)果出現(xiàn)在第一條的位置也會(huì)發(fā)生點(diǎn)擊,所以點(diǎn)擊是受到位置影響的。在這種情況下訓(xùn)練數(shù)據(jù)是有偏的。

對于這個(gè)問題,有兩種解決思路:
① 降低Top位置的樣本權(quán)重
既然Top位置更容易受到位置偏差的影響,那么我們就降低頭部樣本的權(quán)重。
至于樣本權(quán)重的確定,我們嘗試過兩種方案:
根據(jù)點(diǎn)擊模型預(yù)估每個(gè)位置的權(quán)重,預(yù)估出來的結(jié)果可能是第一位0.7然后一直增加,到第五位是0.9
通過模型在訓(xùn)練的過程中自動(dòng)學(xué)習(xí)權(quán)重
但是這兩種方案上線之后都沒有正向效果。
② 對Position bias建模
用戶實(shí)際點(diǎn)擊 = 真實(shí)點(diǎn)擊率+ Position Bias
另一種思路就是考慮 Position Bias 的情況下,重新對用戶點(diǎn)擊進(jìn)行建模。既然用戶點(diǎn)擊是由文檔的真實(shí)點(diǎn)擊率和文檔的展示位置共同決定的,那就將這兩部分分開預(yù)測,用文檔的展示位置作為特征通過一個(gè)獨(dú)立的 shallow tower 對 Position Bias 進(jìn)行建模[3],將其他的 Query 和 Doc 本身的特征輸入主模型結(jié)構(gòu)建模文檔的真實(shí)點(diǎn)擊率,將兩部分分?jǐn)?shù)相加來預(yù)測用戶點(diǎn)擊。在線預(yù)測時(shí),只需考慮真實(shí)點(diǎn)擊率的部分。另外在訓(xùn)練的時(shí)候有兩點(diǎn)需要注意,一個(gè)是最好在 shallow tower 的部分加一些 dropout 防止模型對 Position Bias 的過度依賴,另一個(gè)是只有點(diǎn)擊目標(biāo)會(huì)受到位置偏差的影響,所以只需要在點(diǎn)擊目標(biāo)上應(yīng)用這個(gè)策略,在轉(zhuǎn)化類目標(biāo)上則無需這種處理。這一版的策略上線對點(diǎn)擊比帶來了顯著的提升。

5. Context Aware LTR

對于排序任務(wù)可以有幾種理解:
Point wise:確定每個(gè)文檔獨(dú)立打分,最終根據(jù)分?jǐn)?shù)排序
Pair wise:確定兩兩文檔對的相對順序,推導(dǎo)出最終排序
List wise:直接優(yōu)化待排序的文檔的整體順序
三種不同的方式都有對應(yīng)損失函數(shù),實(shí)踐證明,對排序任務(wù)而言 List wise loss 優(yōu)于 Pair wise loss 優(yōu)于 Point wise loss。
從特征角度我們也可以通過構(gòu)造一些 context 特征來實(shí)現(xiàn) List wise,比如對待排序文檔的特征取平均值或者中位數(shù)作為模型排序特征,實(shí)現(xiàn)起來比較簡單,當(dāng)然也是有效的。
常規(guī)的模型對不同文檔的打分是相互獨(dú)立的,我們希望可以實(shí)現(xiàn)一個(gè)模型在對單條文檔打分時(shí),同時(shí)可以考慮到其他的文檔。在實(shí)踐中我們借鑒了CV 中的 SE Block[4] 結(jié)構(gòu),具體到排序的場景就是:以全連接層輸出 X 作為 SE Block 的輸入,全連接層的輸出維度是 L*C(L代表list size,C代表特征維度),然后先在 List維度上做Pooling,然后經(jīng)過兩層的全連接層之后將輸出做Sigmoid 轉(zhuǎn)換,映射到0到1之間,再跟乘回 X。通過List wise 的 Pooling操作就可以把一整個(gè)list信息融合到每個(gè)樣本的打分里面,實(shí)現(xiàn) List wise 打分。每一層全連接層后都可以接一個(gè) SE Block 結(jié)構(gòu)。在訓(xùn)練時(shí)有一個(gè)需要注意的點(diǎn)是,由于訓(xùn)練日志只是有展現(xiàn)的一小部分文檔,但是在精排線上打分時(shí)候選集是比較大的,所以存在線上線下不一致的問題,而這種不一致對于 SE Block 的計(jì)算影響很大。為了解決這種的不一致的問題,我們在精排之后加了一個(gè)重排序階段,把精排Top16的結(jié)果送到重排序模型中。保證Top16文檔可以完整的加入到訓(xùn)練數(shù)據(jù)中,在離線訓(xùn)練時(shí)只有重排序模型應(yīng)用 SE Block 結(jié)構(gòu),這樣就保證了線上線下的一致性。這一版的策略更新對于頭部位置的點(diǎn)擊比提升比較明顯。

Se Block結(jié)構(gòu)之所以能發(fā)揮作用,本質(zhì)上是因?yàn)樵趩螚l樣本打分過程中融合了所有候選集的信息。另外有一種可能的解釋是 SE Block結(jié)構(gòu)實(shí)現(xiàn)了某種注意力機(jī)制,輸出的 0 - 1 的打分可以看做是某個(gè)特征在當(dāng)前 Query context 下的特征重要性,而同一個(gè)特征在不同 Query 下的特征重要性是一樣的,所以通過這種結(jié)構(gòu)模型可能可以學(xué)到這樣的信息,來幫助模型更好的打分。

6. End2End 學(xué)習(xí)
之前我們的排序模型并沒有直接使用 Query 和文檔的原文作為排序特征,而是將其輸入相關(guān)性模型將計(jì)算得到的相關(guān)分?jǐn)?shù)做為上層排序模型的特征,所以我們進(jìn)行了一些 End2End 學(xué)習(xí)的嘗試。
由于我們是使用 BERT 模型計(jì)算文本相關(guān)性,所以我們嘗試了將 BERT 也加入到 LTR 的模型中進(jìn)行訓(xùn)練。由于 BERT 的計(jì)算量過大,我們實(shí)際只加載的前三層的 Transformer。但是訓(xùn)練時(shí)長依然過長,且離線指標(biāo)無提升。之后我們進(jìn)行了第二次嘗試,只是將 BERT 編碼之后的 Query 和標(biāo)題的 Embedding 向量加入到 LTR 模型中,在其上加入 Dense 層進(jìn)行微調(diào),這種方式最終獲得了一定的線上收益。
7. 個(gè)性化 LTR
用戶在發(fā)生點(diǎn)擊行為之前,可能已經(jīng)產(chǎn)生了很多的行為,比如有過搜索,或者點(diǎn)擊過首頁推薦的內(nèi)容,這些交互行為都可以提供一些用戶額外的信息用于排序。我們將用戶近 30min 的搜索 Query 和點(diǎn)擊的文檔標(biāo)題用 BERT 模型生成句向量輸入到模型里,跟當(dāng)前 Query 的Embedding做內(nèi)積,計(jì)算最大匹配分?jǐn)?shù)作為特征,這樣操作雖然比較簡單,但是拿到了很好的線上收益。除此之外我們還嘗試了一些更為復(fù)雜特征交互結(jié)構(gòu),但是上線之后發(fā)現(xiàn)效果都不如這個(gè)簡單的策略好。

1. GBDT特征編碼模型

這個(gè)思路是Facebook 提出的[6],首先用點(diǎn)擊數(shù)據(jù)訓(xùn)練一個(gè) GBDT模型,利用模型進(jìn)行特征分桶和特征組合,將GBDT輸出的葉子節(jié)點(diǎn)編號(hào)作為排序模型的特征,但是這個(gè)方案沒有線上收益。
2. IRGAN,生成對抗網(wǎng)絡(luò)模型
利用生成對抗網(wǎng)絡(luò)訓(xùn)練排序任務(wù)[7],具體實(shí)現(xiàn):實(shí)現(xiàn)一個(gè)生成網(wǎng)絡(luò)一個(gè)判別網(wǎng)絡(luò),把展示未點(diǎn)擊的樣本喂給生成器,采樣出疑似的正樣本(作為判別器的負(fù)樣本)和用戶真實(shí)點(diǎn)擊的樣本一起喂給判別器。判別器的錯(cuò)誤率作為生成器的 reward。核心思想是希望通過生成器生成的難負(fù)樣本提高判別器的分類性能。但是實(shí)際訓(xùn)練時(shí)發(fā)現(xiàn)在一定步數(shù)之后模型會(huì)訓(xùn)練發(fā)散,并不能達(dá)到比較好的性能。

1. Online learning
我們之前發(fā)現(xiàn)模型在上線一段時(shí)間后指標(biāo)有逐漸下降的趨勢,之后嘗試了模型日更,結(jié)果表明日更模型表現(xiàn)較好。提高模型更新頻率可以讓模型更快的適應(yīng)新的數(shù)據(jù)分布,如果可以實(shí)時(shí)更新模型預(yù)計(jì)效果會(huì)進(jìn)一步提高。
2. Graph embedding
用戶的搜索 Query 和點(diǎn)擊的文檔可以構(gòu)建一個(gè)圖,用圖挖掘的算法有可能從其中挖掘出更多的信息,提高排序模型的性能。
3. 個(gè)性化
我們目前關(guān)于個(gè)性化的嘗試只是通過用戶的近期交互行為挖掘了一些用戶的短期興趣,利用用戶的長期興趣畫像,可以在 Query 意圖寬泛時(shí)對結(jié)果做一些個(gè)性化的排序,更好的滿足用戶的個(gè)性化需求。
4. 邊緣計(jì)算
與云計(jì)算方式不同,邊緣計(jì)算可以利用用戶更細(xì)粒度的交互信息,通過端上計(jì)算即時(shí)的對排序結(jié)果進(jìn)行調(diào)整,進(jìn)一步提升排序質(zhì)量,是一個(gè)非常有潛力的發(fā)展方向。
參考資料:
今天的分享就到這里,謝謝大家。
在文末分享、點(diǎn)贊、在看,給個(gè)3連擊唄~

王瑞欣
知乎?| 搜索算法工程師
王瑞欣,知乎搜索算法工程師,在文本相關(guān)性判斷和排序任務(wù)方面經(jīng)驗(yàn)豐富。


