推薦系統實務 (一) : Embedding 技巧

Edward Tung
數學、人工智慧與蟒蛇
39 min readMar 22, 2021

Practical Recommendation System 01 : Embedding Techniques

目錄

前言精準描繪用戶 Precise Depiction of Users
一 : 用戶資訊描繪 User Side Info Depictions
【1.1 - Word2Vec Embedding】
【1.2 - Field-based Encoding and Factorization Machine】
二 : 用戶歷史行為描繪 User Historical Data Depictions
【2.1— Simple Pooling From Item Embeddings】
【2.2 — Sequence Embedding with Transformer】
【2.3 — Session-based GRU4REC Methods】
三 : 用戶社交關係描繪 User Social Relations Depictions
【3.1 — Nearest Item Embedding on Similarities】
四、其他酷東東 Other Cool Stuff
精準描繪產品 Precise Depiction of Product
一、產品資訊描繪 Product Side Information Depiction
二、產品相似度描繪 Product Similarities Depiction
【2.1 — Similarity of a Product】
【2.2 — Item2Vec Embedding】
【2.3 — Graph Embedding : DeepWalk and Node2Vec】
三、其他酷東東 Other Cool Stuff
結語

前言

趁著歲月靜好,來系統性總結一下這一大方向的實作心得與技巧。

推薦系統 (Recommendation System) 顧名思義解決的是如何給使用者作推薦的問題,舉凡在 Youtube 上看過的影片推薦內容、Netflix 客製化的首頁推薦、各種算法近乎惱人的廣告推薦以及在 Google 搜尋中輸入字串後得到的結果排序,都有該技巧的影子在裏頭。

與一般機器學習任務比較常見的,如預測模型、電腦視覺、語音處理等比較不同的是,推薦系統在問題定義、資料蒐集、模型架構上皆有著驚人的彈性,由於缺少比較固定的 I/O,這個領域幾乎沒有所謂的定式可言,因此你很少會在給定一組資料集的前提下單獨進行模型改進,當然某些論文發表在一些較有公信力的數據集以及損失函數上做出優化是另當別論,但實務上這些論文能夠涵蓋到的方面往往只有整個系統架構的冰山一角。

這些困難點通常包含幾個,由比較大層面的方向到細微的調整分別是 :

一、資料蒐集的困難 : 除了少數大公司由於深入你生活的方方面面,能夠得到更多個人數據以外,大部分情況下推薦系統都只能從用戶的歷史行為著手去刻劃用戶,且依據業務場景不同這些蒐集回來的數據往往並非十分乾淨,這時就需要花更多時間檢視資料蒐集的 Trigger Point,花費大量的時間討論數據正確性,以及該如何埋點蒐集更多數據等等。當然,這在任何一個機器學習的實際應用中皆是如此,因此這個系列中也不會多提。

二、刻劃用戶與產品 : 與任何一個和消費者直接相關的建模或分析任務雷同,我們總想著要如何更精準地描述用戶與產品,來達成精準媒合。與傳統分析任務如消費者存活分析、購買頻率分析等比較不同的是,推薦系統由於需要細化到消費者級別,因此許多場景下捨棄了對入模數據解釋性的要求,這使得我們可以用更複雜的方法描繪這些屬性,但這並不代表不追求可解釋性,因為在推薦系統的場域中,如何更有道理地去設計這些變量往往也來自於對於消費者心理的把握。

三、損失函數的設計與模型結構的調整 : 目前的業界主流已經大量應用複雜的深度神經網絡去處理這一類信息過濾問題,但是依據業務場景不同,你希望模型達成的效果也往往有所差異,因此損失函數的設計就變得至關重要,又加上多元目標往往是在實務上有需求,但技術上難以實現的,因此常見的是在不同的地方去搭建不同模型,甚至不同用戶給予不同模型的情況。

四、消費者心理感受與模型結果的差異性 : 以 Youtube 一個著名的例子來說,我們滿常在影片下方的留言看見諸如 「演算法推薦我十年前的影片」等例子,這是因為如果太關注近期的用戶行為去做推薦,很有可能造成用戶剛一搜尋某個東西,就整幅頁面充斥該類型推薦等不好的體驗,因此往往模型上合理的設計可能就需要為了兼顧這樣心理的多元性去作出調整。

五、產品迭代與效益評估 : 由於推薦系統的成效與否仍然決定在消費者行為上,但這些行為往往有一定的延遲性,造成產品效益評估上往往不能單純通過線下測試去完成,而線上測試帶來的各種問題又反向托類的產品迭代速度,因此如何更快速完成這些流程並進入下一階段,往往是許多大廠的數據科學團隊所要專注發展的。

