前深度學習時代-推薦系統的進化之路附部分代碼(深度學習推薦系統學習筆記)

目錄

1 傳統模型的演化關係圖

2 協同過濾-經典的推薦算法

2.1 什麼是協同矩陣

2.2 用戶相似度計算

2.3 最終結果的排序

2.4 ItemCF

2.5 UserCF 與 ItemCF 的應用場景

 2.6 協同過濾的下一步發展

3 矩陣分解算法-協同過濾的進化

3.1 矩陣分解算法原理

3.2 矩陣分解的求解過程

3.3 消除用戶和物品的打分偏差

3.4 矩陣分解的優點與侷限性

4 邏輯迴歸

5 從FM到FFM-自動特徵交叉的解決方案

5.1 POLY2模型-特徵交叉的開始

5.2 FM模型-隱向量特徵交叉

5.3 FFM模型-引入特徵域的概念

5.4 從POLY2到FFM的模型演化過程

6 GBDT+LR——特徵工程模型化的開端

6.1 GBDT+LR 組合模型的結構

6.2  GBDT進行特徵轉換的過程

6.3 GBDT+LR組合模型開啓的特徵工程新趨勢

7 LS-PLM - 阿里巴巴曾經的主流推薦模型

7.1 LS-PLM 模型的主要結構

7.2 LS-PLM模型的優點

7.3 從深度學習的角度重新審視LS-PLM模型

8 總結


1 傳統模型的演化關係圖

           

2 協同過濾-經典的推薦算法

2.1 什麼是協同矩陣

協同過濾:就是協同大家的反饋、評價和意見一起對海量的信息進行過濾,從中篩選出目標用戶可能感興趣的信息的推薦過程。

         

推薦過程:

(1)圖(a)表示商品庫裏的四件商品(🎮,小說,雜誌和📺)

(2)我們要決定是否推薦📺給用戶X。可利用X對其他商品的歷史評價數據及其他用戶對這些商品的歷史評價數據

(3)爲了便於計算,將有向圖轉換成共現矩陣的形式,用戶行爲作爲行向量,物品表現作爲列向量,將👍和👎的行爲數據轉換成矩陣中相應的元素值,例如👍爲1,👎爲0。

(4)找到與用戶X興趣最相似的n個用戶,綜合相似用戶對📺的評價,得出用戶X對📺評價的預測(圖中B和C是與X相似的top2用戶,其中B、C均爲負面評價,可以推測X對📺的評價也是負面的,不推薦)。

2.2 用戶相似度計算

共現矩陣中的行向量是用戶向量,計算用戶i和用戶j的相似度,即是計算行向量i和行向量j之間的相似度,理論上任何合理的“向量相似度定義方式”都可以作爲相似用戶計算的標準,常用的如下:
餘弦相似度:夾角越小,餘弦相似度越大,兩個用戶越相似。

        sim(\boldsymbol{i},\boldsymbol{j})=cos(\boldsymbol{i},\boldsymbol{j})=\frac{\boldsymbol{i}\cdot \boldsymbol{j}}{||\boldsymbol{i}||\cdot ||\boldsymbol{j}||} \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (1)                                                                                          

皮爾遜相關係數:相比於餘弦相似度,皮爾遜相關係數使用用戶平均分對個獨立評分進行修正,減小了用戶評分偏置,其中R_{i,p}表示用戶i對物品p的評分,\bar{R}_{i,p}表示用戶i對所有物品的平均評分,P代表所有物品的集合。

       sim(\boldsymbol{i},\boldsymbol{j})= \frac{\sum_{p \in P}(R_{i,p}-\bar{R}_i)(R_{j,p}-\bar{R}_j)}{\sqrt{\sum_{p \in P}(R_{i,p}-\bar{R}_i)^2}\sqrt{\sum_{p \in P}(R_{j,p}-\bar{R}_j)^2}} = \frac{(\boldsymbol{i}-\bar{R}_i)\cdot (\boldsymbol{j}-\bar{R}_j)}{||\boldsymbol{i}-\bar{R}_i||\cdot ||\boldsymbol{j}-\bar{R}_j||} \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (2)  

相比於餘弦相似度,引入物品平均分減少物品評分偏置對結果的影響,\bar{R}_{p}表示物品p得到的所有評分的平均分,\boldsymbol{p}表示P中所有物品的平均評分向量

     sim(\boldsymbol{i},\boldsymbol{j})= \frac{\sum_{p \in P}(R_{i,p}-\bar{R}_p)(R_{j,p}-\bar{R}_p)}{\sqrt{\sum_{p \in P}(R_{i,p}-\bar{R}_p)^2}\sqrt{\sum_{p \in P}(R_{j,p}-\bar{R}_p)^2}} = \frac{(\boldsymbol{i}-\boldsymbol{p})\cdot (\boldsymbol{j}-\boldsymbol{p})}{||\boldsymbol{i}-\boldsymbol{p}||\cdot ||\boldsymbol{j}-\boldsymbol{p}||} \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (3)           

