【机器学习】梯度下降与矩阵分解

在正式讲解之前,需要提前了解一些预备知识

【预备知识】

偏导数

偏导数虽然和导数只有一字之差,但是却相差甚多,从它们的定义来看,偏导数是指对含有两个自变量的函数中的一个自变量求导,也就是说偏导数要求函数必须具备两个自变量。比如拿 z=f(x,y) 举例,如果只有自变量x变化,而自变量y固定(即看作常量),这时它就是x的一元函数,这函数对x的导数,就称为二元函数z对于x的偏导数,记做 fx(x,y) 。

有如下函数 z = x2 + 3xy + y2,分别求 z 对于 x 、y 的偏导数。如下所示:

fx(x,y) = 2x + 3y # 关于 x 的偏导数
fy(x,y) = 3x + 2y # 关于 y 的偏导数

当求 x 的偏导时就要把 y 当做常数项来对待,而当求 y 的偏导时就要把 x 当做常数项对待。关于偏导数还会涉及到高阶偏,如果感兴趣的话可以点击了解一下。

方向导数

偏导数反映的是函数沿坐标轴方向的变化率,而方向导数是研究函数沿任一指定方向的变化率问题。关于方向导数的存在及计算,我们有以下 定理 :如果函数 在点可微分,那么函数在该点沿任一方 向l的方向导数存在,且有

 

 

其 中 cos α 和 cos β 是方向 l的方向余弦.

梯度

与方向导数有关联的一个概念是函数的梯度. 在二元函数的情形,设函数在平面区域D内具有一阶连续偏导数,则对于每一点,都 可定出一个向量 

这向量称为函数f(x,y)在点 P。(x。,y。)的梯度,记作 grad f(x。,y。)或,即 

 【机器学习】梯度下降与矩阵分解_第1张图片

 这一关系式表明了函数在一点的梯度与函数在这点的方向导数间的关系,特别的,由这关系可知

【机器学习】梯度下降与矩阵分解_第2张图片

 

假设函数

假设函数(Hypothesis Function)可表述为y=f(x)其中 x 表示输入数据,而 y 表示输出的预测结果,而这个结果需要不断的优化才会达到预期的结果,否则会与实际值偏差较大。

由此我们知道假设函数是用来预测结果的。函数表达式如下所示:

假设函数


乍一看你可能蒙圈了,记住不用紧张。其实它和 Y=wX + b 是类似的,只不过我们这个标量公式换成了向量的形式。我们可以这样理解,Y1仍然代表预测结果, X1表示数据样本, b表示用来调整预测结果的“偏差度量值”,而wT表示权值系数的转置。矩阵相乘法是一个求两个向量点积的过程,也就是按位相乘,然后求和,如下所示:

【机器学习】梯度下降与矩阵分解_第3张图片 

 矩阵 A 的每一行分别与矩阵 B 的每一列相乘,比如 1*5+2*5+3*7 =36 、1*2+2*6+3*6=32、1*6+2*7+3*4=32,即可得出结果的第一行数据。

转置操作的目的是为了保证第一个矩阵的列数(column)和第二个矩阵的行数(row)相同,只有这样才能做矩阵乘法运算。

您也可以将假设函数写成关于 x 的函述表达式,如下所示:
 

假设函数

损失函数

损失函数(Loss Function)又叫目标函数,简写为 L(x),这里的 x 是假设函数得出的预测结果“y”,如果 L(x) 的返回值越大就表示预测结果与实际偏差越大,越小则证明预测值越来越“逼近”真实值,这才是机器学习最终的目的。因此损失函数就像一个度量尺,让你知道“假设函数”预测结果的优劣,从而做出相应的优化策略。

我们知道,在线性回归模型中数据样本散落在线性方程的周围,如下图所示:
 

【机器学习】梯度下降与矩阵分解_第4张图片


图2:线性回归模型