六、冷啟動與邊際效益遞減問題 : 通常兩種情況下推薦系統會失去其作用,第一是對新用戶的處理,在你對用戶仍舊一無所知前實際上推薦基本只能亂猜,因此如何用更合理的方式去調整這一策略往往是該系統能否有爆炸性成長表現的關鍵之一。邊際效益遞減則是對那些已經留存一段時間的老用戶,對於產品的探索已經有一定理解並更加追求新鮮感的心理狀態,往往造成在自家產品不夠豐富的時候一些建模困難,因此這時往往會退化成更簡單地,非關用戶歷史行為的一些深層心理調整,如一些行銷方案的設計、觀測用戶遷移興趣時所產生的行為模式進而做出推薦。

七、機器學習工程問題 : 此類問題包含訓練模型的複雜性、更新的實時性、返回預測結果的頻繁性以及用戶數據的隱蔽性等等。比如在 Netflix 打開時,可能就需要透過所謂的 On-demand prediction 來設計系統架構,但在個人化推薦列表中,也許僅採用 Cloud-based batch prediction 即可有一定效果。用戶數據的隱蔽性則在於許多時候用戶的行為僅會有正向回饋,你很難知道一個用戶是否討厭該產品,因為根本不會有任何交互數據產生。

這些內容不可能在一個篇幅中講完,因此在系列的第一篇,我將要先從如何更有效率地刻劃用戶與產品行為著手,這類技巧在深度學習的模型中非常常見,通常採用的是 Embedding 方法,然而如何更精準透過 Embedding 來描述這些行為,則是我們要深入探討的一大重點。本文中我會預期你已經有一些足夠的關於 Embedding 在深度學習中應用的知識 (比如至少認識到深度神經網絡結構中對於離散數據處理的不足,以及基礎 NLP 概念的認識),此外我會使用 PyTorch 來做程式碼的示範,如果對這兩套工具或方法還不熟悉的,建議可以先參考以下的連結 :

此外,由於簡便因素,以下的 pyTorch 程式碼僅包含必要的 forward() 部份以及 __init__ 中的必帶參數,對於 run_epoch 與 validation 細節除非必要否則不會特別寫出來。在開始之前,先用一個簡單的圖讓大家有基本概念:

精準描繪用戶 Precise Depiction of Users

對於用戶的描寫我們大概可以從幾個部份去講解 :

一、用戶資訊描繪 User Side Information Depiction

【1.1 - Word2Vec Embedding】
想像一下一般情況下我們在產品端可以收到哪些數據,用戶 ID 是一個鐵定會有的,如果幸運的話 (代表通常不會),你還可以進一步得知其性別、年齡等個人化資訊以及一些離散的,與實際行為比較無關的跟產品互動的資訊,比如用戶加入產品的月份、過去近幾個月是否有活躍、平均消費金額多少等等,這些我們統一稱作 Side Information。

為甚麼稱作 Side Information? 這些東西大部分並不直接與用戶的真實偏好相關,你也許會認為比如收入高的用戶會容易喜歡更高價的產品,這在 Large Scale 來說也許會觀察到這樣的情況,但請注意一旦放到更個人化的層面,這樣的因果推論往往是有問題的,高收入的用戶不代表都不喜歡高 CP 值的產品,或根本只是因為你顯示在首頁上那些比較低價的產品剛好不符合他們的口味罷了。有鑑於此,這些數據我們稱作 Side Information,除了一些必要的如用戶ID、近期是否活躍等資訊外,通常比較是 Good-to-have 的,或是你需要這些資訊來做一些 Generalized Recommendation 時才派上用場。

這些數據通常是高度離散化的,充滿許多類別變量,一般來說類別變量直接放入神經網絡或甚至許多傳統機器學習模型的效果都不太好,我們會需要幾種比較特別的 Encoding 方法,最常見的當然就是 One-hot-encoding,也就是將其全數轉變為 0-1 變量。

很顯然這樣的作法並不是特別精確,模型除了得到 Yes and No 以外幾乎沒有特別多有用的資訊,因此有一些思想就開始將類別與用戶連續值數據聯繫起來,比如 Kaggler 特愛的 Target Encoding ( 或不放入自己的 Leave-one-out target encoding) :

不過這樣顯然還是遠遠不足,轉換過程太過線性且缺乏足夠的資訊,僅有平均或即使你多了許多不同種的編碼如中位數等等,對於某些情況如 Category 數量巨大的時候,往往會力不從心,而且重點是,太占儲存空間了,因此,人們開始把目光投向一個在 NLP 領域大熱門的概念 : Word2Vec。

Efficient Estimation of Word Representation in Vector Space (Google, 2013)
https://arxiv.org/abs/1301.3781

Word2Vec 我這邊只快速的說明一下概念,有興趣的請參照上方的連結論文,簡單來說,假設我們有一個給定的文本,裡頭包含了 N 個詞彙,那我們能否找到一種方式將這些離散的詞彙映射到向量空間 R^K 裏頭,其中 K 代表了一個向量的長度,這樣詞與詞之間就可以更好地進行比較了。