2.3 最終結果的排序

最常用的方式是利用用戶相似度和相似用戶的評價的加權平均獲得目標用戶的評價預測。其中,權重w_{u,s}是用戶u和用戶s的相似度,R_{s,p}是用戶s對物品p的評分。

      R_{u,p} = \frac{\sum_{s \in S}(w_{u,s}\cdot R_{s,p})}{\sum_{s \in S}w_{u,s}} \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (4)

符合直覺“興趣相似的朋友喜歡的物品我也喜歡”。

簡而言之,對給定的目標用戶我們是這樣決定候選集合中的物品的展示順序的,先找到與該用戶相似的Top n個用戶,利用這n個用戶對候選物品的加權打分來預測目標用戶對該候選物品的評分(缺點中的用戶歷史向量往往非常稀疏的問題,可能每個用戶只對其中的一兩個商品有過點擊,由於相似度是按元素相乘,沒有行爲的可能是0,點擊的數據過少,我們很難根據重合的這一兩個數據來說他們就是興趣相似的用戶,即是計算出的相似度很高,也不一定他們興趣相似度高,存儲量n^2增長的問題,感覺可能是保留了用戶與剩下的所有用戶的相似度信息,二不僅僅是保留了Top n個相似用戶的相似度,因爲後者的存儲增長是n)。

缺點:

  1. 用戶數遠大於物品數的場景,UserCF需要維護用戶相似度矩陣以便快速的找出Top n相似用戶,該矩陣存儲開銷很大,且隨着業務的發展,用戶數增長會導致用戶相似度矩陣的空間複雜度以n^2的速度增長
  2. 用戶歷史數據向量往往非常稀疏,對於只有幾次購買或點擊行爲的用戶來說,找到相似用戶的準確度是非常低的,導致UserCF不適用那些正反饋獲取較困難的場景,例如酒店預訂,大件商品購買等低頻應用。

2.4 ItemCF

ItemCF是基於物品相似度進行推薦的協同過濾算法,通過計算共現矩陣中物品列向量的相似度得到物品之間的相似矩陣,再找到用戶的歷史正反饋物品的相似物品進一步排序和推薦,ItemCF的具體步驟如下:

(1)構建共現矩陣,行向量是用戶向量,列向量是物品相關

(2)計算共現矩陣晾涼列向量之間的相似度,構建n*n爲的物品相似度矩陣

(3)獲得用戶歷史行爲數據中的正反饋物品列表

(4)利用物品相似度矩陣,針對目標用戶歷史行爲中的正反饋物品,找出相似的Top K個物品,組成相似物品集合。

(5)對相似物品集合中的物品,利用相似度分值排序,生成最終的推薦列表

在第5步中,若一物品與多個用戶歷史行爲中的正反饋相似,則該物品最終的相似度十多個相似度的累加,其中H是用戶正反饋物品集合,w_{p,h}是物品p與物品h的相似度,R_{u,h}是用戶u對物品h的已有評分。

       R_{u,p} = \sum_{h \in H}(w_{u,p}\cdot R_{u,h}) \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (5)

2.5 UserCF 與 ItemCF 的應用場景

UserCF基於用戶相似度,具有更強的社交性。非常適用於新聞推薦場景,因新聞本身的興趣點往往是分散的,相比用戶對不同新聞的興趣偏好,新聞的及時性、熱點性往往是更重要的,UserCF正適用於發現熱點,以及跟蹤熱點的趨勢。

ItemCF更適用於興趣變化比較穩定的應用,例如推薦商品,電影,電視劇等。

 2.6 協同過濾的下一步發展

協同過濾可解釋性強,但不具備強的泛化能力,協同過濾無法將兩個物品相似這一信息推廣到其他物品的相似性計算上,導致-熱門的商品頭部效應明顯,容易跟大量物品產生相似性;尾部物品特徵向量稀疏,很少與其他物品產生相似性,很少被推薦。簡言之,推薦結果的頭部效應明顯,處理稀疏向量能力弱。

舉個🌰,A、B和C之間的相似度爲0,與A、B和C都相似的物品均爲D,故在ItemCF下,D將會被推薦給所有對A、B和C有正反饋的用戶,實際上D與其餘物品相似僅是因爲D是一件熱門商品,無法找出A、B和C之間的相似度僅是因爲其特徵向量非常稀疏,缺乏相似性計算的直接數據。

         

