深入淺出排序學習:寫給程序員的算法系統開發實踐

引言

我們正處在一個知識爆炸的時代,伴隨着信息量的劇增和人工智能的蓬勃發展,互聯網公司越發具有強烈的個性化、智能化信息展示的需求。而信息展示個性化的典型應用主要包括搜索列表、推薦列表、廣告展示等等。

很多人不知道的是,看似簡單的個性化信息展示背後,涉及大量的數據、算法以及工程架構技術,這些足以讓大部分互聯網公司望而卻步。究其根本原因,個性化信息展示背後的技術是排序學習問題(Learning to Rank)。顯然,市面上大部分關於排序學習的文章,要麼偏算法、要麼偏工程。雖然算法方面有一些系統性的介紹文章,但往往對讀者的數學能力要求比較高,也偏學術論文,對於非算法同學來說門檻非常高。而大部分工程方面的文章也比較粗糙,基本上停留在Google的Two-Phase Scheme階段,從工程實施的角度來說,遠遠還不夠具體。

對於那些由系統開發工程師負責在線排序架構的團隊來說,本文會採用通俗的例子和類比方式來闡述算法部分,希望能夠幫助大家更好地理解和掌握排序學習的核心概念。如果是算法工程師團隊的同學,可以忽略算法部分的內容。本文的架構部分闡述了美團點評到店餐飲業務線上運行的系統,可以作爲在線排序系統架構設計的參考原型直接使用。該架構在服務治理、分層設計的理念,對於保障在線排序架構的高性能、高可用性、易維護性也具有一定的參考價值。包括很多具體環節的實施方案也可以直接進行借鑑,例如流量分桶、流量分級、特徵模型、級聯模型等等。

總之,讓開發工程師能夠理解排序學習算法方面的核心概念,併爲在線架構實施提供細顆粒度的參考架構,是本文的重要目標。

算法部分

機器學習涉及優化理論、統計學、數值計算等多個領域。這給那些希望學習機器學習核心概念的系統開發工程師帶來了很大的障礙。不過,複雜的概念背後往往蘊藏着樸素的道理。本節將嘗試採用通俗的例子和類比方式,來對機器學習和排序學習的一些核心概念進行揭祕。

機器學習

什麼是機器學習?

典型的機器學習問題,如下圖所示:

機器學習模型或算法(Model/Algorithm)會根據觀察到的特徵值(Feature)進行預測,給出預測結果或者目標(Prediction/Target)。這就像是一個函數計算過程,對於特定X值(Feature),算法模型就像是函數,最終的預測結果是Y值。不難理解,機器學習的核心問題就是如何得到預測函數。

Wikipedia的對機器學習定義如下:

“Machine learning is a subset of artificial intelligence in the field of computer science that often uses statistical techniques to give computers the ability to learn with data, without being explicitly programmed.”

機器學習的最重要本質是從數據中學習,得到預測函數。人類的思考過程以及判斷能力本質上也是一種函數處理。從數據或者經驗中學習,對於人類來說是一件再平常不過的事情了。例如人們通過觀察太陽照射物體影子的長短而發明了日晷,從而具備了計時和制定節氣的能力。古埃及人通過尼羅河水的漲落髮明瞭古埃及曆法。

又比如人們通過觀察月亮形狀的變化而發明了陰曆。


如果機器能夠像人一樣具備從數據中學習的能力,從某種意義上講,就具備了一定的“智能”。現在需要回答的兩個問題就是:

  • 到底什麼是“智能”?
  • 如何讓機器具備智能?

什麼是智能?

在回答這個問題之前,我們先看看傳統的編程模式爲什麼不能稱之爲“智能”。傳統的編程模式如下圖所示,它一般要經歷如下幾個階段:

  • 人類通過觀察數據(Data)總結經驗,轉化成知識(Knowledge)。
  • 人類將知識轉化成規則(Rule)。
  • 工程師將規則轉化成計算機程序(Program)。

在這種編程模式下,如果一個問題被規則覆蓋,那麼計算機程序就能處理。對於規則不能覆蓋的問題,只能由人類來重新思考,制定新規則來解決。所以在這裏“智能”角色主要由人類來承擔。人類負責解決新問題,所以傳統的程序本身不能稱之爲“智能”。

所以,“智能”的一個核心要素就是“舉一反三”。

如何讓機器具備智能?