那麼我們怎麼用向量來表達這些詞呢? 一個很簡單的思想在於,詞與詞之間通常是有上下文聯繫的,如果我能將每個詞語表達成一組向量,而這組向量能夠成功 "預測" 其最有可能的上下文,那麼我就可以更準確地用 Low rank dense vector 來描繪這些向量了。在一開始該方法提及的時候,常見的作法是 CBOW 或是 Skip-gram 結構,也就是一個詞語分別是以 "預測一段話中的中心詞" (CBOW) 或是預測一段話之中的上或下一個詞彙 (Skip-gram) 為核心去訓練的 :

Green : Context ; Red : Target

當然,這樣的訓練也並不一定要只用下一個來當對象,一般來說是支持滑動窗口的設計,也就是你大可以拿,比如每四個詞去預測下一兩個詞,這樣的方式來做訓練。早期該方法剛提出來的時候是用 Huffman Tree 去進行編碼,但隨著序列方法如 RNN、LSTM、Transformer 等蓬勃發展,訓練的精準度與彈性都有所提升,當然這些新技巧我們晚點再談,因為在單純得到詞向量的場景中,這些離散數據還沒有這麼多如上下文關係等給我們做訓練。

一般來說,對於這類型沒有上下文關係的離散數據如用戶 ID 等,僅需要使用簡單隨機賦值的方式即可,比如在 pyTorch 的 nn.Embedding 模組中就可以很輕易地調用。

如果你的離散數據中包含 NLP 相關的文字資訊,比如用戶填寫的回饋等等,你也可以載入預先訓練好的 Word2Vec 模型來處理,知名的 gensim 模組已經幫你完成了類似的任務 :

因此,一般來說你可以這樣寫一個 Embedding 層來處理這些離散數據 :

非常簡單地完成任務,當然,乍看之下這樣的 Embedding 方法在一開始包含的資訊並不見得勝過 Target Encoding,但在神經網絡的訓練方法下,這樣的數據結構反而更加適合。

【1.2 - Field-based Encoding and Factorization Machine】
通常,不同類型的變量會經過不同的 Embedding 層,這種作法我們稱作 Field-based Embedding,每一個不同的變量或每一種不同的變量組合我們將其稱作 Field,之所以這麼做也是為了保證數據是分開的,不會彼此混合。

然而,對 Logistic Regression 建模如果有一定的了解,就會明白這種作法在所謂的特徵交叉維度上幾乎完全是不合格的,線性建模中為了彌補無法獲取變量非線性資訊的缺點,通常會做許多的二階交叉處理,其中一個集大成者莫過於分解機模型 (Factorization Machine),雖然思路十分簡單只是將兩兩變量再度交乘起來,對稀疏數據的效果卻出奇地好 :

當然,這也不單單只是兩兩變量交乘,注意到上式中的 <v_i, v_j>,這之中借用了矩陣分解的思想,先將原先兩變量交乘的模型分解成兩個包含隱向量的矩陣後再做運算,如果對該方法有興趣的朋友可以參考 :

把這樣的思路與我們剛才說的 Field-based 方法結合,就變成了 Field-aware Factorization Machine,這個方法曾經獲得過 Kaggle 推薦競賽的冠軍,由台大的林智仁教授與 Criteo 公司研究員等人共同發表:

與 FM 不同的點在於,該方法將同一種變量生成的 One-Hot 特徵都放入同一 Field 之中,並對這些 Field 去作出交叉,因此長得會像是 :

而 FM 則成為 FFM 的一個特例,也就是所有變量都歸屬於同一 Field 時的情況,因此,這樣的方法也可以用來做 Embedding,取代原先只採用隨機賦值的方式來進行,效果會更好一些。

那麼,有沒有辦法把預先做好的 Embedding 與 FM 的思想結合呢 ? 有的,實際上這樣的結構在實務應用上更加常見一些,先透過某些方法學習 Embedding 以後再將其用來做 FM 或是 FFM 的交叉並餵到後續的神經網絡中,甚至直接就將其當成推薦結果也是大有人在。

舉例來說,2017 年哈爾濱工業大學與華為諾亞實驗室的研究員就提出了 DeepFM 架構,先用 Field-based 的方法生成 Embedding 之後再進而做 FM 交叉,並將其當成是淺層模型的輸出。

Deep Factorization Machine (2017)
https://arxiv.org/pdf/1703.04247.pdf
注意上圖左半部分,為 FM Layer 的結構

而且這樣結構的好處在於,即使不是我們說的 Side Information,那怕是後續用序列方法或社交網絡方法(下面會提及),都可以放進去同樣的結構中,而不會只侷限在用以預訓練離散數據本身,我自己就滿愛用類似這樣的結構去進行魔改的,實驗上效果普遍不差。

要放入 FFM 模型也不難,這裡我稍微寫一下,由於 DeepFM 牽涉的調整太多,與數據結構、網絡結構都有密切關係,我就不完整寫出來了,只稍微寫一個基於 pyTorch 的 FFM 以供參考。

