【Airbnb搜索】:Applying Deep Learning To Airbnb Search

論文地址:https://arxiv.org/abs/1810.09591

這篇論文將的是airbnb搜索在深度學習方面的探索

airbnb最開始在搜索排序中使用的是gbdt,但是隨着模型的穩定,gbdt帶來的提升越來越有限。而這篇文章就是要講airbnb將深度學習技術應用到實際環境中去的實踐。論文並有沒提出什麼新的理論技術,重點放在了整個工程實現以及模型優化,迭代,各種在由傳統機器學習向深度學習遷移過程中遇到的坑,對那些想開始往深度學習進行探索的團隊來說有很多幹貨可以借鑑。中間很多在遇到問題後的思考以及深度的分析做的確實很到位,值得學習。

介紹

airbnb是房屋分享平臺,供房方提供出租的房子,供全世界的潛在客戶預定。典型的預定方式是客戶在airbnb上搜索指定地理位置的可用房源,然後搜索排序的任務就是從成千上萬的庫存中向客戶提供一個排序的可用房源。搜索排序的最快速實現方法就是使用手工的靜態分,計算出客戶提供的query和待排序的房源,具體大家可以參考下es的靜態分計算方法。當然靜態分的計算,只考慮了query和房源titile本身的信息,而且計算方式是固定的。雖然他們利用gbdt代替靜態分的計算方式,在搜索排序效果上獲得了巨大的提升。但是gbdt的迭代獲得的收益越來越低,就開始往深度學習開始探索。

搜索排序模型是整個搜索系統的重要一部分,它直接決定了向客戶展示的房源以及順序。在整個模型生態中,機器學習模型可以用來預測客戶接受預定的請求,預測客戶對旅行體驗的評價等等。而我們這裏討論的是搜索排序中最複雜的一塊,它需要根據客戶的需要,列出所有用戶可能會喜歡的房源。

                                  

作者展示了一個搜索行爲session,如上。用戶通過多次搜索,點擊查看詳情頁。一個成功的session會以客戶預定一個房源結束。而這些信息都會被記錄下來,在訓練的時候,新的模型利用這些日誌信息訓練模型。而新的模型訓練的目的就是去讓被預定的房源在整個曝光房源中僅可能的高。然後訓練好的模型再放到線上去,通過A/B測試,來檢驗新的模型比原來的模型是否更加有效。

模型演變

模型的演變是一次次迭代形成的必然結果,如下圖所示分別展示了airbnb在模型演變過程中在離線和線上分別獲得的收益。

                                                        

    1.簡單NN

    Andrej Karpathy(特斯拉人工智能和自動駕駛視覺總監)對模型結構設計的建議是:don't be a hero。 但是誰不想做出點不一樣的成績,作者開始也認爲:Why can't we be heros? 開始設計複雜的模型結構,只能花費大量的四件去優化模型,最後消耗大量的時間精力。最後作者上線的第一個網絡就是一個簡單的單隱層的32個節點的NN。網絡的輸入特徵和GBDT的特徵一樣,模型的訓練目標也保持不變:最小化L2迴歸損失,預定的商品清單爲1,沒有預定的爲0。整個流程證明NN可以應用到線上服務。

    2.Lambdarank NN

    結合NN和Lamdarank。因爲離線採用的是NDCG指標來作爲最直接的模型效果度量。Lambdarank給了我們一個最直接的方式去利用NDCG指標優化NN模型。這裏涉及到兩項對迴歸公式的改進:

    1.使用成對的數據作爲訓練樣本,如{booked listing, not-booked listing} 作爲訓練樣本,訓練過程中,最小化預定房源和非預定房源得分之間的交叉熵損失。

    2.通過交換組成訓練樣本對的兩個列表內的數據位置,根據產生的NDCG差異來衡量每對損失。這樣可以使得模型更加關注列表頂部的數據。如把預定的列表排名從2排到1 比從10排到9要重要。

文章還列出來整個loss的tensorflow計算代碼:

                                            

    3.決策樹/FM NN