在討論這個問題之前,可以先回顧一下人類是怎麼掌握“舉一反三”的能力的?基本流程如下:

  • 老師給學生一些題目,指導學生如何解題。學生努力掌握解題思路,儘可能讓自己的答案和老師給出的答案一致。
  • 學生需要通過一些考試來證明自己具備“舉一反三”的能力。如果通過了這些考試,學生將獲得畢業證書或者資格從業證書。
  • 學生變成一個從業者之後將會面臨並且處理很多之前沒有碰到過的新問題。

機器學習專家從人類的學習過程中獲得靈感,通過三個階段讓機器具備“舉一反三”的能力。這三個階段是:訓練階段(Training)、測試階段(Testing)、推導階段(Inference)。下面逐一進行介紹:

訓練階段

訓練階段如下圖所示:

  • 人類給機器學習模型一些訓練樣本(X,Y),X代表特徵,Y代表目標值。這就好比老師教學生解題,X代表題目,Y代表標準答案。
  • 機器學習模型嘗試想出一種方法解題。
  • 在訓練階段,機器學習的目標就是讓損失函數值最小。類比學生嘗試讓自己解題的答案和老師給的標準答案差別最小,思路如出一轍。

測試階段

測試階段如下圖所示:

  • 人類給訓練好的模型一批完全不同的測試樣本(X,Y)。這就好比學生拿到考試試卷。
  • 模型進行推導。這個過程就像學生正在考試答題。
  • 人類要求測試樣本的總損失函數值低於設定的最低目標值。這就像學校要求學生的考試成績必須及格一樣。

推導階段

推導階段如下圖所示:

  • 在這個階段機器學習模型只能拿到特徵值X,而沒有目標值。這就像工作中,人們只是在解決一個個的問題,但不知道正確的結果到底是什麼。
  • 在推導階段,機器學習的目標就是預測,給出目標值。

排序學習

什麼是排序學習?

Wikipedia的對排序學習的定義如下:

“Learning to rank is the application of machine learning, typically supervised, semi-supervised or reinforcement learning, in the construction of ranking models for information retrieval systems. Training data consists of lists of items with some partial order specified between items in each list. This order is typically induced by giving a numerical or ordinal score or a binary judgment (e.g. "relevant" or "not relevant") for each item. The ranking model's purpose is to rank, i.e. produce a permutation of items in new, unseen lists in a way which is "similar" to rankings in the training data in some sense.”

排序學習是機器學習在信息檢索系統裏的應用,其目標是構建一個排序模型用於對列表進行排序。排序學習的典型應用包括搜索列表、推薦列表和廣告列表等等。

列表排序的目標是對多個條目進行排序,這就意味着它的目標值是有結構的。與單值迴歸和單值分類相比,結構化目標要求解決兩個被廣泛提起的概念:

  • 列表評價指標
  • 列表訓練算法

列表評價指標

以關鍵詞搜索返回文章列表爲例,這裏先分析一下列表評價指標要解決什麼挑戰。

  • 第一個挑戰就是定義文章與關鍵詞之間的相關度,這決定了一篇文章在列表中的位置,相關度越高排序就應該越靠前。
  • 第二個挑戰是當列表中某些文章沒有排在正確的位置時候,如何給整個列表打分。舉個例子來說,假如對於某個關鍵詞,按照相關性的高低正確排序,文檔1、2、3、4、5應該依次排在前5位。現在的挑戰就是,如何評估“2,1,3,4,5”和“1,2,5,4,3”這兩個列表的優劣呢?

列表排序的評價指標體系總來的來說經歷了三個階段,分別是Precision and Recall、Discounted Cumulative Gain(DCG)和Expected Reciprocal Rank(ERR)。我們逐一進行講解。

Precision and Recall(P-R)

本評價體系通過準確率(Precision)和召回率(Recall)兩個指標來共同衡量列表的排序質量。對於一個請求關鍵詞,所有的文檔被標記爲相關和不相關兩種。

Precision的定義如下:

Recall的定義如下:

舉個列子來說,對於某個請求關鍵詞,有200篇文章實際相關。某個排序算法只認爲100篇文章是相關的,而這100篇文章裏面,真正相關的文章只有80篇。按照以上定義:

  • 準確率=80/100=0.8
  • 召回率=80/200=0.4。

Discounted Cumulative Gain(DCG)