這裡假設 DataLoader 吐出來的資料包含了 N 個 Field,其中每個 Field 包含了 Embedding Vector,下面如果要預訓練可以加入 y 並設定損失函數,如果直接拚接於其他模型上則是直接嵌入即可。

二、用戶歷史行為描繪 User Historical Behavior Depiction

用戶歷史行為也就是其與哪些產品有過互動,這類行為的刻畫我通常會處理兩個種類,第一個是物品建模,也就是關注於用戶與哪些產品互動過,我們怎麼用 Embedding 方法來描述這些行為;第二則是序列建模,也就是考慮用戶不同時間段與互動的順序,後者在許多場景更加重要,因為其通常能更準確地抓住用戶的近期感興趣物品。

【2.1— Simple Pooling From Item Embeddings】
首先,對於產品互動的刻劃基本上仰賴於產品訊息,對於產品的刻劃我會在下面說明,因此我們這邊先假設已經有每個產品處理好的 Embedding 向量。

此時,我們要思考的問題是如何將其作為用戶刻畫的基礎條件,一個最簡單的方法就是,我們將用戶瀏覽過的商品或觀看過的影片 Embedding 向量去進行各種交叉處理,比如很容易想像的做法就是取平均或是最大化等等操作,不過單純這樣操作其實必須要十分謹慎,因為這大部分仰賴於預先訓練好的 Embedding 向量在這麼做之後是否仍有意義,以及在實際業務場景上這樣做的可行性高低。舉例來說,以 Youtube 知名的深度學習推薦系統論文中,對用戶的刻畫就採用了這樣的結構,先將看過的與搜索過的影片向量訓練好之後,直接餵進去做平均計算,也有效避免了用戶觀看數量、時長不同的情況下如何做統一處理等等 :

Source : Deep Neural Network for Youtube Recommendation (2016)

當然,這麼做的可行因素在於,第一是這些物品/影片是經過一定的模型訓練的,也許通過大量用戶對其的歷史觀看行為等資訊進行訓練等 (這邊論文沒有明說),因此本質上這些 Embedding Vectors 已經有一定的業務意涵。第二則是該操作不單純只是做平均而已,通過考量進去經過時間長短、影片重要性等因素,是將其映射成多個 Embedding 向量,並且用加權平均的方式調整這些時間與影片因素等 (如上圖左下藍色部分)。

值得一提的是,Youtube 實際上因為工程考量而採取了兩部分模型架構,前者的 Recall 層用比較簡單的方式,從百萬量級的影片中預先篩選過用戶可能更加喜歡的影片內容,並在 Ranking 層用上圖的方式去進行精排,這也是其中一個為甚麼這樣的操作較不容易產生偏誤的原因之一。

Source : Deep Neural Network for Youtube Recommendation (2016)

這種近似 Pooling 的操作實作上非常簡單,我就不多提了,關鍵在於能否基於業務理解去更有效率地調整並擴增這種方法的可吸收資訊量,而非單純只將數據拼接起來,比如我自己就很喜歡用時間間隔乘上指數的方式去做加權平均,反映出某些物品由於時代久遠,重要性應該遠遠更低的情況。

【2.2 — Sequence Embedding with Transformer】
一個實務上考慮的點是,由於使用者的偏好往往與過去與哪些商品互動過有關,因此最好的作法當然就是我們對該使用者的描述直接就是由使用者的歷史互動序列去生成。

Source : Online Customer Buying Behavior

透過序列來生成 Embedding 的方法有很多,但其中最有名的應該要屬於 Seq2Seq 思想,由於推薦系統的 Embedding 大量受到 NLP 對於文字或語句序列處理方法的影響,諸如 Seq2Seq 之類的方法也被大量採用在該領域中。

Seq2Seq 顧名思義,給定一個序列然後輸出另外一個序列,基本上並不是一個模型的名字而是一種方法的統稱,在語言處理上,可以用來處理文本的翻譯問題,而在推薦系統上,如果我們有一些長度不等的用戶行為序列 — 當然你可以進一步擴展他,比如在電商的場景中,把搜尋、放入購物車以及實際購買結帳的產品分開來當作不同的序列處理等。

雖然對於如何產出這個結果並沒有明確的 Best Practice,但大多數情況下我們會採用 Encoder-Decoder 框架,然後在 Encoder, Decoder 中各自採用一些序列模型去進行訓練 :

而說到序列問題,一個最簡單的做法就是用 RNN 去處理他,不過由於 RNN 容易造成梯度消失,且對於更長期資訊的處理明顯不足,在許多長序列的情況下處理效果仍舊不好,我們這時會考慮採用 LSTM 或 GRU 方法去替代他。

Souce : Wikipedia