在主要流量爲NN的同時,作者也同時研究來其他的模型。值得注意的是:作者發現gbdt,fm和nn三者雖然預測離線指標都差不多,但是預測出的結果差異較大,所以結合來三者的效果,將GBDT的葉子節點做embedding後和FM的預測結果作爲網絡的特徵放到NN裏面,具體如下圖所示:

                                            

     4 .深度NN

    提出了作者採用的典型網絡配置:在將類別特徵做完embedding後總共輸入195個特徵,輸入到一個包含127維的隱層,激活函數爲relu,再繼續到83維的relu層。喂到DNN裏的特徵都是房源的基礎屬性,如價格,設備,歷史訂單量等,幾乎在沒有特徵工程的情況下直接喂到網絡中,還包括了些從其他模型輸出的特徵:

  1.智能定價特徵,由專門的模型產生;

  2.當前列房源和用戶過去看的房源的相似度,利用共現embedding計算。

這些模型挖掘的數據並不直接是搜索排序中的數據,所以給DNN提供了額外的信息。

模型通過17億的樣本對進行訓練,如下圖所示,經過不斷的訓練,模型的泛化性能越來越好,訓練集和測試集的ndcg越來越接近。

                                     

失敗的模型

   1.房源ID

在airbnb中每個房源都有一個對應的id,NN是可以有機會直接使用這些房源id來作爲特徵。用法很簡單,將id直接embedding成向量,然後將該embedding學習出來就可以了。但是在aribnb的實踐中房源id的embedding幾乎都導致了過擬合。下圖是學習曲線

                                      

經過分析,作者認爲過擬合的原因在於潛在市場的獨特屬性。因爲我們如果需要學習出每個id的embedding,那麼我們就需要針對每個id都有大量的數據,這樣才能擬合出每個id合理的embedding值。所以像文本中的文字或者在線短視頻之類的,因爲可以無限重複的出現,那麼我們就可以收集大量的交互數據用來擬合向量。但是因爲airbnb的貢獻出來的item是房源,一個人預定了,其他人就不能預定了,那麼如果一個房源很受歡迎,那麼它一年也最多被預定365次,而常見的交互是更少的。這樣就造成針對該id的交互數據很少,這就導致了id值在訓練過程中極爲稀疏,從而導致了id特徵的過擬合問題。

   2.多任務學習

先分析數據,預定的量是比查看詳情頁的量要少一個數據集的;但是預定有實際環境的限制,可訪問詳情頁是沒有的。而且在詳情頁的查看時間和上架情況是成正比的。所以針對這一點,作者提出來如下的想法來結果id導致過擬合的問題。

爲了解決房源id過擬合的問題,作者打算採用多任務學習的方法來解決。利用模型來同時預測預定和長曝光的概率,同時優化兩個損失函數,一個是以預定爲正樣本的損失,還有一個是長曝光的損失,兩者共享同一個隱層。網絡結構如下: 

                                      

通過共享曝光和預定兩者的id embedding,這樣就可以是得id embedding的學習可以來自於長曝光的數據。因爲長曝光的房源數據比預定的量要多出一個數據級。同時在損失函數中,爲了保持整個模型對預定房源的關注,對預定的損失應用來更高的補償權重。每個長曝光標籤被進一步壓縮爲log(曝光時間),而模型上線的只用到了預定的概率值。

在在線測試的時候,該模型大幅增加來長曝光,但是預定情況保持不變。通過手動查看那些長曝光和預定比例過高的房源,作者提出來幾個可能的原因。可能的原因在於這些房源都是高端但是價格昂貴的房源,或者是擁有很長的描述,又或者是比較幽默比較特別的房源等。

特徵工程

典型的特徵工程包括一些計算比例,滑動窗口平均,還有一些其他的操作等等。但是很難去評價一個特徵是不是好的,以及該特徵隨着時間變化會不會隨着市場的變化而變得過時,DNN的一個吸引力就是可以做到自動的特徵選擇,只需要將特徵輸入模型,神經網絡就可以在隱層做好特徵工程以及特徵選擇。所以NN相對傳統的機器學習來說,需要的不是基於更多的特徵上的特徵工程,而是將重點放在輸入NN的數據符合某些基本的屬性,以便NN能夠自己有效的進行數學計算。

   1.特徵歸一化

