梯度下降的矩阵分解公式推导与实例分析

注:此博客只是作者在学习的过程中的一些记录和浅疏的理解,内容多为借鉴和自己的一些总结。

当我们了解和学习过梯度下降之后,对于矩阵分解的学习会更直接易懂。
矩阵分解就是将一个大的矩阵分解成两个行对应列相等的两个小矩阵,用两个小的矩阵去预测大的矩阵的取值通。俗来说就是矩阵相乘的逆运算。在这里我们还要借用损失函数,构造损失函数(loss function)。接下来让我们看一些例子和相关理论介绍。

一,基于矩阵分解的推荐算法相关理论介绍

如图1,是一个用户对物品的评分距图

深度学习求矩阵的梯度 矩阵分解梯度下降推导_损失函数


U1,2,3,4,5表示五个用户,D1,2,3,4表示四个不同的物品,表中的数据表示用户对物品的打分 评价。- 则表示没有打分。现在我们的目的就是把这些没有打分的通过方法预测出来。这也是矩阵分解的主要内容。

那我们该如何预测这些数值呢?

对于缺失的评分,可以转化为基于机器学习的回归问题,也就是连续值的预测。

对于矩阵分解有如下式子,假设R是图1的评分矩阵,N深度学习求矩阵的梯度 矩阵分解梯度下降推导_矩阵分解_02M维度(N为行,M为列),我们可以将其分解为用户-特性矩阵P,以及物品-特性矩阵Q。其中P矩阵维度N深度学习求矩阵的梯度 矩阵分解梯度下降推导_矩阵分解_02K,Q矩阵维度M深度学习求矩阵的梯度 矩阵分解梯度下降推导_矩阵分解_02K。所以我们可以得到式子1

深度学习求矩阵的梯度 矩阵分解梯度下降推导_深度学习求矩阵的梯度_05


其中Q深度学习求矩阵的梯度 矩阵分解梯度下降推导_深度学习求矩阵的梯度_06是对Q矩阵进行转置,便于矩阵之间的计算。

二,对于P,Q矩阵的解释

P矩阵是N个用户对K个主题的关系,Q矩阵是K个主题跟M个物品的关系,这里K是我们引入的一个参数,在这里不予讨论。在算法里面K是一个参数,需要调节,通常是10~100之间。

然后我们便可以通过公式得到我们想要的那些预测值。

深度学习求矩阵的梯度 矩阵分解梯度下降推导_损失函数_07


式子2的左边深度学习求矩阵的梯度 矩阵分解梯度下降推导_损失函数_08表示的是深度学习求矩阵的梯度 矩阵分解梯度下降推导_矩阵分解_09

三,构造损失函数

所以,这里我们又用到了损失函数来判断两者的相对误差大小。如式子3:

深度学习求矩阵的梯度 矩阵分解梯度下降推导_深度学习求矩阵的梯度_10


构造完损失函数,我们便可以运用梯度下降里面的知识对两个参数进行不断地迭代,更新P和Q的值。

深度学习求矩阵的梯度 矩阵分解梯度下降推导_迭代_11

P,Q矩阵求出来以后,对于每个用户i对商品j的评价就是:
p(i,1)*q(1,j)+p(i,2)*q(2,j)+…+p(i,k)*q(k,j)。

一般的为了防止过拟合问题,会对上述式子4加入正则化运算。
四,算法终止

每次更新完深度学习求矩阵的梯度 矩阵分解梯度下降推导_矩阵分解_09后,计算一次loss值,若loss值非常小或者到达最大迭代次数,结束算法。于是就得到了我们最终的预测矩阵深度学习求矩阵的梯度 矩阵分解梯度下降推导_矩阵分解_09

五,手工实例

深度学习求矩阵的梯度 矩阵分解梯度下降推导_迭代_14


深度学习求矩阵的梯度 矩阵分解梯度下降推导_损失函数_15


六,代码实现

import numpy as np
import math
import matplotlib.pyplot as plt


#定义矩阵分解函数
def Matrix_decomposition(R, P, Q, N, M, K, alpha=0.0002, beta=0.02):
    Q = Q.T  # Q矩阵转置
    loss_list = []  # 存储每次迭代计算的loss值
    for step in range(5000):
        # 更新$\hat{R}$
        for i in range(N):
            for j in range(M):
                if R[i][j] != 0:
                    # 计算损失函数
                    error = R[i][j]
                    for k in range(K):
                        error -= P[i][k] * Q[k][j]
                    # 优化P,Q矩阵的元素
                    for k in range(K):
                        P[i][k] = P[i][k] + alpha * (2 * error * Q[k][j] - beta * P[i][k])
                        Q[k][j] = Q[k][j] + alpha * (2 * error * P[i][k] - beta * Q[k][j])

        loss = 0.0
        # 计算每一次迭代后的loss大小,就是原来R矩阵里面每个非缺失值跟预测值的平方损失
        for i in range(N):
            for j in range(M):
                if R[i][j] != 0:
                    # 计算loss公式加号的左边
                    data = 0
                    for k in range(K):
                        data = data + P[i][k] * Q[k][j]
                    loss = loss + math.pow(R[i][j] - data, 2)
                    # 得到完整loss值
                    for k in range(K):
                        loss = loss + beta / 2 * (P[i][k] * P[i][k] + Q[k][j] * Q[k][j])
                    loss_list.append(loss)
        plt.scatter(step, loss)
        # 输出loss值
        if (step + 1) % 1000 == 0:
            print("loss={:}".format(loss))
        # 判断
        if loss < 0.001:
            print(loss)
            break
    plt.show()
    return P, Q


if __name__ == "__main__":
    N = 5
    M = 4
    K = 5
    R = np.array([[4, 0, 3, 5],
                  [0, 5, 4, 0],
                  [5, 4, 2, 0],
                  [2, 4, 0, 3],
                  [3, 4, 5, 0]])  # N=5,M=4
    print("初始评分矩阵:")
    print(R)
    # 定义P和Q矩阵
    P = np.random.rand(N, K)  # N=5,K=2
    Q = np.random.rand(M, K)  # M=4,K=2
    print("开始矩阵分解:")
    P, Q = Matrix_decomposition(R, P, Q, N, M, K)
    print("矩阵分解结束。")
    print("得到的预测矩阵:")
print(np.dot(P, Q))