爲解決上述問題,並提升泛化能力,矩陣分解技術被提出,該方法在協同過濾的基礎上,使用更稠密的隱向量表示用戶和物品,挖掘用戶和物品之間的隱含興趣和隱含特徵,在一定程度上彌補了協同過濾處理稀疏矩陣能力不足的問題。

另外,協同過濾僅利用了用戶和物品的交互信息,無法引入用戶年齡、性別、商品描述、當前時間等用戶特徵、物品特徵以及上下文特徵。爲了引入這些特徵,逐漸發展到以邏輯迴歸爲核心的、能夠綜合不同特徵的機器學習模型的道路上。

3 矩陣分解算法-協同過濾的進化

3.1 矩陣分解算法原理

       

協同過濾的推薦如(a)所示,基於用戶的歷史觀看,找到與目標用戶Joe看過同樣視頻的相似用戶,然後找到這些相似用戶喜歡看的其他視頻推薦給目標用戶Joe。矩陣分解算法則期望爲每一個用戶和視頻生成一個隱向量,將用戶和視頻定位到隱向量的表示空間上,距離相近的用戶和視頻表明特點接近,在推薦過程中,應把距離相近的視頻推薦給用戶,例如發現裏Dave的用戶向量最近的兩個視頻是Ocean's 11 和 The Lion King,可依據向量距離由近到遠的順序生成Dave的推薦列表。隱向量表達用戶和物品,還要保證相似的用戶及用戶可能喜歡的物品的距離相近,在矩陣分解的框架下,用戶和物品的隱向量是通過分解協同過濾生成的共現矩陣得到的。

      

矩陣分解算法將m*n維的共現矩陣\boldsymbol{R}分解爲m*k維的用戶矩陣\boldsymbol{U}和k*n維的物品矩陣\boldsymbol{V}相乘的形式。其中m是用戶數,n是物品數,k是隱向量的數量,k的大小決定了隱向量表達能力的強弱。k越小,隱向量包含的信息越少,模型泛化程度越高;反之,k越大,包含信息越多,泛化程度越低。此外,k取值還與求解複雜度直接相關。

基於用戶矩陣\boldsymbol{U}和物品矩陣\boldsymbol{V},用戶u對物品i的評估加分如下,其中\boldsymbol{p}_{u}是用戶u在用戶矩陣\boldsymbol{U}中的行向量,\boldsymbol{q}_{i}是物品i在物品矩陣\boldsymbol{V}中的列向量,簡言之,用戶u對物品i的評分即是用戶向量\boldsymbol{p}_{u}與物品向量\boldsymbol{q}_{i}的點積。

       \boldsymbol{\hat{r}}_{u,i}=\boldsymbol{q}_{i}^T\boldsymbol{p}_u \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (6)

3.2 矩陣分解的求解過程

三種常用的矩陣分解法:特徵值分解(Eigen Decomposition)、奇異值分解(Singular Value Decomposition,SVD)和梯度下降(Gradient Descent)。其中特徵值分解只能作用於方陣。

奇異值分解描述如下,之前有記錄過Matlab作SVD的過程https://blog.csdn.net/qq_xuanshuang/article/details/79639240

\boldsymbol{M}是n*m的矩陣,則必存在一個分解\boldsymbol{M} = \boldsymbol{U}\boldsymbol{\Sigma}\boldsymbol{V}^T,其中\boldsymbol{U}是m*m的正交陣,\boldsymbol{V}是n*n的正交陣,\boldsymbol{\Sigma}是m*n的對角陣。取\boldsymbol{\Sigma}中較大的k個與納素作爲隱含特徵,刪除\boldsymbol{\Sigma}的其他維度及\boldsymbol{U}\boldsymbol{V}中對應的維度,矩陣\boldsymbol{M}被分解爲\boldsymbol{M} \approx \boldsymbol{U}_{m\times k}\boldsymbol{\Sigma}_{k \times k}\boldsymbol{V}_{k \times n}^T

奇異值分解不適用於互聯網環境,(1):奇異值分解要求原始共現矩陣是稠密的;(2)傳統奇異值分解計算複雜度O(mn^2)

下面講述梯度分解,式(7)是求解矩陣分解的目標函數,其中K是所有用戶評分樣本的集合:

        \min_{\boldsymbol{q}^*,\boldsymbol{p}^*}\sum_{(u,i) \in K} (\boldsymbol{r}_{ui} - \boldsymbol{q}_i^T\boldsymbol{p}_u)^2 \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (7)

在式(7)的基礎上加上正則化項,以避免過擬合:

       \min_{\boldsymbol{q}^*,\boldsymbol{p}^*}\sum_{(u,i) \in K} (\boldsymbol{r}_{ui} - \boldsymbol{q}_i^T\boldsymbol{p}_u)^2 + \lambda (||\boldsymbol{q}_i||^2+||\boldsymbol{p}_u||^2)\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (8)