损失函数就像一个衡量尺,这个函数的返回值越大就表示预测结果与真实值偏差越大。其实计算单个样本的误差值非常简单,只需用预测值减去真实值即可:

单样本误差值 = Y1 - Y 

但是上述方法只适用于二维平面的直线方程。在线性方程中,要更加复杂、严谨一些,因此我们采用数学中的“均方误差”公式来计算单样本误差:
 

损失函数


公式是求“距离”因此要使用平方来消除负数,分母 2 代表样本的数量,这样就求得单样本误差值。当我们知道了单样本误差,那么总样本误差就非常好计算了:
 

损失函数

最后,将假设函数带入上述损失函数就会得到一个关于 w 与 b 的损失函数(loss),如下所示:
 

损失函数


 

在机器学习中使用损失函数的目的,是为了使用“优化方法”来求得最小的损失值,这样才能使预测值最逼近真实值。

在上述函数中 n、Y、X1 都是已知的,因此只需找到一组 w 与 b 使得上述函数取得最小值即可,这就转变成了数学上二次函数求极值的问题,而这个求极值的过程也就我们所说的“优化方法”。

【正式开讲】

 梯度下降

梯度下降是机器学习中常用的一种优化方法,主要用来解决求极小值的问题,某个函数在某点的梯度指向该函数取得最大值的方向,那么它的反反向自然就是取得最小值的方向。

梯度是微积分学的术语,它本质上是一个向量,表示函数在某一点处的方向导数上沿着特定的方向取得最大值,即函数在该点处沿着该方向变化最快,变化率最大。梯度下降法的计算过程就是沿梯度方向求解极小值,当然你也可以沿梯度上升的方向求解极大值。

那么如何能够更好的理解“梯度下降”呢?如果不考虑其他外在因素,其实你可以把它想象成“下山”的场景,如何从一个高山上以最快的时间走到山脚下呢?其实很简单,以你所在的当前位置为基准,寻找该位置最陡峭的地方,然后沿着此方向向下走,并且每走一段距离,都要寻找当前位置“最陡峭的地方”,反复采用上述方法,最终就能以最快的时间抵达山脚下。

在这个下山的过程中,“寻找所处位置最陡峭的地方,并沿此位置向下走”最为关键,如果把这个做法对应到函数中,就是找到“给定点的梯度”而梯度的方向就是函数值变化最快的方向。

【机器学习】梯度下降与矩阵分解_第5张图片 示意图

从上述描述中,你可能感觉到平淡无奇,其实每一个词语都蕴含着数学知识,比如“以当前所在位置为基准,找到最陡峭的地方”从数学角度来讲就是找到所在点的“切线”方向,也就是对这点“求导”,然后循着切线轨迹点反复使用此方法,就可以到达极小值点。

在【预备知识】中我们讲解了线性回归的损失函数,而梯度下降作为一种优化方法,其目的是要使得损失值最小。因此“梯度下降”就需要控制损失函数的wb参数来找到最小值。比如控制 w 就会得到如下方法:

w新=w旧 - 学习率 * 损失值

通过梯度下降计算极小值时,需要对损失函数的w求偏导求得,这个偏导也就是“梯度”,通过损失值来调节w,不断缩小损失值直到最小,这也正是梯度下降的得名来由。

“学习率”是一个由外部输入的参数,被称为“超参数”,可以形象地把它理解为下山时走的“步长”大小,想要 w 多调整一点,就把学习率调高一点。不过学习率也不是越高越好,过高的学习率可能导致调整幅度过大,导致无法求得真正的最小值。当损失函数取得极小值时,此时的参数值被称为“最优参数”。因此,在机器学习中最重要的一点就是寻找“最优参数”。

   【求解过程】:
      1.设出两个较小的正数s,b       s代表步长(学习率),b代表非常小的常数阈值;

      2.求当前位置的偏导数:

       ▽f(x)=f'(x);▽f(x,y)=(∂f/∂x, ∂f/∂y)T          (x=0....n)

      3.修改函数的参数值:

        X1=x-s*▽

       参数值为函数的梯度与步长的乘积的绝对值。

       4.如果修改后的参数值小于b,则此时的参数值就是求得最小值;否则回到步骤2,此时x=x-X0。

    一般情况下,梯度向量为0的时候就是一个极值点,此时梯度的幅值也为0。梯度下降算法迭代结束的条件是幅值接近0,故刚开始可以设置一个较小的阈值。