LSTM 由於 Forget Gate 的設計,Gate 在開啟時,梯度會接近於 1,由於又加上一個 Sigmoid 的 Activation Function,此時也不容易發生梯度爆炸,整個概念有點像 ResNet,某種程度上跳過了梯度的直接傳播。

GRU 在此之上進一步修正了閘門的機制,透過刪除 Output Gate 等方式來減少參數量,下方圖片可以很明顯地看到對比,至於詳細機制我就不多說了,有興趣的朋友關於這兩大模型的介紹應該都能很容易在網上找到 :

Learning Phrase Representation using RNN Encoder-Decoder for Statistical Machine Translation (2014)
https://arxiv.org/pdf/1406.1078.pdf

當然,近期持續關注 NLP 的朋友們一定對另一個更加潮潮的名詞不陌生,也就是 Transformer,該技術讓 Google 催生出了 BERT (當然最近 OpenAI 又搞出了 GPT-3,覺得土豪) 等等預訓練的自然語言模型。Transformer 的好處在於幾個,一是透過平行化運算的方法解決了以往 RNN、LSTM 訓練速度慢的問題,比如 LSTM 一次設計了四個閘門,這使得訓練上往往沒辦法帶大 Batch 來執行,二來是該架構的設計能夠比以往更好地學習到長序列的資訊,因此基本上在大量數據的情況下幾乎表現都是優於 RNN 的,當然小序列不一定,偶爾用 Transformer 還是很容易 Overfit 的。

Source : 李宏毅教授,講解得非常清楚
Attention is all you (2017)
https://arxiv.org/pdf/1706.03762.pdf

同樣,要採用 Seq2Seq 的方法來建立使用者行為序列的 Embedding 並不困難,pyTorch 的官方已經有非常簡易的程式碼教學,很快就可以上手,如果你不想採用 Transformer 架構,也有很多如 LSTM、GRU 等等的選擇。不過我自己更喜歡採用 Transformer,因為他能夠允許 Positional Embedding 的方式來處理序列之中的時間差距不一致的問題。

如果採用的是 RNN、LSTM 方法,直接以序列中最後一個值作為預訓練的對象,而不想麻煩地套上 Encoder-Decoder 架構時,則可以直接套用 nn.LSTM 即可,不過注意由於此時序列長度必須相同,對於空白值必須自己填補,比如說統一所有用戶以前20次互動作為輸入,則對於短序列則須自己填入一些index 值比如 -1 等等,如:

【2.3 — Session-based GRU4REC Methods】
另一個我想介紹的主題是 2015 年發表的這篇文章。

Session-based Recommendation with Recurrent Neural Network (2015)
https://arxiv.org/pdf/1511.06939.pdf

之所以會特別拿出來講,是因為這個技術是將業務情況與模型架構連結的一個良好例子,作者注意到在許多場景下用戶的興趣是 by Sessions 的,Session 通常代表一個用戶不間斷操作的時間區段,比如你打開網購頁面到離開為止的所有行為算成一個 Session,下一次再打開則是下一個 Session。

由於你在離開網頁時可能發生了許多事造成興趣改變,因此最能夠抓取興趣的應該是該 Session 下的所有行為,因此,雖然整個主旨仍然脫離不了序列建模,但在於如何選擇序列這件事上做出了調整。

文章的模型結構並沒有差異太大,僅是一個 Embedding 後接入 GRU 層而已,值得一看的是其中對於輸入輸出的資料拼接,由於各 Session 長度會有所不同,因此在 Batch Design 上就是拿每一個 Session 的第 t 個值去預測第 t+1 個值,進而用滑動的方式完成預訓練。

我個人認為這是一個很好地將業務與模型結構連結起來的案例,不過這僅在 User 的興趣與 Session 高度相關時有效,在某些場景比如 Netflix 上,可能就不是這一回事,如果有興趣的讀者也可以參考上面的論文連結。

三、用戶社交關係描繪 User Social Relations Depiction

【3.1 — Nearest Item Embedding on Similarities】
另一個常用來刻劃用戶的方法是,你與哪些用戶相似,且他們都與哪些產品互動過。比如在 Youtube 中你可能會看到這樣的一個標語 : 「XXX 的粉絲也看了 ... 」,這樣的方式在前端呈現或是後端運算往往會有不錯的效果。

這些 User 的相似程度我們通常會將其描繪成 Social Relations,在不同的場景下你可以有不同的 Social Relations 定義,而不只有相似程度,比如在社交平台的場域下最直接的就是看你與其他用戶的好友關係與共同追蹤關係來定義連結,而在 Netflix 的情況下可能就是你與其他用戶看過的影片中相似程度事多少藉以定義相似度,而相似度的計算方法也有很多種,比如各式各樣的距離等等,端看你的應用場景而定,比如以觀看紀錄來說可能可以採用 Cosine Distance,以其他的 Side Info 相似度來說採用 Euclidean 等等 :