\boldsymbol{q}_{i}\boldsymbol{p}_{u}分別求偏導,得:

      \begin{aligned} &\boldsymbol{q}_i : 2(\boldsymbol{q}_i^T\boldsymbol{p}_u-\boldsymbol{r}_{ui}) \boldsymbol{p}_u- 2\lambda \boldsymbol{q}_i \\ &\boldsymbol{p}_u : 2(\boldsymbol{q}_i^T\boldsymbol{p}_u- \boldsymbol{r}_{ui}) \boldsymbol{q}_i- 2\lambda \boldsymbol{p}_u \end{aligned}

在矩陣分解中,由於隱向量的存在,是任意的用戶和物品之間都可以得到預測值,隱向量的生成過程其實是對共現矩陣進行全局擬合的過程,具有更強的泛化能力;而協同過濾,若兩個用戶沒有相同的歷史行爲,兩個物品沒有相同的人購買,則這倆用戶和倆物品相似度都將爲0。

下面附上python實現的矩陣分解:

代碼中R指原始的共現矩陣,U指用戶矩陣,V指物品矩陣,寫代碼的時候梯度(哪個矩陣在前,是否需轉置)可以用形狀來判斷,第一組🌰中,原始矩陣不含0元素,即均有值,我們可以看出當隱向量的維度是2的時候,誤差就很小,即預測值和原始值很接近;第二組🌰,原始矩陣中含有0元素,當隱向量維度比較小時(此處是2),預測出的矩陣在原矩陣爲0的地方也有值,誤差相對較大,當隱向量維度較大時(此處是5),預測出的矩陣與原矩陣很接近,原矩陣爲0的地方,預測的矩陣也近乎爲0,誤差相對較小。

import numpy as np


class MF:
    def __init__(self):
        self.U = None
        self.V = None

    def train(self, R, k, L2=None, l2_lambda = 0):
        def J(R, U, V, L2=None, l2_lambda=0.):
            j = 0.5 * np.sum((R - U.dot(V)) ** 2)
            if L2:
                j = 0.5 * l2_lambda * (np.sum(U.dot(U.T)) + np.sum(V.T.dot(V)))
            return j

        def gradient(R, U, V, L2=None, l2_lambda=0.):
            dV = U.T.dot(U.dot(V) - R)
            dU = (U.dot(V) - R).dot(V.T)
            if L2:
                dU = dU + l2_lambda * U
                dV = dV + l2_lambda * V
            return dU, dV

        U = np.random.random(size=(R.shape[0], k))
        V = np.random.random(size=(k, R.shape[1]))
        eps, n_iters, iter, lr = 1e-8, 5000, 0, 0.001
        while iter < n_iters:
            last_U, last_V = U, V
            dU, dV = gradient(R, U, V, L2, l2_lambda)
            U = U - lr * dU
            V = V - lr * dV
            if abs(J(R, last_U, last_V, L2, l2_lambda) - J(R, U, V, L2, l2_lambda)) < eps:
                break
            iter += 1
        self.U, self.V = U, V

    def predict(self):
        return self.U.dot(self.V)


if __name__ == "__main__":
    R = np.array([[1, 2, 3], [4, 5, 6], [0.1, 0.22, 0.31], [2, 4, 6]])
    mf = MF()
    mf.train(R, 2, "L2", 0.1)
    R_hat = mf.predict()
    print(R)
    print(mf.U)
    print(mf.V)
    print(R_hat)
    print(np.sum(R - R_hat) ** 2)

3.3 消除用戶和物品的打分偏差

引入全局偏差常數\mu(也可以學習),物品偏差係數b_i(可以使用物品i所獲得的評分的均值,也可以直接學習),用戶偏差係數b_u(可以使用用戶u給出的評分的均值,也可以直接學習)

       \boldsymbol{r}_{ui}=\mu + b_i + b_u + \boldsymbol{q}_i^T\boldsymbol{p}_u \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (9)

相應的目標函數改爲

      \min_{\boldsymbol{q}^*,\boldsymbol{p}^*,\boldsymbol{b}^*}\sum_{(u,i) \in K} (\boldsymbol{r}_{ui} -\mu - b_i - b_u - \boldsymbol{q}_i^T\boldsymbol{p}_u)^2 + \lambda (||\boldsymbol{q}_i||^2+||\boldsymbol{p}_u||^2 + b_i^2 +b_u^2 )\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (10)

加入用戶和物品的打分偏差項之後,矩陣分解得到的隱向量更能反應不同用戶對不同物品的“真實”態度的差異,也就更容易捕捉評價數據中有價值的信息,避免推薦結果有偏。