矩阵分解

矩阵分解就是把一个矩阵近视变成若干个小矩阵相乘的形式。

例如

有如下R(5,4)的打分矩阵:(“-”表示用户没有打分)

其中打分矩阵R(n,m)是n行和m列,n表示user个数,m行表示item个数

【机器学习】梯度下降与矩阵分解_第6张图片
 

那么,如何根据目前的矩阵R(5,4)如何对未打分的商品进行评分的预测(如何得到分值为0的用户的打分值)?

——矩阵分解的思想可以解决这个问题,其实这种思想可以看作是有监督的机器学习问题(回归问题)。

矩阵R可以近似表示为P与Q的乘积:R(n,m)≈ P(n,K)*Q(K,m)

矩阵分解的过程中,将原始的评分矩阵

分解成两个矩阵的乘积: 

矩阵P(n,K)表示n个user和K个特征之间的关系矩阵,这K个特征是一个中间变量,矩阵Q(K,m)的转置是矩阵Q(m,K),矩阵Q(m,K)表示m个item和K个特征之间的关系矩阵,这里的K值是自己控制的,可以使用交叉验证的方法获得最佳的K值。为了得到近似的R(n,m),必须求出矩阵P和Q,如何求它们呢?

 【机器学习】梯度下降与矩阵分解_第7张图片

【代码实现】

import matplotlib.pyplot as plt
from math import pow
import numpy
def matrix_factorization(R,P,Q,K,steps=5000,alpha=0.0002,beta=0.02):
    Q=Q.T  # .T操作表示矩阵的转置
    result=[]
    for step in range(steps):
        for i in range(len(R)):
            for j in range(len(R[i])):
                if R[i][j]>0:
                    eij=R[i][j]-numpy.dot(P[i,:],Q[:,j]) # .dot(P,Q) 表示矩阵内积
                    for k in range(K):
                        P[i][k]=P[i][k]+alpha*(2*eij*Q[k][j]-beta*P[i][k])
                        Q[k][j]=Q[k][j]+alpha*(2*eij*P[i][k]-beta*Q[k][j])
        eR=numpy.dot(P,Q)
        e=0
        for i in range(len(R)):
            for j in range(len(R[i])):
                if R[i][j]>0:
                    e=e+pow(R[i][j]-numpy.dot(P[i,:],Q[:,j]),2)
                    for k in range(K):
                        e=e+(beta/2)*(pow(P[i][k],2)+pow(Q[k][j],2))
        result.append(e)
        if e<0.001:
            break
    return P,Q.T,result
 
if __name__ == '__main__':
    R=[
        [5,3,0,2],
        [4,0,0,1],
        [1,1,0,5],
        [1,0,1,4],
        [0,1,5,4]
    ]
    R=numpy.array(R)
    N=len(R)
    M=len(R[0])
    K=2
 
    P=numpy.random.rand(N,K) #随机生成一个 N行 K列的矩阵
    Q=numpy.random.rand(M,K) #随机生成一个 M行 K列的矩阵
 
    nP,nQ,result=matrix_factorization(R,P,Q,K)
    print("原始的评分矩阵R为:\n",R)
    R_MF=numpy.dot(nP,nQ.T)
    print("经过MF算法填充0处评分值后的评分矩阵R_MF为:\n",R_MF)

你可能感兴趣的:(机器学习,机器学习,矩阵,逻辑回归,人工智能)