而我們這邊要工作的在於,如何在這基礎之上去設計 Embedding Layer 來表達這種相似度關係,因為這有利於更複雜的模型運算,一種簡單的方式是採用 Nearest Neighbor 的方式,通常又分為有監督的方法與無監督的方法。

無監督的方法比較簡單,我對每個人隨機選取 K 個最近鄰來做其 Embedding 的拼接,比如平均處理等等,但當然效果較差,畢竟考慮到的社交關係廣度與深度都應該要因人而異,好處是運算簡單。有監督的 Nearest Neighbor 方法則複雜得多,一種方式是選取一定數量的近似樣本,並將這些樣本的 Embedding 差值或是其他任意定義的相似度當作訓練對象,進行 Embedding 的訓練,也就是目的在於希望訓練出來的 Embedding 能夠學習到與該用戶相似的用戶相似(差異)程度。

注意上圖不是要你最後一層放 Embedding Layer,而是把輸出層前面層當作 Embedding 給萃取出來

類似的做法在一篇基於 Matrix Factorization 去做相似度判斷的文章中有提到,當然,上述的架構主要是因為現今我們已經非常熟悉如何用 Neural Network 來完成矩陣分解工作了,但核心思想還是沒有變的 :

A Matrix Factorization Technique with Trust Propagation for Recommendation in Social Networks (2010)
http://web.cs.ucla.edu/~yzsun/classes/2014Spring_CS7280/Papers/Recommendation/p135-jamali.pdf

當然,參考詞向量的生成方法也是可以的,比如透過該社交關係圖去生成特定序列,來判斷是否與該用戶相似,不過該方法由於難以同步表達近似程度,即使採用如 Node2Vec 等方法 (下面提到),用戶的社交關係由於總是比產品複雜得多,生成序列的效果往往不是太過理想,因此在刻劃用戶關係上,我還是喜歡採取用相似學習的方式來處理,甚至由於業務關係,不大需要將時間因素給考慮進去,畢竟還是有機會讓用戶了解到一些舊但是高品質的產品。

上面是基於 DSSM 模型輸出的一個類矩陣分解神經網路,當然這只是一個範例,實際上相似度計算、神經網絡內容都是可以根據需求調整的。

Learning Deep Structured Semantic Models for Web Search using Clickthrough Data (Microsoft, 2015)
https://posenhuang.github.io/papers/cikm2013_DSSM_fullversion.pdf

四、其他酷東東 Other Cool Stuff

【4.1 — Sentiment Analysis】
情感分析也是很重要的一個環節,將用戶的評論資訊或其他相關數據做情感描述,並且將其當成 Embedding 輸入資訊,情感分析的方法有很多種,你可以載入別人訓練好的 BERT、GPT 等模型來做情感判斷,也可以透過各種如 in-app survey 等方式做有監督訓練等。

精準描繪產品 Precise Depiction of Products

一、產品資訊描繪 Product Side Information Depiction

這一塊與剛才 User 十分相似,通過產品的 Side Information 去進行諸如 Word2Vec 訓練等等,因此這邊就不再贅述。

二、產品相似度描繪 Product Similarities Depiction

【2.1 — Similarity of a Product】
推薦相似的產品給用戶是非常常見的操作,比如你看了某種類型的片子,或是看過某種類型的商品,我們總是想要推薦更多類似的商品出去,因此,判斷產品之間的相似度在推薦系統 Embedding 裏頭幾乎是不可避免的。

一個最簡單的例子當然是直接通過產品之間 Embedding 向量來計算一些相關的指標,如同上面說過的,你可以有各種距離的度量來評估一個產品是否與其他產品相近。當然,相近的定義有許多層面,以商品來講,大分類是一個相似的度量標準,但價錢是否在同一區間也是另外一個衡量方法,因此,透過 Field-based 方式建構 Embedding 向量再生成 Similarity 也是常見的做法。

【2.2 — Item2Vec Embedding】
然而真正能夠說明產品相似度的,除了一些直覺可以想到的因素外,最直接的就是觀察消費者是否在一個購物籃裡頭會同樣購買這個商品組合,舉例來說,如果消費者一次買了一籃物品 [A, B, C, D, E],通常我們會說 A 與 B 相似,若是更多消費者同樣都買了 A 與 B,我們會更有信心說這兩個產品相似度更高一些。

觀察一下現在的數據結構,消費者購買的一籃產品對我們而言就如同一組序列一樣,那麼很自然地,透過序列建模的方法去做詞向量轉換也在考慮之中,參考 Word2Vec 的作法,我們可以用 CBOW 或是 Skip-Gram 來預訓練這些資訊,讓模型學習到如果出現 A 產品,那麼就很容易也出現 B 產品這樣的模式。因此,同等於 Word2Vec,我們可以用這樣的概念去進行 Embedding,也就是所謂的 Item2Vec 方法。

Item2Vec : Neural Item Embedding for Collaborative Filtering 
https://arxiv.org/vc/arxiv/papers/1603/1603.04259v2.pdf