待解決:

書中說\mu是全局偏差常數,是否是一個定值的意思,還是可學習的?以及b_i,b_v是直接用均值替代,還是亦是可學習的。

附上代碼

這邊關於b_i,b_v,\mu的偏導,還是可以通過形狀來推,這邊借住了np.add.reduce_sum,但是不確定是不是可以這樣,不過在紙上舉過🌰,像b_i,b_v,\mu確實會出現多次,故求和應該也沒啥問題。

db_u = np.reshape(np.add.reduce(UdV, 1),newshape=(b_u.shape))
db_v = np.reshape(np.add.reduce(UdV, 0),newshape=(b_v.shape))
dmu = np.sum(UdV)
import numpy as np


class MF_bias:
    def __init__(self):
        self.U = None
        self.V = None
        self.b_u = None
        self.b_v = None
        self.mu = 0.

    def train(self, R, k, L2=None, l2_lambda = 0):
        def J(U, V, b_u, b_v, mu, L2=None, l2_lambda=0.):
            j = 0.5 * np.sum((R - U.dot(V) - mu - np.reshape(b_u, newshape=(U.shape[0],1))
                              - np.reshape(b_v, newshape=(1,V.shape[1]))) ** 2)
            if L2:
                j = 0.5 * l2_lambda * (np.sum(U.dot(U.T)) + np.sum(V.T.dot(V))
                                       + b_u.T.dot(b_u) + b_v.T.dot(b_v))
            return j

        def gradient(U, V, b_u, b_v, mu, L2=None, l2_lambda=0.):
            UdV = U.dot(V) + mu + np.reshape(b_u, newshape=(U.shape[0],1)) \
                  + np.reshape(b_v, newshape=(1,V.shape[1])) - R
            dV = U.T.dot(UdV)
            dU = (UdV).dot(V.T)
            db_u = np.reshape(np.add.reduce(UdV, 1),newshape=(b_u.shape))
            db_v = np.reshape(np.add.reduce(UdV, 0),newshape=(b_v.shape))
            dmu = np.sum(UdV)
            if L2:
                dU = dU + l2_lambda * U
                dV = dV + l2_lambda * V
                db_u = db_u + l2_lambda * b_u
                db_v = db_v + l2_lambda * b_v
            return dU, dV, db_u, db_v, dmu

        U = np.random.random(size=(R.shape[0], k))
        V = np.random.random(size=(k, R.shape[1]))
        b_u = np.zeros(shape=(R.shape[0]))
        b_v = np.zeros(shape=(R.shape[1]))
        # print(b_u, b_v)
        mu = 0.
        eps, n_iters, iter, lr = 1e-8, 5000, 0, 0.001
        while iter < n_iters:
            last_U, last_V,last_b_u, last_b_v, last_mu = U, V, b_u, b_v, mu
            dU, dV, db_u, db_v, dmu = gradient(U, V, b_u, b_v, mu, L2, l2_lambda)
            U = U - lr * dU
            V = V - lr * dV
            b_u = b_u - lr * db_u
            b_v = b_v - lr * db_v
            mu = mu - lr * dmu
            if iter % 1000 == 0:
                print(abs(J(last_U, last_V, last_b_u, last_b_v, last_mu, L2, l2_lambda)
                   - J(U, V, b_u, b_v, mu, L2, l2_lambda)),  J(U, V, b_u, b_v, mu, L2, l2_lambda))
            if abs(J(last_U, last_V, last_b_u, last_b_v, last_mu, L2, l2_lambda)
                   - J(U, V, b_u, b_v, mu, L2, l2_lambda)) < eps:
                break
            iter += 1
        self.U, self.V, self.b_u, self.b_v, self.mu = U, V, b_u, b_v, mu

    def predict(self):
        return self.U.dot(self.V) - np.reshape(self.b_u, newshape=(self.U.shape[0],1)) \
               - np.reshape(self.b_v, newshape=(1,self.V.shape[1])) - self.mu

if __name__ == "__main__":
    R = np.array([[1, 2, 3], [4, 5, 6], [0.1, 0.22, 0.31], [2, 4, 6]])
    mf = MF_bias()
    mf.train(R, 5)
    R_hat = mf.predict()
    print(R)
    print(mf.b_u)
    print(mf.b_v)

注:這邊的代碼沒有想到好的驗證正確性的方法,但是大概看出來沒啥太大問題,首先目標函數的值確實在減小,也確實達到一個較小的值,然後從兩個偏差係數的角度,用戶偏差係數也確實在在用戶打分偏高的時候偏大,在打分偏低的時候偏低;物品偏差係數同理。

3.4 矩陣分解的優點與侷限性

