wide&deep 在貝殼推薦場景的實踐

  • 2019 年 12 月 20 日
  • 筆記

本文主要向大家介紹 wide & deep 模型在貝殼推薦場景中的實踐。

"推薦" 對於我們來說並不陌生,已經滲透到了我們生活中的方方面面,比如淘寶的商品推薦,抖音的短影片推薦等。在房產O2O領域,同樣也需要推薦。無論在哪個推薦領域,推薦系統面臨的一個共同挑戰是如何同時滿足推薦結果的準確性和多樣性。準確性要求推薦的內容與用戶高度相關,推的精準;多樣性則要求推薦內容更加新穎,讓用戶具有新鮮感。設計合理的推薦策略,兼顧內容準確性和多樣性,提升線上推薦效果,一直是我們演算法同學的工作重點。本文向大家介紹wide & deep 模型的設計理念與基本原理,以及該 模型在我們的業務場景中的實踐與效果。本文分享的結構如下:

  • wide & deep 模型概述
  • wide & deep 模型在貝殼推薦場景的實踐
  • 階段總結與未來規劃

wide & deep 模型概述

wide & deep模型是Google在2016年發布的一類用於分類和回歸的模型。該模型應用到了Google Play的應用推薦中,有效的增加了Google Play的軟體安裝量。目前wide & deep模型已經開源,並且在TensorFlow上提供了高級API。下面將主要圍繞Google發布的論文《Wide & Deep Learning for Recommender Systems》來介紹 wide&deep 模型的原理和框架。

文中設計了一種融合淺層模型(wide)和深層模型(deep)進行聯合訓練的框架,綜合利用淺層模型的記憶能力和深層模型的泛化能力,實現單模型對推薦系統準確性和多樣性的兼顧。模型框架如圖 Figure 1 所示。

在wide & deep模型中包括兩部分,分別為wide模型和deep模型,其中wide部分是一個廣義線性模型, 上圖中的左側部分,deep模型是一個前饋神經網路,如上圖右側所示。wide & deep模型的思想來源是,模仿人腦有不斷記憶並且泛化的過程,將線性模型(用於記憶)和深度神經網路模型(用於泛化)相結合,汲取各自優勢,從而達到整體效果的最優。

wide & deep模型旨在使得訓練得到的模型能夠同時兼顧記憶(Memorization)與泛化(Generalization)能力:

  • Memorization:模型能夠從歷史數據中學習到高頻共現的特徵組合,發掘特徵之間的相關性,通過特徵交叉產生特徵相互作用的「記憶」,高效可解釋。但要泛化,則需要更多的特徵工程。
  • Generalization:代表模型能夠利用相關性的傳遞性去探索歷史數據中從未出現過的特徵組合,通過embedding的方法,使用低維稠密特徵輸入,可以更好的泛化訓練樣本中從未出現的交叉特徵。

我們分別來看一下wide部分和deep部分:

Wide部分 就是我們熟知的LR線性模型,這部分主要用作學習樣本中特徵的共現性,達到 「記憶」 的目的。該模型的表達式如下:

其中,y是預估值,x表示特徵向量,w為模型參數, b是偏置項。

特徵集合包括原始特徵和轉換後的特徵,其中交叉特徵在wide部分十分重要,能夠捕捉到特徵間的交互,因此通常會對稀疏的特徵進行交叉特徵轉換,定義如下:

其中是一個布爾變數,當第個特徵是第個轉換的一部分時為1,否則為0。舉個二元特徵來說,交叉特徵轉換(e.g : ),只有當和同時為1時,轉換結果才為1,否則為0。因此,通過特徵之間的交叉變換,便捕獲了二元特徵之間的相關性,為廣義線性模型增加了非線性。

Deep部分是一個前饋神經網路。該部分的輸入,通常是一些稠密的連續特徵,對於一些高維的稀疏特徵(id類等特徵),首先會轉換成低維且稠密的向量,就是大家常說的embeding vector,然後將這些特徵拼接成一個大的稠密矩陣,再喂入第一層。在訓練過程中通過優化損失函數不斷迭代更新,每個隱藏層執行下面的運算:

其中l是隱層的標號;f是激活函數,Google的論文中使用的是ReLU。

最後通過 聯合訓練 的方式將 wide 模型的輸出和 deep 模型的輸出合併到一起。這裡要重點區別聯合訓練和集成學習的差別。集成學習是多模型分別獨立訓練,最後再將結果進行融合;而聯合訓練會將wide和deep模型組合在一起,在訓練時同時優化所有參數,並且進行加權求和,根據最終的loss計算出gradient,反向傳播到Wide和Deep兩部分中,分別訓練自己的參數。也就是說,wide & deep 模型的權重更新會受到 wide 側和 deep 側對模型訓練誤差的共同影響。在論文中,wide部分是使用L1正則化的Follow-the-regularized-leader(FTRL)演算法進行優化,deep部分使用的是AdaGrad完成優化。