P-R的有兩個明顯缺點:

  • 所有文章只被分爲相關和不相關兩檔,分類顯然太粗糙。
  • 沒有考慮位置因素。

DCG解決了這兩個問題。對於一個關鍵詞,所有的文檔可以分爲多個相關性級別,這裏以rel1,rel2...來表示。文章相關性對整個列表評價指標的貢獻隨着位置的增加而對數衰減,位置越靠後,衰減越嚴重。基於DCG評價指標,列表前p個文檔的評價指標定義如下:

對於排序引擎而言,不同請求的結果列表長度往往不相同。當比較不同排序引擎的綜合排序性能時,不同長度請求之間的DCG指標的可比性不高。目前在工業界常用的是Normalized DCG(nDCG),它假定能夠獲取到某個請求的前p個位置的完美排序列表,這個完美列表的分值稱爲Ideal DCG(IDCG),nDCG等於DCG與IDCG比值。所以nDCG是一個在0到1之間的值。

nDCG的定義如下:

IDCG的定義如下:

|REL|代表按照相關性排序好的最多到位置p的結果列表。

Expected Reciprocal Rank(ERR)

與DCG相比,除了考慮位置衰減和允許多種相關級別(以R1,R2,R3...來表示)以外,ERR更進了一步,還考慮了排在文檔之前所有文檔的相關性。舉個例子來說,文檔A非常相關,排在第5位。如果排在前面的4個文檔相關度都不高,那麼文檔A對列表的貢獻就很大。反過來,如果前面4個文檔相關度很大,已經完全解決了用戶的搜索需求,用戶根本就不會點擊第5個位置的文檔,那麼文檔A對列表的貢獻就不大。

ERR的定義如下:

列表訓練算法

做列表排序的工程師們經常聽到諸如Pointwise、Pairwise和Listwise的概念。這些是什麼東西呢,背後的原理又是什麼呢?這裏將逐一解密。

仍然以關鍵詞搜索文章爲例,排序學習算法的目標是爲給定的關鍵詞對文章列表進行排序。做爲類比,假定有一個學者想要對各科學生排名進行預測。各種角色的對應關係如下:

首先我們要告訴學者每個學生的各種屬性,這就像我們要告訴排序算法文檔特徵。對於目標值,我們卻有三種方式來告訴學者:

  • 對於每個學科,我們可以告訴學者每個學生的成績。比較每個學生的成績,學者當然可以算出每個學生的最終排名。這種訓練方法被稱爲Pointwise。對於Pointwise算法,如果最終預測目標是一個實數值,就是一個迴歸問題。如果目標是概率預測,這就是一個分類問題,例如CTR預估。
  • 對於每個學科,我們可以告訴學者任意兩個學生的相互排名。根據學生之間排名的情況,學者也可以算出每個學生的最終排名。這種訓練方法被稱爲Pairwise。Pairwise算法的目標是減少逆序的數量,所以是個二分類問題。
  • 對於每個學科,我們可以直接告訴學者所有學生的整體排名。這種訓練方法被稱爲Listwise。Listwise算法的目標往往是直接優化nDCG、ERR等評價指標。

這三種方法表面看上去有點像玩文字遊戲,但是背後卻是工程師和科學家們不斷探索的結果。最直觀的方案是Pointwise算法,例如對於廣告CTR預估,在訓練階段需要標註某個文檔的點擊概率,這相對來說容易。Pairwise算法一個重要分支是Lambda系列,包括LambdaRank、LambdaMart等,它的核心思想是:很多時候我們很難直接計算損失函數的值,但卻很容易計算損失函數梯度(Gradient)。這意味着我們很難計算整個列表的nDCG和ERR等指標,但卻很容易知道某個文檔應該排的更靠前還是靠後。Listwise算法往往效果最好,但是如何爲每個請求對所有文檔進行標註是一個巨大的挑戰。

在線排序架構

典型的信息檢索包含兩個階段:索引階段和查詢階段。這兩個階段的流程以及相互關係可以用下圖來表示:

索引階段的工作是由索引器(Indexer)讀取文檔(Documents)構建索引(Index)。

查詢階段讀取索引做爲召回,然後交給Topn Retriever進行粗排,在粗排後的結果裏面將前n個文檔傳給Reranker進行精排。這樣一個召回、粗排、精排的架構最初是由Google提出來的,也被稱爲“Two-Phase Scheme”。