相比協同過濾,優點如下:

  1. 泛化能力強,一定程度緩解數據稀疏的問題
  2. 空間複雜度低,協同過濾需要存儲用戶相似度矩陣(m*m)或者物品相似度矩陣(n*n),矩陣分解只需存儲用戶和物品隱向量((n+m)*k)
  3. 更好的擴展性和靈活性,最終產出用戶和物品隱向量,與Embedding的思想不謀而合,故其便於與其他特徵進行組合和拼接,便於與深度學習網絡進行無縫結合。

與協同過濾一樣,無法引入用戶年齡、性別、商品描述、當前時間等用戶特徵、物品特徵以及上下文特徵。爲了引入這些特徵,逐漸發展到以邏輯迴歸爲核心的、能夠綜合不同特徵的機器學習模型的道路上。

4 邏輯迴歸

https://blog.csdn.net/qq_xuanshuang/article/details/104432710

相比於協同矩陣和矩陣分解利用用戶和物品的“相似度”進行推薦,logistic迴歸將推薦問題看成一個分類問題,通過預測正樣本的概率對物品進行排序,因此,邏輯迴歸模型將推薦問題轉換成了一個點擊率預估問題。

邏輯迴歸作爲廣義線性模型的一種,他的假設是因變量y服從伯努利分佈(線性迴歸的假設是因變量y服從高斯分佈)。

優點

  • 數學含義上的支撐,其假設是因變量y服從伯努利分佈,採用邏輯迴歸作爲CTR模型符合點擊這一事件的無力意義。
  • 可解釋性強,各特徵的加權和綜合了不同特徵對CTR的影響,不同特徵權重不同,代表不同特徵的重要程度。
  • 工程化的需要,易於並行,模型簡單,訓練開銷小

缺點

    表達能力不強,無法進行特徵交叉特徵篩選等一系列操作,爲解決這一問題,衍出了因子分解機等高維的複雜模型。

5 從FM到FFM-自動特徵交叉的解決方案

5.1 POLY2模型-特徵交叉的開始

POLY2模型的數學形式:

            \phi POLY2(\boldsymbol{w},\boldsymbol{x})=\sum_{j_1=1}^n\sum_{j_2=j_1+1}^n w_{h(j_1,j_2)}x_{j_1}x_{j_2} \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (11)

該模型對所有特徵進行了兩兩交叉(特徵x_{j_1}x_{j_2}),並對所有特徵組合賦予權重w_{h(j_1,j_2)},在一定程度上解決了特徵組合的問題,本質上仍是線性模型,訓練方法與邏輯迴歸無區別。

缺點

  • 互聯網數據的特徵原本就稀疏,無選擇的特徵交叉就使得特徵更加稀疏,導致大部分交叉特徵的權重缺乏有效的數據進行訓練,無法收斂。
  • 權重參數的數量由n直接上升到n^2((n*(n-1)/2),增加訓練複雜度

5.2 FM模型-隱向量特徵交叉

下面給出FM的數學形式,與POLY2相比,主要區別是用兩個向量內積(\boldsymbol{w}_{j_1} \cdot \boldsymbol{w}_{j_2})取代了單一權重係數w_{h(j_1,j_2)},具體來說,FM爲每個特徵學了一個隱權重向量,FM將矩陣分解的隱向量思想進行了進一步擴展,從單純的用戶、物品隱向量擴展到所有特徵上。

           y(x)=w_0 + \sum_{j_1=1}^nw_{j_1}x_{j_1}+ \sum_{j_1=1}^n\sum_{j_2=j_1+1}^n ( \boldsymbol{w}_{j_1}\cdot \boldsymbol{w}_{j_2})x_{j_1}x_{j_2} \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (12)

其中二階部分展開如下,自己不和自己交叉。

          \begin{aligned} \phi FM(\boldsymbol{w},\boldsymbol{x})&=\sum_{j_1=1}^n\sum_{j_2=j_1+1}^n ( \boldsymbol{w}_{j_1}\cdot \boldsymbol{w}_{j_2})x_{j_1}x_{j_2} \\ & = \frac{1}{2}\sum_{j_1=1}^{n}\sum_{j_2=1}^{n}( \boldsymbol{w}_{j_1}\cdot \boldsymbol{w}_{j_2})x_{j_1}x_{j_2} - \frac{1}{2}\sum_{j_1=1}^{n}( \boldsymbol{w}_{j_1}\cdot \boldsymbol{w}_{j_1})x_{j_1}x_{j_1} \\ &=\frac{1}{2}\sum_{j_1=1}^{n}\sum_{j_2=1}^{n}\sum_{f=1}^k v_{j_1,f} v_{j_2,f}x_{j_1}x_{j_2} - \frac{1}{2}\sum_{j_1=1}^{n}\sum_{f=1}^k ( v_{j1,f}v_{j_1,f})x_{j_1}x_{j_1} \\ &=\frac{1}{2}\sum_{f=1}^k((\sum_{j_1=1}^nv_{j_1,f}x_{j_1})(\sum_{j_2=1}^nv_{j_2,f}x_{j_2}) - \sum_{j_1=1}^nv_{j_1,f}^2x_{j_1}^2) \\ &=\frac{1}{2}\sum_{f=1}^k((\sum_{j_1=1}^nv_{j_1,f}x_{j_1})^2 - \sum_{j_1=1}^nv_{j_1,f}^2x_{j_1}^2) ) \ \end{aligned}