到此對 wide & deep 模型結構的講解就結束了,它的核心思想是結合線性模型的記憶能力和 DNN 模型的泛化能力,從而提升模型的整體性能,也因此能夠同時兼顧推薦的準確性和多樣性。

wide & deep 模型在貝殼推薦場景的實踐

我們的推薦系統中,主要分為兩大階段:召回和排序。如圖 Figure 2 所示,其中召回階段負責從數據存儲系統中篩選出與用戶相關的一些房源,排序階段負責對這些召回的房源進行精準的排序和打分。

我們將wide&deep模型應用在了貝殼首頁推薦場景下的排序階段,優化目標定義為推薦 點擊率。排序階段模型的搭建主要包括了樣本構建、特徵工程、模型離線訓練及線上化,其中樣本與特徵是整個機器學習中最重要的兩個環節,直接決定了模型效果的上限。接下來分別介紹下這幾個部分:

樣本構建

推薦排序模型的目標是預測用戶是否點擊,我們的訓練樣本取樣自用戶在首頁場景下對房源卡片的瀏覽和點擊數據。

原始樣本是一個三元組,包括userid,itemid和label。其中label的定義如下:

  • 正樣本:用戶點擊的房源。
  • 負樣本:用戶點擊最大位置以上曝光未點擊的房源;從未點擊的用戶部分曝光未點擊的房源。

label為1時,代表用戶點擊,為0時代表用戶曝光未點擊。

在首頁場景下的正負樣本比例在1:12,為了解決正負樣本的不均衡問題,我們對負樣本進行下取樣,將正負比例控制在了1:8。在離線訓練時,我們也嘗試對於商機樣本進行一定程度的加權,使得模型能夠更充分的學到這部分樣本的特徵。

此外,我們還對訓練樣本進行了清洗,去除掉 Noise樣本,這裡的Noise樣本指的是特徵值近似或相同的情況下,分別對應正負兩種樣本。在我們的業務場景下,用戶在不同時間對同一房源可能會存在不同的行為,導致採集的樣本中有正有負,而特徵只存在微小的差異,模型是很難學到微小的特徵差異對結果帶來的改變的,此類樣本送入到模型中會產生 "歧義"。因此,我們將Noise樣本進行清洗,去掉衝突,減少對模型的干擾。

特徵工程

特徵工程主要包括特徵構建,特徵分析,特徵處理,以及特徵選擇等。特徵構建也主要是圍繞用戶和房源這兩個角色構建相關的特徵。我們主要用到了以下的特徵:

  • 用戶特徵:註冊時長、上一次訪問距今時長等基礎特徵,最近3/7/15/30/90天活躍/瀏覽/關注/im數量等行為特徵,以及畫像偏好特徵和轉化率特徵。
  • 房源特徵:價格、面積、居室、樓層等基礎特徵,是否地鐵房/學區房/有電梯/近醫院等二值特徵,以及熱度值/點擊率等連續特徵。
  • 交叉特徵:將畫像偏好和房源的特徵進行交叉,主要包含這幾維度:價格、面積、居室、城區、商圈、小區、樓層級別的交叉。交叉值為用戶對房源在該維度下的偏好值。

在構建完特徵,拿到一份數據集後,需要先對數據進行EDA分析,包括查看數據的統計分布、類別概況與取值範圍等。對原始數據有了初步的認識與了解後,我們會進行特徵處理將特徵轉化為更容易被模型學習的數據形式,主要的特徵分析和處理過程如下:

缺失值與異常值處理:首先我們會進行特徵的缺失值分析,分析其缺失、異常、為0的比例,根據特徵的類型(離散/連續)與缺失的比例,進行不同方式的缺失值填充。此外,通過對樣本特徵進行EDA分析可知,有些特徵存在異常值,導致整體的數據分布出現嚴重偏差,這裡通過四分位距(IQR)對異常值進行檢測,並將異常值進行截斷。

等頻分桶處理:對於一些連續特徵,例如價格、面積等,我們對其分布進行畫圖分析。如圖 Figure 3 所示, 這裡以價格特徵為例:

通過畫圖分析可知,價格整體呈長尾分布,這就導致大部分樣本的特徵值都集中在一個小的取值範圍內,使得樣本特徵的區分度減小。因此,我們將這類連續特徵進行等頻分桶,保證樣本的分布在每個區間是均勻的,從而保證樣本之間的區分度和數值的穩定性。

此外,不同城市下的分布區間存在較大差異,如上圖中,天津的價格區間主要是分布在50-150萬,北京的價格區間主要是分布在100-350萬,如果對整體的訓練集做等頻分桶,會導致不同城市下的特徵存在偏差。針對這一問題,我們做特徵處理時,是分城市進行處理的,從而保證每個城市下的特徵都是均勻分布的。

歸一化處理:對取值較大的連續值特徵使用了最大最小歸一化方法,將特徵值都轉化為0-1之間的數值。該方法能夠使得特徵之間擁有統一的標準,提升特徵的區分度,並且將數據歸一化到0到1之間的數據,能夠加快模型的訓練速度,實驗也證明模型效果確實有顯著提升。

