本文將分享百度在推薦排序方面的思考與實踐。在整個工業界的推廣搜場景上,特征設計通常都是采用離散化的設計,需要保證兩方面的效果,一方面是記憶,另一方面是泛化。特征都是通過哈希的方式做成 one hot 的離散化。
一、背景
首先來介紹一下百度綜合信息流推薦的業務背景、數據背景,以及基本的算法策略。
1、百度綜合信息流推薦
百度的綜合信息流包括手百 App 中搜索框的列表頁以及沉浸頁的形態,有著非常多的產品類型。從上圖中可以看到,有類似于抖音的沉浸態的推薦,也有單列的推薦,以及類似于小紅書筆記的雙列推薦。交互形態也是多種多樣的,可以在落地頁上進行評論、點贊、收藏,也可以點進作者頁中查看作者的相關信息并進行交互,當然也可以有負向的 feedback 等等。
2、數據背景
從建模的角度上看,主要面對三方面的挑戰:
- 大規模。每天的展現量級超過了百億級別,因此模型需要有天級別百億的吞吐能力。每天的 DAU 過億,這也決定了整個模型需要有高吞吐、高可擴展性的設計。對于排序模型來說,在線每秒鐘有數億次的計算,因此模型設計時不僅要考慮效果,同時也要考慮性能,需要做到很好的性能和效果的折中。用戶交互形態以及場景的多樣化,還要求模型可以預估多類型任務。
- 高要求。整個系統的響應時間要求非常高,端到端都是毫秒級的計算,超過了預定的時間,就會返回失敗。這也造成了另一個問題,就是復雜結構上線困難。
- 馬太效應強。從數據樣本角度上來看,馬太效應非常強,少量的頭部活躍用戶貢獻了大多數的分發量,頭部的熱門資源也覆蓋到了大多數的展現量。無論是用戶側還是資源側,馬太效應都是非常強的。因此,系統設計時就需要弱化馬太效應,使得推薦更加公平。
3、基本算法策略
在整個工業界的推廣搜場景上,特征設計通常都是采用離散化的設計,需要保證兩方面的效果,一方面是記憶,另一方面是泛化。特征都是通過哈希的方式做成 one hot 的離散化。對于頭部用戶需要有精細刻畫,準確記憶。而對于占比更大的稀疏長尾,則需要很好地泛化。另外,對于用戶的點擊以及消費決策序列,session 是非常重要的。
模型設計需要平衡很大的頭部,使整個數據呈現出 Beta distribution 的分布,需要平衡頭部的準確以及長尾的泛化。由于特征設計已經做了這方面的考量,模型的設計也需要同時兼顧泛化以及準確。百度整個的推薦漏斗對性能要求是非常極致的,所以要考慮到架構跟策略的聯合設計,需要考慮性能與效果的折中,另外也需要考慮平衡模型的高吞吐性以及精度。
架構的設計也要從性能和效果這兩個維度來綜合考量。一個模型算不動所有數千萬的資源庫,所以必須要做分層的設計,核心思想是分治法。當然各層之間是有關聯的,所以會做多階段的聯訓,來提升多階段漏斗之間的效率。另外,還有彈性計算法,保證在資源幾乎不變的情況下,上線非常復雜的模型。
上圖中右側的漢諾塔項目,在粗排這一層非常巧妙地實現了用戶與資源的分離建模。還有 CTR3.0 聯合訓練,實現了多層多階段的聯訓,比如精排,是整個系統中最復雜、最精致的模型,精度是相當高的,重排是在精排之上做 list wise 的建模,精排跟重排的關系是很緊密的,我們提出的基于這兩個模型聯訓的方式,取得了非常好的線上效果。
接下來,將分別從特征、算法和架構三個角度進一步展開介紹。
二、特征
1、用戶-系統交互決策過程
特征描述了用戶與系統之間的交互決策過程。
下圖中展示了用戶-資源-場景-狀態時空關系交互矩陣圖。
首先將所有信號切分為用戶、資源、場景和狀態這四個維度,因為本質上是要建模用戶與資源之間的關系。在每個維度上,可以做各種各樣的畫像數據。
用戶維度上,最基礎的年齡、性別、興趣點畫像。在此基礎上還會有一些細粒度的特征,比如相似用戶,以及用戶歷史上對不同資源類型的偏好行為等。session 特征,主要是長短期行為序列。業界有很多做序列的模型,在此不作贅述。但無論做何種類型的序列模型,都缺少不了特征層面的離散 session 特征。在百度的搜索廣告上,從 10 多年前就已經引入了這一種細粒度的序列特征,對用戶在不同的時間窗口上,對不同資源類型的點擊行為、消費行為等等都細致地刻畫了多組序列特征。
資源維度上,也會有 ID 類特征來記錄資源本身的情況,主導的是記憶。還有明文畫像特征來實現基礎的泛化能力。除了粗粒度的特征以外,也會有更為細致的資源特征,比如 Embedding 畫像特征,是基于多模態等預訓練模型產出的,更細致地建模離散 embedding 空間中資源之間的關系。還有統計畫像類的特征,描述資源各種情況下的后驗如何。以及 lookalike 特征,通過用戶來反向表征資源進而提升精度。
在場景維度上,有單列、沉浸式、雙列等不同的場景特征。
用戶在不同的狀態下,對于 feed 信息的消費也是不同的。比如刷新狀態是如何的,是從什么樣的網絡過來的,以及落地頁上的交互形態是怎樣的,都會影響到用戶未來的決策,所以也會從狀態維度來描述特征。
通過用戶、資源、狀態、場景四個維度,全面刻畫用戶與系統交互的決策過程。很多時候也會做多個維度之間的組合。
2、離散特征設計原理
接下來介紹離散特征設計原理。
優質的特征通常具有三個特點:區分度高、覆蓋率高、魯棒性強。
- 區分度高:加入特征后,后驗有著很大差異。比如加入 a 特征的樣本,后驗點擊率跟沒有命中 a 特征的后驗點擊率差距是非常大的。
- 覆蓋率高:如果加入的特征在整個樣本中的覆蓋率只有萬分之幾、十萬分之幾,那么即使特征很有區分度,但大概率也是沒有效果的。
- 魯棒性強:特征本身的分布要是相對穩定的,不能隨著時間發生非常劇烈的變化。
除了上述三個標準,還可以做單特征的 AUC 判斷。比如只用某一特征來訓練模型,看特征跟目標之間的關系。也可以去掉某特征,看少了特征之后的 AUC 變化情況。
基于上述設計原則,我們來重點討論三類重要特征:即交叉、偏置和序列特征。
- 交叉特征方面,業界有數百篇的相關工作,實踐中發現無論任何類型的隱式特征交叉都無法完全替代顯示特征交叉,也不可能把所有的交叉特征全部刪掉,只用隱式表征來做。顯示特征交叉能夠刻畫出隱式特征交叉所無法表達的相關信息。當然如果做得更深,可以用 AutoML 來進行自動搜索可能的特征組合空間。因此在實踐中,以顯式特征交叉為主,隱式特征交叉為輔的方式來做特征之間的 cross。
- 偏置類特征指的是,用戶的點擊不等于用戶滿意,因為資源的展示有各種各樣的偏置,比如最普遍的就是 position bias,展現在頭部的資源天然更容易被點擊。還有 system bias,系統優先展現出認為最優的,但不一定是真的最優,比如新發布的資源,可能會因為缺少后驗信息而處于劣勢。
對于偏置特征有一個很經典的結構,就是谷歌提出的 Wide&Deep 結構,Wide 側通常會放各種偏置的特征,線上直接可以裁剪掉,通過這種偏序排序的方式來達到無偏估計的效果。 - 最后是序列特征,是非常重要的一類用戶個性化特征。業界現在主流的都是做超長序列的建模,具體的實驗中會發現,通常長序列的存儲開銷是非常大的。前文中提到我們要達到性能與效果的折中。長序列可以通過離線預計算好,短序列可以在線實時計算,所以我們往往會結合兩種方式。通過門控網絡來決策用戶當前更偏向于短序列還是長序列的方式,來 balance 長期興趣以及短期興趣。同時需要注意,隨著序列拉長其邊際收益是遞減的。
3、推薦漏斗最優化的特征體系
整個推薦漏斗是分層設計的,每一層都做了過濾與截斷。如何在過濾截斷的分層設計中達到效率最高呢?前面也提到會做模型的聯合訓練。另外,特征設計的維度上也可以做相關的設計。這里也存在一些問題:
- 首先,為了提升漏斗通過率,召回和粗排直接擬合精排打分或者精排序,會導致馬太效應進一步加強,此時,召回/粗排模型并非用戶行為驅動學習過程,而是擬合漏斗。這不是我們希望看到的結果。正確的做法是推薦漏斗各層模型解耦合設計,而不是直接擬合下層的漏斗。
- 第二是粗排方面,理論上與召回靠得更近,本質上相當于是統一召回的出口。所以粗排這一層,可以引入更多召回的信號,例如協同推薦的人群投票信號,圖索引的路徑等等,以便粗排能夠與召回隊列聯合優化,使得進入精排的資源的召回效率能夠最優化。
- 第三是計算復用,在降低計算量的同時又能夠提升模型的魯棒性。此處要注意的是,常有級聯類的模型,第二級模型使用第一級模型的打分作為特征,這種做法的風險很大,因為模型最終的預估值是不穩定的分布,如果直接使用第一級模型的預估值當做特征,會使得下層模型有非常嚴重的耦合,造成系統的不穩定。
三、算法
接下來介紹核心算法的設計。
1、系統視角下的排序模型
首先來看推薦排序模型。一般認為,精排是推薦系統中精度最高的模型。業界有一種觀點認為粗排附屬于精排,對著精排學就可以了,但具體實踐中發現粗排并不能直接對著精排來學,可能會帶來很多問題。
從上圖可以看出,粗排與精排的定位不同。一般來說,粗排的訓練樣本與精排一樣,也是展現樣本。每次召回候選供粗排打分的結果有數萬條之多,這里面 99% 以上的資源是沒有被展現的,而模型僅使用最終展現的十幾條資源來做訓練,這就打破了獨立同分布的假設,在離線模型分布差異極大。這種情況在召回是最為嚴重的,因為召回的候選集都是數百萬、數千萬甚至數億,最終返回的結果大多數也都是沒有被展現的,粗排一樣相對也比較嚴重,因為候選集通常也在數萬級別。而精排就相對好很多,通過了召回與粗排兩層漏斗后,資源的基礎質量是有保證的,它主要做優中選優的工作。因此,精排在離線分布不一致問題不是那么嚴重,不需要過多地考慮樣本選擇偏差(SSB)的問題,同時由于候選集合小,可以做重計算,精排重點在于特征交叉,序列建模等。
但是粗排這一層,并不能直接對著精排學,也不能直接做類似于精排的重計算,因為其計算量是精排的數十倍,如果直接用精排的設計思路,線上的機器是完全不可承受的,所以粗排需要高度的技巧平衡性能與效果,它是一個輕量級模塊。粗排迭代的重點與精排不同,主要解決樣本選擇偏差,召回隊列優化等問題。由于粗排與召回關系緊密,更關注的是返回精排的數千資源的平均質量,而不是精確的排序關系。精排則是與重排關系更緊密,更關注的是單點的 AUC 精度。
因此在粗排的設計上,更多的是做樣本的選擇與生成,和泛化特征與網絡的設計。而精排的設計可以做復雜的多階交叉特征、超長序列建模等等。
2、超大規模離散 DNN 的泛化
前面介紹的是宏觀層面的,下面來看一下微觀層面。
具體到模型的訓練過程,目前業界主流的是使用超大規模的離散 DNN,泛化問題會是比較嚴重的。因為超大規模離散 DNN,通過 embedding 層,主要做的是記憶的功能。參見上圖,整個 embedding 空間是非常龐大的矩陣,通常都是千億或者萬億行,1000 列。所以模型訓練都是全分布式,數十乃至上百臺 GPU 做分布式訓練。
理論上,對于這么大的矩陣,并不會直接做暴力計算,而是采用類似矩陣分解的操作。當然這個矩陣分解和標準的 SVD 矩陣分解并不一樣,這里的矩陣分解是先學到低維的表征,通過 slot 之間的 parameter 的 share 來降低計算跟存儲量,也就是分解成兩個矩陣的 learning 的過程。首先是特征、表征矩陣,會學習特征跟低維嵌入的關系,這個嵌入很低,通常會選擇十維左右的嵌入。另外一個是嵌入和神經元矩陣,每個槽位之間的權重是共享的。通過這種方式既降低了存儲量,又能夠提升效果。
低維的嵌入學習是離線 DNN 優化泛化能力的關鍵,它等價于做稀疏矩陣分解,因此,整個模型泛化能力提升的關鍵就在于如何使得參數規模與樣本數能夠更好地匹配。
從多個方面來進行優化:
- 首先是從嵌入維度方面,因為不同特征的展現量差異是很大的,有些特征的展現量非常高,比如頭部的資源、頭部的用戶,可以使用更長的嵌入維度,這就是常見的動態嵌入維度的思想,即展現越充分嵌入維度越長。當然如果要做得更 fancy,可以用 autoML 等方式做強化學習,自動搜索最優嵌入長度。
- 第二個方面是創建閾值,由于不同資源展現量不同,因此,何時為特征創建嵌入表征也是需要考量的。
3、過擬合問題
業界通常是采用兩階段訓練抗過擬合的方式。整個模型由兩層組成,一個是很大的離散矩陣層,另一個是很小的稠密參數層。離散矩陣層是非常容易過擬合的,所以業界實踐通常都是采用 One Pass TrAIning,即 online learning,所有的數據都過一遍,并不會像學術界一樣的做 batch training。
另外,業界通常會利用時序 Validation Set 來解決稀疏層的 overfitting 問題。把整個訓練數據集按時間維度切分成很多個 Delta,T0,T1,T2,T3 不同的 Delta。每次訓練是用前幾小時訓練好的離散參數層固定住,再用下一個 Delta 的數據 f.NETune dense 網絡。也就是通過固定稀疏層、重訓其它參數的方式來緩解模型的過擬和問題。
這種做法也會帶來另外一個問題,因為訓練是切分開的,并且每次都需要固定 T0 時刻的離散參數,再用 t+1 時刻重訓 join 階段,這樣會拖累整個訓練速度,帶來擴展性方面的挑戰。所以近年來都是采用單階段訓練,即將離散表征層與稠密網絡層在一個 Delta 中同時更新。而單階段訓練也存在一個問題,因為整個模型除了 embedding 特征之外,還有很多連續值特征,這些連續值特征會統計每個離散特征的展現點擊情況,因此,可能帶來數據穿越的風險。所以在具體實踐時,第一步會先除掉統計量的特征,第二步使得稠密網絡與離散表征一起訓練,使用單階段的方式訓練。另外整個嵌入的長度,都是自動可伸縮的方式。通過這一系列方法,可以使得模型訓練提速 30% 左右。實踐表明,該方法過擬合程度很輕微,訓練跟測試的 AUC 的差距也都是 1/ 1000 或者更低的程度。
四、架構
接下來介紹架構設計上的思考和經驗。
1、系統分層設計原理
系統設計的核心原則是分治法。召回需要有多個通道,核心的目標是要提升召回率,以及召回資源的豐富程度。同時召回也要考慮探索跟利用的問題,是推薦效果的基礎保證。粗排做第一層的過濾,主要做輕量級點預估,承上啟下。精排通常是做重計算,也是做點預估,跟重排之間的關系非常緊密,通常會使用非常復雜的結構,也是業界研究的重點。重排是最后一層,重排是具體面對用戶的,決定了最終的展現序列,基于精排的結果考慮上下文然后來做復雜的序列預估,即 list wise 的排序。重排序需要考慮很多業務的約束,里面有很多規則,包括打散、LCN、退場等等,是規則與模型雙重驅動的模塊。
推薦系統各層的目標基本一致,但是各層側重不太一樣。召回和粗排側重的是泛化以及召回率,精排側重的是單點 AUC 的精度,重排側重的是整體序列最優。從數據上來看,越靠近召回粗排,越泛化,越靠近精排重排,越要求精度。越靠近召回源,性能受限越嚴重,因為候選資源越多計算量越大。粗排只需要對齊精排是一個誤區,粗排需要考慮與精排的一致性,但是并不能只對齊精排。如果粗排什么都不做,只是做對齊精排,會帶來非常嚴重的馬太效應。因為精排不是 ground truth,用戶的行為才是,需要學習好用戶行為,而不是學習精排,這是很重要的一點提示。
2、多階段模型聯合訓練
精排跟重排之間的關系是非常緊密的,早年重排是直接用精排的打分來做訓練的,一方面耦合很嚴重,另一方面直接使用精排打分來做訓練,很容易產生線上的波動。
百度鳳巢 CTR 3.0 精排跟重排聯合訓練項目,就非常巧妙地利用模型同時訓練避免打分耦合的問題。該項目將精排子網絡的隱層及內部打分,都作為重排子網絡的特征,然后,將精排與重排子網絡拆開,分別部署于各自模塊。一方面可以很好地復用中間結果,不會出現打分耦合帶來的波動問題,同時對于重排的精度又會有百分位的提升。這也是當年百度最高獎的子項目之一。
另外,注意該項目并不是 ESSM,ESSM 是 CTCVR 建模,是多目標建模,而 CTR3.0 聯合訓練主要解決打分耦合和重排模型精度的問題。
此外,要對召回和粗排做解耦合,因為新隊列加入進來,對于新隊列可能會不太公平。因此,提出了隨機掩碼的方式,即隨機 mask 掉一部分特征,使得耦合度不會那么強。
3、稀疏路由網絡
最后再來看一下部署在線上的過程。模型參數規模都是千億到萬億量級,目標也非常多,直接進行線上部署開銷是非常大的,不能只考慮效果,不考慮性能。有一種比較好的方式就是彈性計算,類似于 Sparse MOE 的思想。
粗排接入了非常多的隊列,有數十個甚至數百個隊列。這些隊列對線上的價值(LTV)是不一樣的,由流量價值層來計算不同召回隊列對線上點擊時長的價值。其核心思想是召回隊列整體的貢獻度越大,越可以享受更復雜的計算。從而使得有限的算力能夠服務于更高價值的流量。所以我們也沒有采用傳統的蒸餾的方式,而是采用類似 Sparse MOE 的思想來做彈性計算,即策略跟架構 co-design 的設計,使得不同的召回隊列能夠使用最適合的資源網絡進行計算。
五、未來計劃
眾所周知,現在已經進入 LLM 大模型時代。百度對下一代基于 LLM 大語言模型的推薦系統的探索將會從三個方面來展開。
第一方面是希望模型從基礎的預測升級到能夠做決策。比如經典的冷啟資源高效率探索,沉浸式序列推薦反饋,以及從搜索到推薦的決策鏈等等重要的問題,都可以借助大模型來進行決策。
第二方面是從判別到生成,現在整個模型都是判別式的,未來會探索生成式推薦的方式,比如自動生成推薦理由,對長尾數據基于 prompt 來做數據自動增強,以及生成式的檢索模型。
第三方面是從黑盒到白盒,傳統做推薦系統,大家常說神經網絡是煉丹術,是黑盒的,是否有可能向白盒化方向探索,也是未來的重要工作之一。比如基于因果,探究用戶行為狀態遷移背后的原因,推薦公平性方面做更好的無偏估計,以及 Multi Task machine Learning 的場景上能夠做更好的場景自適應。