梯度:

           \frac{\partial y}{\partial \theta} =\left\{\begin{aligned} &1& &, \ if\ \theta\ is \ w_0\\ &x_{j_1}& &, \ if\ \theta\ is \ w_j_1 \\ &x_{j_1}\sum_{j_2=1}^nv_{j_2,f}x_{j_2} - v_{j_1,f}x_{j_1}^2& &, \ if\ \theta\ is \ v_{j_1,f} \end{aligned} \right.

由上式可知,v_{j_1,f}的訓練只需要樣本的x_{j_1}特徵非0即可,適合於稀疏數據,就能夠方便得到所有的v_{j_1,f}梯度,上述偏導結果求和公式中沒有j_1,即與j_1無關,只與f有關,顯然計算所有f\sum v_{j_2,f}x_{j_2}的複雜度是O(kn),模型參數一共有kn+n+1 個。

從式(12)可看,將POLY2模型的n^2級別的權重參數數量減少到了nk(k爲隱向量維度,n \gg k),從簡化式可看,FM將訓練複雜度從POLY2的n^2級別降低到了nk級別,同時隱向量的引入使FM能更好的解決數據稀疏性的問題,舉個🌰:有倆特徵頻道和品牌,某組合特徵是(ESPN,Adidas),在POLY2中,只有當ESPN和Adidas同時出現在一個訓練樣本中,模型才能學廚這個組合的權重;在FM中,ESPN的隱向量也可以通過(ESPN,Gucci)樣本更新,Adidas的隱向量也可以通過(NBC,Adidas)樣本更新,即使對於從未出現的特徵組合(NBC,Gucci),由於已經學習過NBC和Gucci的隱向量,具備了計算該特徵組合權重的能力。

相比POLY2,FM雖然丟失了某些具體特徵組合的精確記憶能力,但是提高了泛化能力,同樣可利用梯度下降法學習。

5.3 FFM模型-引入特徵域的概念

        y(x)=w_0 + \sum_{j_1=1}^nw_{j_1}x_{j_1}+ \sum_{j_1=1}^n\sum_{j_2=j_1+1}^n ( \boldsymbol{w}_{j_1,f2}\cdot \boldsymbol{w}_{j_2,f1})x_{j_1}x_{j_2} \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (13)

在FM模型的基礎上引入了特徵域感知這一概念,於FM的主要區別就是隱向量由之前的\boldsymbol{w}_{j_1}變爲了\boldsymbol{w}_{j_1,f_2},這意味着每個特徵對應的不是唯一一個隱向量而是一組隱向量,其中f_1是第j_11個特徵所屬的特徵域,在FFM模型的訓練過程中,需要學習n個特徵在f個域上的k維隱向量,參數數量共nfk個,由於域的引入,不能像FM模型那樣簡化,因此其複雜度是kn^2

5.4 從POLY2到FFM的模型演化過程

preview

POLY2模型直接學習每個交叉特徵的權重,權重數量共n^2個。

preview

FM模型學習每個特徵的k維隱向量,交叉特徵由相應特徵隱向量的內積得到,權重數量共n*k個。

preview

FFM模型引入了特徵域這一概念,在做特徵交叉時,每個特徵選擇與對方域對應的隱向量做內積運算得到交叉特徵的權重。參數數量共n*k*f個。

GBDT+LR——特徵工程模型化的開端

FFM模型採用引入特徵域的方式增強了模型的表達能力,但無論如何,FFM只能夠做二階的特徵交叉,如果要繼續提高特徵交叉的維度,不可避免的會發生組合爆炸和計算複雜度過高的情況。

6.1 GBDT+LR 組合模型的結構

可以利用GBDT自動進行特徵篩選和組合,進而生成新的離散特徵向量,再把該特徵向量當作LR模型輸入,預估CTR的模型結構。

          

用GBDT構建特徵工程,和利用LR預估CTR兩步是獨立訓練的。所以自然不存在如何將LR的梯度回傳到GBDT這類複雜的問題。

6.2  GBDT進行特徵轉換的過程

GBDT模型訓練好後,一個訓練樣本在輸入GBDT的某一子樹後,會依據每個節點的規則最終落入某一葉子節點,把該葉子節點置爲1,其他置爲0,所有葉子節點組成的向量即形成了該棵樹的特徵向量,把所有子樹的特徵向量連接起來,即形成了後續LR輸入的特徵向量。

          preview

舉個🌰,如上圖所示,GBDT由三顆子樹構成,每個子樹有4個葉子節點,一個訓練樣本進來後,先後落入“子樹1”的第3個葉節點中,那麼特徵向量就是[0,0,1,0],“子樹2”的第1個葉節點,特徵向量爲[1,0,0,0],“子樹3”的第4個葉節點,特徵向量爲[0,0,0,1],最後連接所有特徵向量,形成最終的特徵向量[0,0,1,0,1,0,0,0,0,0,0,1]。

決策樹的深度就決定了特徵交叉的維度。如果決策樹的深度爲4,通過三次節點分裂,最終的葉節點實際上是進行了3階特徵組合後的結果,如此強的特徵組合能力顯然是FM系的模型不具備的。但由於GBDT容易產生過擬合,以及GBDT這種特徵轉換方式實際上丟失了大量特徵的數值信息,因此我們不能簡單說GBDT由於特徵交叉的能力更強,效果就比FFM好,在模型的選擇和調試上,永遠都是多種因素綜合作用的結果。

6.3 GBDT+LR組合模型開啓的特徵工程新趨勢

GBDT+LR比FM重要的意義在於,它大大推進了特徵工程模型化這一重要趨勢,某種意義上來說,之後深度學習的各類網絡結構,以及embedding技術的應用,都是這一趨勢的延續。

7 LS-PLM - 阿里巴巴曾經的主流推薦模型

LS-PLM(大規模分段線性模型),又被稱爲MLR(混合邏輯迴歸),其結構與三層神經網絡極其相似。

7.1 LS-PLM 模型的主要結構

MLR可以看做是對LR的自然推廣,它LR的基礎上採用分而治之的思路,先對樣本進行分片,再在樣本分片中應用LR進行CTR預估。在LR的基礎上加入聚類的思想,其動機其實來源於對計算廣告領域樣本特點的觀察 。舉個🌰,如果CTR模型要預估的是女性受衆點擊女裝廣告的CTR,顯然我們並不希望把男性用戶點擊數碼類產品的樣本數據也考慮進來,因爲這樣的樣本不僅對於女性購買女裝這樣的廣告場景毫無相關性,甚至會在模型訓練過程中擾亂相關特徵的權重。爲了讓CTR模型對不同用戶羣體,不同用戶場景更有針對性,其實理想的方法是先對全量樣本進行聚類,再對每個分類施以LR模型進行CTR預估。MLR的實現思路就是由該動機產生的。

         f(x) = \sum_{i=1}^m\pi_i(x)\cdot \eta_i(x) = \sum_{i=1}^m\frac{e^{\mu_i\cdot x}}{\sum_{j=1}^m e^{\mu_j\cdot x}} \cdot \frac{1}{1+e^{-w_i\cdot x}} \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (14)

MLR目標函數的數學形式如上,首先用聚類函數π對樣本進行分類(這裏的π採用了softmax函數,對樣本進行多分類),再用LR模型計算樣本在分片中具體的CTR,然後將二者進行相乘後加和。其中超參數分片數m可以較好地平衡模型的擬合與推廣能力。當m=1時MLR就退化爲普通的LR,m越大模型的擬合能力越強,但是模型參數規模隨m線性增長,相應所需的訓練樣本也隨之增長。

7.2 LS-PLM模型的優點

  1. 端到端的非線性學習:從模型端自動挖掘數據中蘊藏的非線性模式,省去了人工特徵設計,這使得MLR算法可以端到端地完成訓練,在不同場景中的遷移和應用非常輕鬆。
  2. 稀疏性:MLR在建模時引入了L1和L2,1範數,可以使得最終訓練出來的模型具有較高的稀疏度,模型的學習和在線預測性能更好。

7.3 從深度學習的角度重新審視LS-PLM模型

LS-PLM可以看作加入了注意力機制的三層神經網絡模型,輸入層:樣本的特徵向量;中間層:m個神經元組成的隱層;輸出層:對CTR預估來說,輸出層是單一神經元。注意力機制:在隱層和輸出層之間,神經元之間的權重由分片函數得出的注意力得分來確定,即樣本屬於哪個分片的概率就是其注意力得分,即式(14)中的\pi_i(x)

8 總結

 

參考:深度學習推薦系統,王喆

            王喆知乎的帖子 https://zhuanlan.zhihu.com/p/61154299

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