低頻過濾:對於離散型特徵,我們對其取值分布進行統計,圖 Figure 4 中,以居室和樓層特徵為例:

通過對居室和樓層級別進行分析可知,卧室數量大部分為兩居、三居。中樓層的房源最多,而底層和頂層的房源非常少。通過對此類特徵的統計,我們能夠清楚的看出特徵值的頻率分布情況,有些類別的取值比較低頻,存在分布不均的情況,因此我們將這部分特徵進行了低頻過濾處理,將出現頻次小於閾值的值歸為一類。

embedding:對於一些高維稀疏的id類特徵,例如小區,商圈id等,可以作為deep模型的embedding輸入,通過embeding層轉換成低維且稠密的向量。降維後的特徵具有較強的「擴展能力」,能夠探索歷史數據中從未出現過的特徵組合,增強模型的表達能力。

這裡需要注意的是,一些id類特徵維度很高,呈長尾分布,可以將這部分特徵進行低頻過濾,降維後再放入embedding中。

模型離線訓練與線上化

離線訓練 經過上述的樣本構建與特徵工程,生成了訓練集,作為wide & deep的訓練樣本。我們使用的模型結構如圖Figure 5所示,採用了三層的網路結構。

image

圖中的Hidden Layers為三個全連接層,每個layer後面連接Relu激活函數,訓練過程中,wdl是採用聯合訓練的方式,將wide和deep模型組合在一起,在訓練時同時優化所有參數,並且在訓練時進行加權求和,根據最終的loss計算出gradient,反向傳播到Wide和Deep兩部分中,分別訓練自己的參數。

模型訓練過程中,我們將數據集按照時間順序切分,採用7天的數據作為訓練集,1天的作為測試集。

在訓練期間,wide側的輸入包含了一些交叉特徵、離散特徵及部分連續特徵。deep側的輸入,主要是一些稠密的連續特徵,我們也嘗試了將城市、城區、商圈等id特徵進行embedding,但沒有取得效果上的提升,猜測是由於模型對這部分特徵沒有學到很好的表達,無法發揮出embedding的優勢,目前我們還在研究和探索好的embedding特徵,也期待能和大家一起討論。

模型調優 為了防止模型過擬合。我們加入了dropOut 與 L2正則;為了加快模型的收斂,引入了Batch Normalization(BN);並且為了保證模型訓練的穩定性和收斂性,嘗試不同的learning rate(wide側0.001,deep側0.01效果較好)和batch_size(目前設置的2048);在優化器的選擇上,我們對比了SGD、Adam、Adagrad等學習器,最終選擇了效果最好的Adagrad。實驗證明,通過參數的調整,能夠明顯的影響模型的訓練效果。

線上化 模型訓練和驗證後,需要將它進行線上化,我們採用了TensorFlow Serving伺服器。對於線上特徵和離線特徵的一致性問題,採取了redis存儲的方式,將離線特徵處理的參數存儲在redis中,並且在上線之前,我們會進行特徵一致性檢驗。為了提升模型的預測性能,我們使用多執行緒並行化的方式構造tf-serving請求,最終能在10ms左右返回120個房源的預測結果。

線上效果

我們在10月中旬上線第一版wdl排序模型,線上效果如下:

image

Figure 6 和Figure 7 分別對應線上CTR 和CVR的提升效果。第一版模型上線後,對比對照組CTR相對提升6.08%,CVR相對提升15.65%。目前我們正在探索新的特徵,以及在樣本和特徵工程上嘗試不同的方法,進行模型的二期優化,提升模型的離線auc,爭取給線上效果帶來進一步的提升。

階段總結和未來規劃

本文主要介紹了深度學習模型 wide&deep 在貝殼排序場景中的實踐,包括根據業務場景構建樣本、特徵,以及搭建模型等工作,在線上也取得了正向收益。

目前我們正在進行模型的二期優化,也在的不斷總結和嘗試。對於接下來的優化方向,主要總結為以下幾個方面:

  • 樣本精細化取樣代替隨機取樣(包括分城市、分用戶群體的取樣)。
  • 為wide側挖掘更多有區分能力的特徵,deep側加入有效的embedding特徵。
  • 引入實時特徵,確保房源和用戶特徵最新和最全。
  • 優化網路結構,提升網路學習能力。
  • 優化模型的訓練效率,加快線上模型的更新速度,提升線上效果。
  • 嘗試gAUC、MAP等評估指標,保證離線效果提升與線上效果提升的一致性。

此外,深度學習模型在推薦系統中的應用還有更多價值等待我們一起去發掘,這條演算法之路,還是十分漫長的,也希望能和大家一起討論,共同學習。

參考資料

[1] https://arxiv.org/pdf/1606.07792.pdf

[2] https://www.tensorflow.org/serving

作者介紹

  • 翟丁丁,2018年校招加入貝殼找房,主要從事推薦演算法相關工作。
  • 郭立星,先後在去哪兒網、一起作業網從事演算法相關工作,現就職於貝殼找房數據智慧中心,擔任資深演算法工程師,專註推薦演算法相關工作。