索引部分屬於離線階段,這裏重點講述在線排序階段,即查詢階段。

三大挑戰

在線排序架構主要面臨三方面的挑戰:特徵、模型和召回。

  • 特徵挑戰包括特徵添加、特徵算子、特徵歸一化、特徵離散化、特徵獲取、特徵服務治理等。
  • 模型挑戰包括基礎模型完備性、級聯模型、複合目標、A/B實驗支持、模型熱加載等。
  • 召回挑戰包括關鍵詞召回、LBS召回、推薦召回、粗排召回等。

三大挑戰內部包含了非常多更細粒度的挑戰,孤立地解決每個挑戰顯然不是好思路。在線排序作爲一個被廣泛使用的架構值得采用領域模型進行統一解決。Domain-driven design(DDD)的三個原則分別是:領域聚焦、邊界清晰、持續集成。

基於以上分析,我們構建了三個在線排序領域模型:召回治理、特徵服務治理和在線排序分層模型。

召回治理

經典的Two-Phase Scheme架構如下圖所示,查詢階段應該包含:召回、粗排和精排。但從領域架構設計的角度來講,粗排對於精排而言也是一種召回。和基於傳統的文本搜索不同,美團點評這樣的O2O公司需要考慮地理位置和距離等因素,所以基於LBS的召回也是一種召回。與搜索不同,推薦召回往往基於協同過濾來完成的,例如User-Based CF和Item-Based CF。

綜上所述,召回總體而言分成四大類:

  • 關鍵詞召回,我們採用Elasticsearch解決方案。
  • 距離召回,我們採用K-D tree的解決方案。
  • 粗排召回。
  • 推薦類召回。

特徵服務治理

傳統的視角認爲特徵服務應該分爲用戶特徵(User)、查詢特徵(Query)和文檔特徵(Doc),如下圖:

這是比較純粹的業務視角,並不滿足DDD的領域架構設計思路。由於特徵數量巨大,我們沒有辦法爲每個特徵設計一套方案,但是我們可以把特徵進行歸類,爲幾類特徵分別設計解決方案。每類技術方案需要統一考慮性能、可用性、存儲等因素。從領域視角,特徵服務包含四大類:

  • 列表類特徵。一次請求要求返回實體列表特徵,即多個實體,每個實體多個特徵。這種特徵建議採用內存列表服務,一次性返回所有請求實體的所有特徵。避免多次請求,從而導致數量暴增,造成系統雪崩。
  • 實體特徵。一次請求返回單實體的多個特徵。建議採用Redis、Tair等支持多級的Key-Value服務中間鍵提供服務。
  • 上下文特徵。包括召回靜態分、城市、Query特徵等。這些特徵直接放在請求內存裏面。
  • 相似性特徵。有些特徵是通過計算個體和列表、列表和列表的相似度而得到的。建議提供單獨的內存計算服務,避免這類特徵的計算影響在線排序性能。本質上這是一種計算轉移的設計。

在線排序分層模型

如下圖所示,典型的排序流程包含六個步驟:場景分發(Scene Dispatch)、流量分配(Traffic Distribution)、召回(Recall)、特徵抽取(Feature Retrieval)、預測(Prediction)、排序(Ranking)等等。

按照DDD的設計原則,我們設計瞭如下在線排序分層模型,包括:場景分發(Scene Dispatch)、模型分發(Model Distribution)、排序(Ranking)、特徵管道(Feature Pipeline)、預測管道(Prediction Pipeline)。我們將逐一進行介紹。

場景分發(Scene Dispatch)

場景分發一般是指業務類型的分發。對於美團點評而言包括:分平臺、分列表、分使用場景等。如下圖所示:

模型分發(Model Distribution)

模型分發的目標是把在線流量分配給不同的實驗模型,具體而言要實現三個功能:

  • 爲模型迭代提供在線流量,負責線上效果收集、驗證等。
  • A/B測試,確保不同模型之間流量的穩定、獨立和互斥、確保效果歸屬唯一。
  • 確保與其他層的實驗流量的正交性。

流量的定義是模型分發的一個基礎問題。典型的流量包括:訪問、用戶和設備。

如何讓一個流量穩定地映射到特定模型上面,流量之間是否有級別?這些是模型分發需要重點解決的問題。