這篇似乎是 Workshop 而非正式 Submission,不過整體架構也很簡單,將同一購買商品視為一個集合後,也是通過滑動 Contextual Window 與負采樣的方式進行迭代,值得一提的是負採樣,以往來說都是以隨機負採樣的方式居多,這某種程度上是合理的,因為大多數情況下我們在推薦系統中回收的數據只會有正樣本,也就是用戶已經跟這個產品互動過,才回傳的樣本。

論文中比較 Item2Vec 與 SVD 的差異

然而在實務上,我們往往會嘗試多種負採樣方法,通常這有兩種情況,一是基於業務理解去進行負採樣,比如我們可以定義說,消費者瀏覽過但最終沒有點擊加入購物車或是往下滑看商品說明的商品,代表某種程度上不喜歡該商品,因此將其標註為負樣本 (當然這也許有點偏激,但不失為一種嘗試);二是基於特定分布去負採樣,比如在某些時候,會得到特定使用者的負回饋資訊,像是他對商品的評論或是按了不喜歡等等,這時候我們就可以拿該用戶的歷史瀏覽與負樣本做比對,判斷瀏覽哪些物品的情況下會對該產品產生負向觀感,並藉此用給定權重的方法從當前已有的瀏覽序列中有偏差地去抽取負樣本 (不會直接拿去建模,通常效果太差且容易太過武斷)。

【2.3 — Graph Embedding : DeepWalk and Node2Vec】
上面的做法還有一些缺點,一個比較明顯的是缺乏先後順序,通常使用者與產品的互動行為更像是網絡圖,會買 A 產品的人有多少比例也會購買 B,而購買 B 產品的人又更容易購買 C 等等。因此,基於 Graph Embedding 的方法映入眼簾,我們需要去思考兩件事,一是如何從用戶與產品的互動中構建關係圖,二是用怎樣的方式去進行 Embedding。

構建關係圖的方式一般有兩種,首先你大可以直接從購買序列裡面去生成圖表,類似這樣 :

透過一些關聯規則學習的方式來構圖也是一種思路,由於前者相對複雜,需要進行多次迭代甚至思考選取序列的方法,預先透過購物籃分析如 Apriori 算法等方式去處理資訊再建圖也是一種可行方案。關於該算法我就不多談了,非常簡單直觀,有興趣的朋友請參考 :

不過第二種作法在產品數量龐大時就行不通,Apriori 要求產品與其他所有產品進行相似度衡量,計算上非常複雜。因此我們總是要面對第一種方式,為了解決序列過多的問題,這包含了幾個小問題,比如如果只按照原始數據序列去選取,某些產品的樣本點會嚴重不足,或是某些大量購買的消費者會大亂整個圖結構等等。

解決這些問題,一個很簡單的方法就是在圖上隨機遊走,確保個商品都有一定數量的序列,之後就可以直接拿這些序列進行序列 Embedding 了 (Word2Vec 或是用 RNN、GRU 等方法訓練)。當然,雖說是隨機遊走,但也不完全是真正的隨機,一般來說生成圖的邊都會帶有權重,也許是瀏覽人數的比例或是共同購買的機率等等,會根據這個權重去給定機率決定下一步要朝哪個方向去進行遊走.

Deepwalk : Online Learning of Social Representations
https://arxiv.org/pdf/1403.6652.pdf

不過隨機遊走的方式其實並不夠完美,當一個圖生成後(不論你是用哪種方式,是否帶權重去生成),隨機遊走搭配隨機產品作為起始點的方法也許有效避免了某些產品樣本不足的窘境,但反過來說卻忽視了圖中的 homophily 及 structural equivalence 兩者平衡,這是什麼意思?Homophily 指的是高度互相交錯的那些節點應該要屬於同一個 Cluster,意思是我們需要觀察到這些節點有一樣的性質 (Embedding Vectors),而 Structural Equivalence 指的是在網路中扮演同樣角色 (Structural Role) 的節點應該有一樣的性質 (即使不見得互相高度交錯).

為了達成 Structural Equivalence,我們傾向用 BFS 的方式遍歷圖,而為了達成 Homophily,則容易選擇用 DFS 的方式來處理,而很顯然 Deepwalk 沒辦法很好地取得平衡,因此我們把目光轉向另一個方法,在 2016 由 Stanford 提出來的 Node2Vec 方法 :

node2vec : Scalable Feature Learning for Networks
https://arxiv.org/pdf/1607.00653.pdf

Node2Vec 採取了一種彈性的鄰接點採樣策略來幫助取得平衡,基於原始的 Random Walk,再加上一種新的 biased Search 方法透過調整權重的方式去取得平衡?How?首先,我們先看一張圖:

Source : https://arxiv.org/pdf/1607.00653.pdf