神經網絡的輸入做歸一化是必須的,所以這裏作者也對他們的輸入做了歸一化,將其數值限制在{-1,1}之間,中值在0。主要的特徵歸一化方法有以下兩種:

  1.當特徵分佈類似於正態分佈的時候,可以將特徵做正常的歸一化,如下

               fea = (fea - \mu ) / \sigma

       其中fea是特徵值,\mu是特徵的均值,\sigma是標準差

  2.如果特徵分佈接近於冪律分佈,則做如下轉換

    fea = log((1+fea)/(1+median)) 

其中fea是特徵值,median是中位值

  2.特徵分佈

  除了特徵需要歸一化,將特徵數值控制在一定的範圍內之外;我們還需要特徵的分佈相對來說比較平滑,原因有如下幾點:

  1.定位異常;當處理成千上萬的特徵樣本的時候,驗證一小部分數據是否有異常是比較困難的,範圍檢查可以起到一定的作用,但是相對來說比較有限。作者發現分佈的平滑是一個定位異常的有效方法,可以和錯誤的分佈形成對比。比如一些價格的異常就會在原始的分佈圖上形成一些峯值。

  2.促進泛化;作者團隊從實踐中得出,網絡的輸出層分佈是趨向于越來越平滑的,如下三個圖

                                                      

分別是同一批樣本經過網絡的輸出,以及在網絡第二和第一層隱層中的分佈。根據這些圖,作者認爲DNN之所以泛化性能好,是因爲我們在構建一個大量特徵的模型的時候,特徵的組合空間非常的大,在訓練過程中往往只能覆蓋一小部分的特徵組合。爲了讓網絡的泛化性能更好,模型下層的分佈平滑就進一步保證來上層對那些沒見過的值的行爲進行更爲準確的預測,所以模型一層層上去就會越來越平滑,那麼反過來,如果在輸入數據的時候就盡最大努力讓輸入數據有一個平滑的分佈,那麼模型擬合起來也應該更好。

那麼怎麼來測試訓練好的模型泛化性能遠遠超出所有日誌中的樣本呢?在真實生成環境下的話,可以直接測試,但是這裏作者提出來一種可以用來離線測試的方法:縮放測試集中給定特徵的所有值,比如價格擴大2倍,4倍等。然後觀察指標NDCG的變化,可以觀察到模型的性能在這些之前沒有見過的值上面也非常的穩定。

大多數特徵在經過調試和適當的歸一化後,就可以獲得平滑的分佈。但是對於少數的特徵,就需要做專門的特徵工程,比如房源的地理位置,它是由其經緯度表示的,如圖

                              

圖a和b是經緯度原始的分佈,爲了確保分佈的平滑,作者通過計算點到地圖顯示的中心偏移來作爲優化後的經緯度特徵。

圖c和d描述的是經過偏移後的特徵分佈,圖d展示的是再經過log偏移量後的特徵分佈,圖e和f是最後平滑好的特徵的分佈,可以看見特徵明顯比之前平滑來很多。

  3.用於檢查特徵的完整性。 什麼意思呢?在某些情況下,通過查看特徵的分佈是否平滑,可以發現模型是否存在缺失的特徵。比如,作者將房源的未來可用天數作爲一個特徵,直觀感覺是高質量的房源肯定會在短時間內被賣出去。但是如下圖所示:

                                                

分佈並不是平滑的,或者說平滑但是缺失了一塊,通過分析發現,原來房源都有最短居住要求,這個時間長短不一,所以需要進一步加入這個特徵,才能更全面的描述數據。

   3.高數量的類別特徵

高數量的類別特徵就是那些取值特別多的類別特徵。所以這些特徵就需要特殊額編碼處理。作者舉例了位置編碼,通過將位置query利用hash函數映射到整數上,建立新的類別特徵,然後再把這些類別特徵映射爲embedding向量,喂到網絡中,再利用網絡訓練。