流量分桶原理

採用如下步驟將流量分配到具體模型上面去:

  • 把所有流量分成N個桶。
  • 每個具體的流量Hash到某個桶裏面去。
  • 給每個模型一定的配額,也就是每個策略模型佔據對應比例的流量桶。
  • 所有策略模型流量配額總和爲100%。
  • 當流量和模型落到同一個桶的時候,該模型擁有該流量。

舉個例子來說,如上圖所示,所有流量分爲32個桶,A、B、C三個模型分別擁有37.5%、25%和37.5%的配額。對應的,A、B、C應該佔據12、8和12個桶。

爲了確保模型和流量的正交性,模型和流量的Hash Key採用不同的前綴。

流量分級

每個團隊的模型分級策略並不相同,這裏只給出一個建議模型流量分級:

  • 基線流量。本流量用於與其他流量進行對比,以確定新模型的效果是否高於基準線,低於基準線的模型要快速下線。另外,主力流量相對基線流量的效果提升也是衡量算法團隊貢獻的重要指標。
  • 實驗流量。該流量主要用於新實驗模型。該流量大小設計要注意兩點:第一不能太大而傷害線上效果;第二不能太小,流量太小會導致方差太大,不利於做正確的效果判斷。
  • 潛力流量。如果實驗流量在一定週期內效果比較好,可以升級到潛力流量。潛力流量主要是要解決實驗流量方差大帶來的問題。
  • 主力流量。主力流量只有一個,即穩定運行效果最好的流量。如果某個潛力流量長期好於其他潛力流量和主力流量,就可以考慮把這個潛力流量升級爲主力流量。

做實驗的過程中,需要避免新實驗流量對老模型流量的衝擊。流量羣體對於新模型會有一定的適應期,而適應期相對於穩定期的效果一般會差一點。如果因爲新實驗的上線而導致整個流量羣體的模型都更改了,從統計學的角度講,模型之間的對比關係沒有變化。但這可能會影響整個大盤的效果,成本很高。

爲了解決這個問題,我們的流量分桶模型優先爲模型列表前面的模型分配流量,實驗模型儘量放在列表尾端。這樣實驗模型的頻繁上下線不影響主力和潛力流量的用戶羣體。當然當發生模型流量升級的時候,很多流量用戶的服務模型都會更改。這種情況並不是問題,因爲一方面我們在嘗試讓更多用戶使用更好的模型,另一方面固定讓一部分用戶長期使用實驗流量也是不公平的事情。

排序(Ranking)

排序模塊是特徵模塊和預測模塊的容器,它的主要職責如下:

  • 獲取所有列表實體進行預測所需特徵。
  • 將特徵交給預測模塊進行預測。
  • 對所有列表實體按照預測值進行排序。

特徵管道(Feature Pipeline)

特徵管道包含特徵模型(Feature Model)、表達式(Expression)、原子特徵(Atomic Feature)、 特徵服務代理(Feature Proxy)、特徵服務(Feature Service)。如下圖所示:

特徵管道要解決兩個核心問題:

  • 給定特徵名獲取對應特徵值。這個過程很複雜,要完成特徵名->特徵服務->特徵類->特徵值的轉化過程。
  • 特徵算子問題。模型使用的特徵往往是對多個原子特徵進行復合運算後的結果。另外,特徵離散化、歸一化也是特徵算子需要解決的問題。

完整的特徵獲取流程如下圖所示,具體的流程如下:

  • Ranking模塊從FeatureModel裏面讀取所有的原始特徵名。
  • Ranking將所有的原始特徵名交給Feature Proxy。
  • Feature Proxy根據特徵名的標識去調用對應的Feature Service,並將原始特徵值返回給Ranking模塊。
  • Ranking模塊通過Expression將原始特徵轉化成複合特徵。
  • Ranking模塊將所有特徵交給級聯模型做進一步的轉換。

特徵模型(Feature Model)