原先 Deepwalk 的方法是直接定義了每一次遊走的轉移機率,通過權重的方式來調整,而 Node2Vec 要進一步定義的是一個 2nd Order 的遊走方式,假設我今天已經從右圖的節點 t 走到節點 v ,那麼在下一次迭代的時候,我應該以怎樣的機率來決定從 v 走到相鄰節點的 t, x1, x2, x3 的機率呢?

我們將 t, x 代表兩個節點之間的最短路徑,透過兩個參數 p, q 的設置來決定 從 v 當下到其他節點的的轉移機率 alpha 應該是多少,用以作為隨機遊走後的 2nd Order 遊走對象.如果 t, x (注意這裡的 t 是以上一次走來的節點為基準) 的距離在 0, 1, 2 之間,會給出不同的轉移機率,這個距離不會超過 3 或小於 0,超過 3 的一定不會與節點 v 直接相連,小於 0 基本就在異世界.

參數 p 我們稱為 return parameter,用以控制第二次的遊走方向是否容易返回已經遍歷過的節點,如果這個數值設定的很高,除非你下一次遊走的對象已經沒有更多節點了,我們會比較不容易去採樣到已經跑過的點,讓整個遊走路徑比較傾向於去找更遠的節點,達成 DFS 的概念.

參數 q 則一般稱為 in-out parameter,控制第二次遊走方向是否容易往更遠處沒有直接與 t 相連的節點去走,如果該值設定的很高 (由於我們將 t, x1 設定為 1,高值在這裡的相對定義就是那些大於 1 的值),遊走對象就比較不容易朝更遠處邁進而是傾向於跑去另一個也與 t 有相連的節點,進而達成 BFS 的要求.

透過這樣的 2nd Order 遊走方法與參數設置,我們比較有機會去達成 homophily 與 structural equivalence 之間的平衡,某種程度上幫助我們更好地去抓取序列訊息.Node2Vec 或剛才的 Deepwalk 在後續生成 Embedding 的方式與前面提及的序列 Embedding 大同小異,不再贅述,而整個算法的重點都在於圖建構與隨機遊走的過程,以 Node2Vec 來說,其中一位作者已經很好心地開源了程式碼,可以用來生成序列後直接接上 pyTorch Embedding:

整個 Node2Vec 與 Deepwalk 在業務層面理解上最大的不同在於,哪怕商品的購買比率不同,只要該商品在圖結構上扮演一樣的角色,比如雖然小眾了一點,但某種香氛蠟燭的確是進入該領域最好的入門商品,這跟更加大眾但同樣扮演入門商品的某款監聽式耳機可能有異曲同工之妙,Node2vec 會嘗試抓住這個點而非一昧地追求轉移機率,因此使用上可以參考業務需求去做出調整.

三、其他酷東東 Other Cool Stuff

【3.1 — Graph Visualization based Embedding】
由於現在許多場景上商品會搭配如圖片甚至語音介紹等等的酷炫功能,而這些圖片介紹往往又對消費者是否購買的心理會產生一定程度的影響,因此將這些圖片作為 Embedding 輸入的方法也是其中一類方向.

Graph Embedding 可用的工具又多出不少,基本上圖片本身就是一種數值型的資料結構,加上電腦視覺領域對這塊的探索已經非常成熟,我們總是可以很輕鬆地找到對應的方法來處理,這邊我就不多談了 (主要我也不熟XD)

結語

Embedding 方法幾乎是推薦系統最重要的一個部分,當然方法鐵定不只有上面提及的內容,每年都有大量的研究機構與公司提交最新的成果,如果對更新的研究方向有興趣,可以參考 RecSys 年會的一些最佳論文:

比如 18 年就有一篇 Casual Embedding 嘗試去解決大多數 Embedding 預訓練對象與實際用戶表現行為不同的一大痛點,或是基於多任務學習的一些方法也值得期待.

實際應用上,考慮許多的業務需求而調整 Embedding 方法是必須的,但工程層面也不見得會總是將所有能用的資訊都用上,其一是會增加整個系統架構的複雜性,如果沒有帶來相應顯著的效能提升,通常並不會考慮將系統設計得如此繁雜;其二則是數據限制,某些數據實際上並不能如此完美地反應業務直覺,最有名的一個例子就是所謂的 Implicit Feedback,用戶與產品的互動行為不見得完美表達用戶的偏好,那麼自然就難以用來建構產品共同偏好序列,因此有時候反而會帶來不好的體驗.因此,考量實際情況作出相應調整才是正確的做法,而非一昧追求技術的完善.

推薦系統的整個大主題還有許多沒有觸及到,下一篇會描述不同的模型結構設計思路以及其與業務目標的結合,也許下下篇提及整個系統的評價方式,包含固定指標的離線評估與非固定指標的線上評估等等 (如果一切我有時間的話),希望這次的整理對各位有所幫助 !

--

--

Edward Tung
數學、人工智慧與蟒蛇

Columbia Student || 2 yrs of data scientist and 1 yr of business consultant experience