系統工程實現

整個搜索的過程如下:用戶輸入搜索的query,調用java服務進行檢索併爲房源打分排序。利用Thrift存儲產生的日誌,利用spark 處理日誌以此獲得訓練數據。模型的訓練使用的是Tensorflow,大部分代碼都是用Scala和java來完成,訓練好的模型加載到java服務中,用於檢索和排序打分,所有的組建都運行在AWS上。

Protobufs  和數據集

GBDT模型的訓練使用的訓練數據是csv格式的數據,作者使用來大量相似的流程來將數據通過feef dict的方法輸入tensorflow訓練模型。但是分析後發現,整個訓練過程大量的時間都花在瞭解析csv文件和數據的複製上面,而且CPU的使用率只有25%作用。所以最後作者改用Protobuf來產生訓練數據,速度提升來17倍,GPU利用率達到了90%。使得原本只能用幾周的數據進行訓練,現在可以擴大到幾個月的訓練數據。

重構靜態特徵

其實輸入的大量特徵都是固定不變的,比如房源的位置,房間數量,各自設備等等各自屬性,每次都要去讀取全部的特徵需要消耗大量的時間。所以爲了解決這個磁盤io的問題,作者只使用了房源id作爲類別特徵,然後把其他全部靜態的特徵打包一個不能訓練的embedding

Java NN Library 

自己創建了一個神經網絡庫

超參數優化

dropout. 第一感覺,dropout是一種正則化技術,所以使用dropout是必須的,但是隨着作者團隊不斷的嘗試,發現基本用了dropout效果就會輕微的下降,所以作者認爲dropout更接近於一種數據增強技術,用來模擬部分數據可能缺失的場景,但是在作者提出的這個場景下並沒有相關的實際場景,所以使用dropout並不能有效的提高模型的泛化性能。

Initialiazation. 全0初始化肯定不行,因爲每個節點學出來的值會都一樣,所以最後作者對網絡的權重使用了Xavier初始化,使用範圍爲{-1,1}的uniform來生成embedding。

Learning rate. 學習率他們使用的是adam的一種變體,LayAdamOptimizer,發現在使用大量的embedding後,它的訓練速度更快。

Batch Size. batch的大小對訓練速度的影響很大,但是對模型本身的影響卻很難把握,最終他們根據經驗選擇來batch 大小爲200.

特徵重要性

評估特徵重要性和模型的可解釋性是模型優化迭代的基礎。

  1.分數分解。就是根據輸出的預測值,去判斷每個節點對這個分數的貢獻。但是對於神經網絡來說,因爲層層相交,所以並不能清晰的劃分出輸入節點和輸出的貢獻。

  2.燒蝕試驗(Ablation Test)。還有一個想法就是,通過加減特徵來查看模型的性能變化,但是這也有問題,第一很費時,第二因爲模型之間存在冗餘,所以很多時候模型的結果也並不能反應特徵的重要程度。

  3.置換試驗(permutation test)。就是在測試集上,隨機的置換特徵,然後觀察測試集上模型的性能,希望的是越重要的特徵,越可能影響模型的性能。但是特徵之間是存在關聯的,其實實驗輸出的結果也沒有什麼意義。

  4.TopBot 分析。自行研發的工具,用來解釋這些特徵而不以任何形式干擾模型。它以測試集作爲輸入,使用模型對每個測試query進行排序,然後統計每個query的頂部預測數據的特徵分佈,和底部預測數據的特徵分佈進行比較。通過比較可以瞭解到模型是怎麼使用特徵的。

                                                              

通過上圖可以發現,排在top的房源的價格是要相對來說偏低的,表面價格對模型排序的影響比較大。而評論次數相對來說對模型的影響並不大,說明評論次數這個特徵對模型來說並不是很敏感。這就需要去考慮爲什麼了?是這個特徵真的不重要,還是沒有學習出來?

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