我們把所有與特徵獲取和特徵算子的相關信息都放在一個類裏面,這個類就是FeatureModel,定義如下:

    //包含特徵獲取和特徵算子計算所需的meta信息 
    public class FeatureModel {   
        //這是真正用在Prediction裏面的特徵名 
        private String featureName;  
        //通過表達式將多種原子特徵組合成複合特徵。
        private IExpression expression; 
        //這些特徵名是真正交給特徵服務代理(Feature Proxy)去從服務端獲取特徵值的特徵名集合。
        private Set<String> originalFeatureNames;
        //用於指示特徵是否需要被級聯模型轉換  
        private boolean isTransformedFeature; 
        //是否爲one-hot特徵    
        private boolean isOneHotIdFeature;
        //不同one-hot特徵之間往往共享相同的原始特徵,這個變量>用於標識原始特徵名。 
        private String oneHotIdKey; 
        //表明本特徵是否需要歸一化
        private boolean isNormalized; 
    }

表達式(Expression)

表達式的目的是爲了將多種原始特徵轉換成一個新特徵,或者對單個原始特徵進行運算符轉換。我們採用前綴法表達式(Polish Notation)來表示特徵算子運算。例如表達式(5-6)*7的前綴表達式爲* - 5 6 7。

複合特徵需要指定如下分隔符:

  • 複合特徵前綴。區別於其他類型特徵,我們以“$”表示該特徵爲複合特徵。
  • 表達式各元素之間的分隔符,採用“_”來標識。
  • 用“O”表示運算符前綴。
  • 用“C”表示常數前綴。
  • 用“V”表示變量前綴。

例如:表達式v1 + 14.2 + (2*(v2+v3)) 將被表示爲 $O+_O+_Vv1_C14.2_O*_C2_O+_Vv2_Vv3

原子特徵(Atomic Feature)

原子特徵(或者說原始特徵)包含特徵名和特徵值兩個部分。原子特徵的讀取需要由4種實體類共同完成:

  • POJO用於存儲特徵原始值。例如DealInfo保存了所有與Deal實體相關的特徵值,包括Price、maxMealPerson、minMealPerson等等。
  • ScoringValue用於存儲從POJO中返回的特徵值。特徵值包含三種基本類型,即數量型(Quantity)、序數型(Ordinal)、類別型(Categorical)。
  • ScoreEnum實現特徵名到特徵值的映射。每類原子特徵對應於一個ScoreEnum類,特徵名通過反射(Reflection)的方式來構建對應的ScoreEnum類。ScoreEnum類和POJO一起共同實現特徵值的讀取。
  • FeatureScoreEnumContainer用於保存一個算法模型所需所有特徵的ScoreEnum。

一個典型的例子如下圖所示:

  • DealInfo是POJO類。
  • DealInfoScoreEnum是一個ScoreEnum基類。對應於平均用餐人數特徵、價格等特徵,我們定義了DIAveMealPerson和DIPrice的具體ScoreEnum類。
  • FeatureScoreEnumContainer用於存儲某個模型的所有特徵的ScoreEnum。

複雜系統設計需要充分的利用語言特性和設計模式。建議的優化點有三個:

  • 爲每個原子特徵定義一個ScoreEnum類會導致類數量暴增。優化方式是ScoreEnum基類定義爲Enum類型,每個具體特徵類爲一個枚舉值,枚舉值繼承並實現枚舉類的方法。
  • FeatureScoreEnumContainer採用Build設計模式將一個算法模型的所需特徵轉換成ScoreEnum集合。
  • ScoreEnum從POJO類中讀取具體特徵值採用的是Command模式。

這裏稍微介紹一下Command設計模式。Command模式的核心思想是需求方只要求拿到相關信息,不關心誰提供以及怎麼提供。具體的提供方接受需求方的需求,負責將結果交給需求方。

在特徵讀取裏面,需求方是模型,模型僅僅提供一個特徵名(FeatureName),不關心怎麼讀取對應的特徵值。具體的ScoreEnum類是具體的提供方,具體的ScoreEnum從POJO裏面讀取特定的特徵值,並轉換成ScoringValue交給模型。

特徵服務代理(Feature Proxy)

特徵服務代理負責遠程特徵獲取實施,具體的過程包括:

  • 每一大類特徵或者一種特徵服務有一個FeatureProxy,具體的FeatureProxy負責向特徵服務發起請求並獲取POJO類。
  • 所有的FeatureProxy註冊到FeatureServiceContainer類。
  • 在具體的一次特徵獲取中,FeatureServiceContainer根據FeatureName的前綴負責將特徵獲取分配到不同的FeatureProxy類裏面。
  • FeatureProxy根據指定的實體ID列表和特徵名從特徵服務中讀取POJO列表。只有對應ID的指定特徵名(keys)的特徵值纔會被賦值給POJO。這就最大限度地降低了網絡讀取的成本。

