深度學習在推薦領域的應用
作者: 吳岸城,菱歌科技首席演算法科學家,致力於深度學習在文字、影象、預測推薦領域的應用。曾在中興通訊、亞信(中國)擔任研發經理、高階技術經理等職務。
責編:何永燦,歡迎人工智慧領域技術投稿、約稿、給文章糾錯,請傳送郵件至heyc#csdn.net(#改為@)
本文為《程式設計師》原創文章,未經允許不得轉載,更多精彩文章請訂閱《程式設計師》
當2012年Facebook在廣告領域開始應用定製化受眾(Facebook Custom Audiences)功能後,“受眾發現”這個概念真正得到大規模應用,什麼叫“受眾發現”?如果你的企業已經積累了一定的客戶,無論這些客戶是否關注你或者是否跟你在Facebook上有互動,都能通過Facebook的廣告系統觸達到。“受眾發現”實現了什麼功能?在沒有這個系統之前,廣告投放一般情況都是用標籤去區分使用者,再去給這部分使用者傳送廣告,“受眾發現”讓你不用選擇這些標籤,包括使用者基本資訊、興趣等。你需要做的只是上傳一批你目前已有的使用者或者你感興趣的一批使用者,剩下的工作就等著Custom Audiences幫你完成了。
Facebook這種通過一群已有的使用者發現並擴展出其他使用者的推薦演算法就叫Lookalike,當然Facebook的演算法細節筆者並不清楚,各個公司實現Lookalike也各有不同。這裡也包括騰訊在微信端的廣告推薦上的應用、Google在YouTube上推薦感興趣視訊等。下面讓我們結合前人的工作,實現自己的Lookalike演算法,並嘗試著在新浪微博上應用這一演算法。
調研
首先要確定微博領域的資料,關於微博的資料可以這樣分類:
- 使用者基礎資料:年齡、性別、公司、郵箱、地點、公司等。
- 關係圖:根據人↔人,人↔微博的關注、評論、轉發資訊建立關係圖。
- 內容資料:使用者的微博內容,包含文字、圖片、視訊。
有了這些資料後,怎麼做資料的整合分析?來看看現在應用最廣的方式——協同過濾、或者叫關聯推薦。協同過濾主要是利用某興趣相投、擁有共同經驗群體的喜好來推薦使用者可能感興趣的資訊,協同過濾的發展有以下三個階段:
第一階段,基於使用者喜好做推薦,使用者A和使用者B相似,使用者B購買了物品a、b、c,使用者A只購買了物品a,那就將物品b、c推薦給使用者A。這就是基於使用者的協同過濾,其重點是如何找到相似的使用者。因為只有準確的找到相似的使用者才能給出正確的推薦。而找到相似使用者的方法,一般是根據使用者的基本屬性貼標籤分類,再高階點可以用上使用者的行為資料。
第二階段,某些商品光從使用者的屬性標籤找不到聯絡,而根據商品本身的內容聯絡倒是能發現很多有趣的推薦目標,它在某些場景中比基於相似使用者的推薦原則更加有效。
第三階段,如果只把內容推薦單獨應用在社交網路上,準確率會比較低,因為社交網路的關鍵特性還是社交關係。如何將社交關係與使用者屬性一起融入整個推薦系統就是關鍵。在神經網路和深度學習演算法出現後,提取特徵任務就變得可以依靠機器完成,人們只要把相應的資料準備好就可以了,其他資料都可以提取成向量形式,而社交關係作為一種圖結構,如何表示為深度學習可以接受的向量形式,而且這種結構還需要有效還原原結構中位置資訊?這就需要一種可靠的向量化社交關係的表示方法。基於這一思路,在2016年的論文中出現了一個演算法node2vec,使社交關係也可以很好地適應神經網路。這意味著深度學習在推薦領域應用的關鍵技術點已被解決。
在實現演算法前我們主要參考瞭如下三篇論文:
第一篇論文是LinkedIn給出的,主要談了針對線上社交網路廣告平臺,如何根據已有的受眾特徵做受眾群擴充套件。這涉及到如何定位目標受眾和原始受眾的相似屬性。論文給出了兩種方法來擴充套件受眾:
- 與營銷活動無關的受眾擴充套件;
- 與營銷活動有關的受眾擴充套件。
在圖1中,LinkedIn給出瞭如何利用營銷活動資料、目標受眾基礎資料去預測目標使用者行為進而發現新的使用者。今天的推薦系統或廣告系統越來越多地利用了多維度資訊。如何將這些資訊有效加以利用,這篇論文給出了一條路徑,而且在工程上這篇論文也論證得比較紮實,值得參考。
第二篇論文,主要講的是node2vec,這也是本文用到的主要演算法之一。node2vec主要用於處理網路結構中的多分類和鏈路預測任務,具體來說是對網路中的節點和邊的特徵向量表示方法。
簡單來說就是將原有社交網路中的圖結構,表達成特徵向量矩陣,每一個node(可以是人、物品、內容等)表示成一個特徵向量,用向量與向量之間的矩陣運算來得到相互的關係。
下面來看看node2vec中的關鍵技術——隨機遊走演算法,它定義了一種新的遍歷網路中某個節點的鄰域的方法,具體策略如圖2所示。
假設我們剛剛從節點t走到節點v,當前處於節點v,現在要選擇下一步該怎麼走,方案如下:
其中dtx表示節點t到節點x之間的最短路徑,dtx=0表示會回到節點t本身,dtx=1表示節點t和節點x直接相連,但是在上一步卻選擇了節點v,dtx=2表示節點t不與x直接相連,但節點v與x直接相連。其中p和q為模型中的引數,形成一個不均勻的概率分佈,最終得到隨機遊走的路徑。與傳統的圖結構搜尋方法(如BFS和DFS)相比,這裡提出的隨機遊走演算法具有更高的效率,因為本質上相當於對當前節點的鄰域節點的取樣,同時保留了該節點在網路中的位置資訊。
node2vec由斯坦福大學提出,並有開原始碼,這裡順手列出,這一部分大家不用自己動手實現了。https://github.com/aditya-grover/node2vec
注:本文的方法需要在原始碼的基礎上改動圖結構。
第三篇論文講的是Google如何做YouTube視訊推薦,論文是在我做完結構設計和流程設計後看到的,其中模型架構的思想和我們不謀而合,還解釋了為什麼要引入DNN(後面提到所有的feature將會合並經歷幾層全連線層):引入DNN的好處在於大多數型別的連續特徵和離散特徵可以直接新增到模型當中。此外我們還參考了這篇論文對於隱含層(FC)單元個數選擇。圖3是這篇論文提到的演算法結構。
實現
-
(a)資料準備
- 獲得使用者的屬性(User Profile),如性別、年齡、學歷、職業、地域、能力標籤等;
- 根據專案內容和活動內容制定一套受眾標籤(Audience Label);
- 提取使用者之間的關注關係,微博之間的轉發關係;
- 獲取微博message中的文字內容;
- 獲得微博message中的圖片內容。
-
(b)使用者標籤特徵處理
- 根據步驟a中使用者屬性資訊和已有的部分受眾標籤系統。利用GBDT演算法(可以直接用xgboost)將沒有標籤的受眾全部打上標籤。這個分類問題中請注意處理連續值變數以及歸一化。
- 將標籤進行向量化處理,這個問題轉化成對中文單詞進行向量化,這裡用word2vec處理後得到使用者標籤的向量化資訊Label2vec。這一步也可以使用word2vec在中文的大資料樣本下進行預訓練,再用該模型對標籤加以提取,對特徵的提取有一定的提高,大約在0.5%左右。
-
(c)文字特徵處理
將步驟a中提取到的所有微博message文字內容清洗整理,訓練Doc2Vec模型,得到單
個文字的向量化表示,對所得的文字作聚類(KMeans,在30w的微博使用者的message上測試,K取128對文字的區分度較強),最後提取每個cluster的中心向量,並根據每個使用者所佔有的cluster獲得使用者所發微博的文字資訊的向量表示Content2vec。 -
(d)影象特徵(可選)
將步驟a中提取到的所有的message圖片資訊整理分類,使用預訓練卷積網路模型(這裡為了平衡效率選取VGG16作為卷積網路)提取影象資訊,對每個使用者message中的圖片做向量化處理,形成Image2vec,如果有多張圖片將多張圖片分別提取特徵值再接一層MaxPooling提取重要資訊後輸出。 -
(e)社交關係建立(node2vec向量化)
將步驟a中獲得到的使用者之間的關係和微博之間的轉發評論關係轉化成圖結構,並提取使用者關係sub-graph,最後使用node2Vec演算法得到每個使用者的社交網路圖向量化表示。
圖4為簡歷社交關係後的部分圖示。圖4 使用者社交關係 -
(f)將bcde步驟得到的向量做拼接,經過兩層FC,得到表示每個使用者的多特徵向量集(User Vector Set, UVS)。這裡取的輸出單元個數時可以根據效能和準確度做平衡,目前我們實現的是輸出512個單元,最後的特徵輸出表達了使用者的社交關係、使用者屬性、發出的內容、感興趣的內容等的混合特徵向量,這些特徵向量將作為下一步比對相似性的輸入值。
-
(g)分別計算種子使用者和潛在目標使用者的向量集,並比對相似性,我們使用的是餘弦相似度計算相似性,將步驟f得到的使用者特徵向量集作為輸入x,y,代入下面公式計算相似性:
使用餘弦相似度要注意:餘弦相似度更多的是從方向上區分差異,而對絕對的數值不敏感。因此沒法衡量每個維度值的差異,這裡我們要在每個維度上減去一個均值或者乘以一個係數,或者在之前做好歸一化。 -
(h)受眾擴充套件
- 獲取種子受眾名單,以及目標受眾的數量N;
- 檢查種子使用者是否存在於UVS中,將存在的使用者向量化;
- 計算受眾名單中使用者和UVS中使用者的相似度,提取最相似的前N個使用者作為目標受眾。
最後我們將以上步驟串聯起來,形成如圖5所示。
在以上步驟中特徵提取完成後,我們使用一個2層的神經網路做最後的特徵提取,演算法結構示意圖如圖6所示。
其中FC1層也可以替換成MaxPooling,MaxPooling層具有強解釋性,也就是在使用者特徵群上提取最重要的特徵點作為下一層的輸入,讀者可以自行嘗試,這裡限於篇幅問題就不做展開了。
講到這裡,演算法部分就已基本完結,其中還有些工程問題,並不屬於本次主題探討範圍,這裡也不做討論了。
結果
我司演算法團隊根據Lookalike思想完整實現其演算法,並在實際產品中投入試用。針對某客戶(乳品領域世界排名前三的品牌主)計算出結果(部分):
可以觀察到以上微博ID的主題基本都是西點企業或西點培訓企業,和品牌主售賣的乳品有很高的關聯性:乳品是非常重要的西點原料,除終端使用者外,西點相關企業就是乳品企業主需要尋找的最重要的受眾之一。
探討
特徵表達
除了以上提到的特徵外,我們也對其他的重要特徵表達做了處理和變換:根據我們的需求,需要抽取出人的興趣特徵,如何表達一個人的興趣?除了他自己生成的有關內容外,還有比較關鍵的一點是比如“我”看了一些微博,但並沒有轉發,大多數情況下都不會轉發,但有些“我”轉發了,有些“我”評論了;“我”轉發了哪些?評論了哪些?這次距上次的瀏覽該人的列表時間間隔多久?都代表“我”對微博的興趣,而間接的反應“我”的興趣特徵。這些資料看來非常重要,又無法直接取得,怎麼辦?
下面來定義一個場景,試圖描述出我們對看過的內容中哪些是感興趣的,哪些不是感興趣的:
- (a)使用者A,以及使用者A關注的使用者B;
- (b)使用者A的每天動作時間(比如他轉發、評論、收藏、點贊)起始時間,我們定義為甦醒時間A_wake(t);
- (c)使用者B每天發帖(轉發、評論)時間:B_action(t);
- (d)簡單假設一下A_wake(t)> B_action(t),也就是B_action(t)的評論都能看到。這就能得到使用者A對應了哪些帖子;
- (e)同理,也可知使用者A 在A_wake(t)時間內轉發了、評論了哪些帖子;
- (f)結合上次瀏覽間隔時間,可以描述使用者A對哪些微博感興趣(post ive),哪些不感興趣(negative)。
全連線層的啟用單元比對提升
在Google那篇論文中比對隱含層(也就是我們結構圖中的FC層)各種單元組合產生的結果,Google選擇的是最後一種組合,如圖7所示。
我們初期選用了512 tanh→256 tanh 這種兩層組合,後認為輸入特徵維度過大,512個單元無法完整的表達特徵,故又對比了 1024→512組合,發現效果確實有微小提升大概在0.7%。另外我們的FC層輸入在(-1,1)區間,考慮到relu函式的特點沒有使用它,而是使用elu啟用函式。測試效果要比tanh函式提升0.3%-0.5%。
附node2vec偽碼: