人工智能—梯度下降
**
1. 梯度下降
2. 矩阵分解
**
**
1. 梯度下降
**
梯度的理解
如果函数为一元函数,梯度就是该函数的导数。
如果为二元函数,梯度定义为:
关于梯度下降最常见的就是下山问题。如图所示:
想一想他怎么可以快速到达山下呢?
不难看出他的速度取决于山的坡度和他自身的步长。即坡度要大步长要长(坡度即该点的斜率)。
该人下降的距离可表示为步长*坡度(斜率)
可用数学公式表示
其中η称为步长,也叫学习率。
对于η的取值非常重要,既不能太大,也不能太小。
1.η如果过大,即移动的步长太大,很有直接几步就蹦出去了,导致无法收敛。如图所示:
2.η也不能太小,如果步长太小,迭代所用的时间就会很长。如图所示:
再来讲一下为什么是负梯度
梯度下降使用负梯度的原因
首先先看一张图片
从这张图片不难看出,当两个向量的夹角最小时(即α=0º时,cosα=1),此时两个向量乘积最大。当两向量夹角最大时(即α=180º时,cosα=-1)此时两个向量乘积最小,此时梯度下降的最快,即负梯度方向是函数值下降最快的方向。梯度下降求解方法
1.首先要设出步长η跟一个较小的常数阈值ε
2.计算出当前点的偏导数
3.修正当前函数的参数值
4.将修正后的参数值与ε值进行比较,如果修正后的参数值小于ε
我们就认为当前的参数值就是我们要求得的。
举例
y=x^2-2*x
设出发点为-4,η为0.9
在这里插入代码片
def f(x):
return 2*x-2
x=-4
a=0.9
b=0.01
while True:
x1=f(x)*a
if x1<0:
x1=-x1
x=x+x1
else:
x=x-x1
if x1<b:
break
print(x)
print("函数最小值",x*x-2*x)
运行结果
5.0
-2.2
3.5600000000000005
-1.048000000000001
2.6384000000000007
-0.3107200000000008
2.0485760000000006
0.16113919999999937
1.6710886400000005
0.46312908799999963
1.4294967296000003
0.6564026163199997
1.2748779069440004
0.7800976744447996
1.1759218604441604
0.8592625116446717
1.1125899906842627
0.9099280074525898
1.0720575940379282
0.9423539247696574
1.046116860184274
0.9631065118525808
1.0295147905179354
0.9763881675856517
1.0188894659314787
0.9848884272548171
1.0120892581961463
0.990328593443083
1.0077371252455336
0.9938102998035732
1.0049517601571414
函数最小值 -0.9999843072456616**
2.矩阵分解
**
简单理解 矩阵R可以近似表示为矩阵P与矩阵Q的乘积形式:R(n,m)≈ P(n,K)*Q(K,m)(线性代数中矩阵的乘法),原始矩阵R中并不是所有的元素都有值,而分解后的矩阵P和Q是都有元素值的。用该方法来预测原始矩阵中本来没有的值。
矩阵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。
求解方法
- 首先令
- 损失函数:使用原始的评分矩阵与构建的评分矩阵之间的差值的平方作为损失函数,即:
如果R(i,j)已知,则R(i,j)的误差平方和为: - 最终,需要求解所有的非“-”项的损失之和的最小值:
- 使用梯度下降法获得修正的p和q分量:
求解损失函数的负梯度:
根据负梯度的方向更新变量:
- 不停迭代直到算法最终收敛(直到sum(e^2) <=阈值)
代码实现
在这里插入代码片
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,1],
[3,0,0,1,3],
[1,2,0,5,4],
[1,0,1,4,4],
[0,1,3,4,3]
]
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)
原始的评分矩阵R为:
[[5 3 0 2 1]
[3 0 0 1 3]
[1 2 0 5 4]
[1 0 1 4 4]
[0 1 3 4 3]]
经过MF算法填充0处评分值后的评分矩阵R_MF为:
[[5.05183296 2.63085678 4.35716635 1.63733513 1.49949403]
[2.93044533 1.73496198 2.68527509 2.04011963 1.84974306]
[1.19951378 1.46882391 1.67228882 4.7954792 4.31648499]
[0.80026714 1.16437523 1.25501615 4.16215574 3.74508732]
[2.60550057 1.88225388 2.6441252 3.58709945 3.23826189]]