預測管道(Prediction Pipeline)

預測管道包含:預測(Prediction)、級聯模型(Cascade Model)、表達式(Expression)、特徵轉換(Transform)、計分(Scoring)和原子模型(Atomic Model)。

預測(Prediction)

預測本質上是對模型的封裝。它負責將每個列表實體的特徵轉化成模型需要的輸入格式,讓模型進行預測。

級聯模型(Cascade Model)

我們構建級聯模型主要是基於兩方面的觀察:

  • 基於Facebook的《Practical Lessons from Predicting Clicks on Ads at Facebook》的Xgboost+LR以及最近很熱門的Wide&Deep表明,對一些特徵,特別是ID類特徵通過樹模型或者NN模型進行轉化,把轉化後的值做爲特徵值交給預測模型進行預測,往往會能實現更好的效果。
  • 有些訓練目標是複合目標,每個子目標需要通過不同的模型進行預測。這些子目標之間通過一個簡單的表達式計算出最終的預測結果。

舉例如下圖所示,我們自上而下進行講解:

  • 該模型有UserId、CityId、UserFeature、POI等特徵。
  • UserId和CityId特徵分別通過GBDT和NN模型進行轉換(Transform)。
  • 轉換後的特徵和UserFeature、POI等原始特徵一起交給NN和LR模型進行算分(Scoring)。
  • 最終的預測分值通過表達式Prediction Score = αNNScore + βLRScore/(1+γ)來完成。表達式中的 α 、β和γ是事先設置好的值。

原子模型(Atomic Model)

在這裏原子模型指的是一種原子計算拓撲結構,比如線性模型、樹模型和網絡模型。

常用的模型像Logistic Regression和Linear Regression都是線性模型。GBDT、Random Forest都是樹模型。MLP、CNN、RNN都是網絡模型。

這裏定義的原子模型主要的目的是爲了工程實施的便利。一個模型被認定爲原子模型有如下兩個原因:

  • 該模型經常做爲獨立預測模型被使用。
  • 該模型有比較完整的實現代碼。

總結

本文總結了作者在美團點評解決到店餐飲個性化信息展示的相關經驗,從算法和架構兩方面進行闡述。在算法部分,文章採用通俗的例子和類比方式進行講解,希望非算法工程師能夠理解關鍵的算法概念。架構部分比較詳細地闡述了到店餐飲的排序架構。

根據我們所掌握的知識,特徵治理和召回治理的思路是一種全新的視角,這對於架構排序系統設計有很大的幫助。這種思考方式同樣也適用於其他領域模型的構建。與Google提供的經典Two-Phase Scheme架構相比,在線排序分層模型提供了更細顆粒度的抽象原型。該原型細緻的闡述了包括分流、A/B測試、特徵獲取、特徵算子、級聯模型等一系列經典排序架構問題。同時該原型模型由於採用了分層和層內功能聚焦的思路,所以它比較完美地體現了DDD的三大設計原則,即領域聚焦、邊界清晰、持續集成。

作者簡介

劉丁,曾就職於Amazon、TripAdvisor。2014年加入美團,先後負責美團推薦系統、智能篩選系統架構、美團廣告系統的架構和上線、完成美團廣告運營平臺的搭建。目前負責到店餐飲算法策略方向,推進AI在到店餐飲各領域的應用。

參考文章:

[1]Gamma E, Helm R, Johnson R, et al. Design Patterns-Elements of Reusable Object-Oriented Software. Machinery Industry, 2003.

[2]Wikipedia,Learning to rank.

[3]Wikipedia,Machine learning.

[4]Wikipedia,Precision and recall.

[5]Wikipedia,Discounted cumulative gain.

[6]Wikipedia,Domain-driven design.

[7]Wikipedia,Elasticsearch.

[8]Wikipedia,k-d tree.

[9]百度百科,太陽曆.

[10]百度百科,陰曆.

[11]Xinran H, Junfeng P, Ou J, et al. Practical Lessons from Predicting Clicks on Ads at Facebook

[12]Olivier C, Donald M, Ya Z, Pierre G. Expected Reciprocal Rank for Graded Relevance

[13]Heng-Tze C, Levent K, et al. Wide & Deep Learning for Recommender Systems

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章