梯度下降算法详解及案例
1.梯度的定义
- 在单变量的函数中,梯度其实就是函数的微分,代表着函数在某个给定点的切线的斜率
- 在多变量函数中,梯度是一个向量,向量有方向,梯度的方向就指出了函数在给定点的上升最快的方向
2.梯度下降算法
迭代寻找下一个点Xi+1,使得f(Xi+1)<=f(Xi),直到 下降的速率为0或者接近零。
3.梯度算法的适用范围
涉及到函数的的最大值与最小值问题都可以求解。
因此判断一个问题能否用“梯度”来解决,就是看这个问题能否转化为“函数最大值和最小值问题求解”
此公示中
- m是数据集中点的个数
- ½是一个常量,这样是为了在求梯度的时候,二次方乘下来就和这里的½抵消了,自然就没有多余的常数系数,方便后续的计算,同时对结果不会有影响
- y 是数据集中每个点的真实y坐标的值
-
h 是我们的预测函数,根据每一个输入x,根据Θ 计算得到预测的y值
所以这个问题就转化成:求θ,使得J(θ)的最小值。
其中,θ=[θ0,θ1]是一个向量。
我们可以根据代价函数看到,代价函数中的变量有两个,所以是一个多变量的梯度下降问题,求解出代价函数的梯度,也就是分别对两个变量进行微分
为了便于计算和编程,我们可以将上述的公式转化为矩阵的公式,进而可以利用numpy包进行编程和运算
其中:X是一个m行2列的矩阵,表示每个数据点,每个点由两个元素(维度)表示,其第一列都为1,第二列为点的横坐标。
Y:点的横坐标值所构成的向量
代码部分:
import numpy as np from matplotlib import pyplot as plt def error_function(theta,X,Y): \'\'\' 代价函数的实现 Parameters: theda - 拟合曲线的参数 X - m行n列的矩阵,m个样本点,每个点由n维元素表示。代价函数自变量 Y - m行1列的矩阵,代价函数值 Returns: 返回代价函数值 \'\'\' diff=np.dot(X,theta)-Y return (1./2*m)*np.dot(np.transpose(diff),diff) def gradient_function(theta,X,Y): \'\'\' Parameters: theda - 拟合曲线的参数 X - m行n列的矩阵,m个样本点,每个点由n维元素表示。代价函数自变量 Y - m行1列的矩阵,函数的真实值 Returns: 返回梯度值 \'\'\' diff = np.dot(X, theta)-Y return (1./m)*np.dot(np.transpose(X),diff) def gradient_descent(X,Y,alpha): \'\'\' Parameters: X - m行n列的矩阵,m个样本点,每个点由n维元素表示。代价函数自变量 Y - m行1列的矩阵,函数的真实值 alpha - 学习率 Returns: 返回theda值 \'\'\' theda=np.array([1,1]).reshape(2,1) gradient = gradient_function(theda,X,Y) while not (np.all(np.absolute(gradient) <= 1e-5 )): theda=theda-alpha*gradient gradient = gradient_function(theda, X, Y) return theda #测试代码 #定义点的个数 m=20 #定义X矩阵 x0=np.ones((m,1)) x1=np.arange(1,m+1).reshape(m,1) X=np.hstack((x0,x1)) #定义Y矩阵 Y = np.array([3, 4, 5, 5, 2, 4, 7, 8, 11, 8, 12,11, 13, 13, 16, 17, 18, 17, 19, 21]).reshape(m, 1) #给定学习率 alpha=0.01 theda_result=gradient_descent(X,Y,alpha) print("theta的值是:", theda_result) print("代价函数值是:", error_function(theda_result,X,Y)) #做出拟合图像 Xa=np.linspace(1,20,20) Ya=theda_result[0]+theda_result[1]*Xa plt.plot(Xa,Ya) plt.plot(Xa,Y,\'ro\') plt.show()
最后的拟合结果为:
总结
多样本点的问题,要学会使用矩阵的这个工具。若能转化为矩阵问题,则用numpy能大大地简化代码,和提高运算速度。
问题的转化。
关于上面程序中所用到的numpy知识点
- np.hstack(x,y) 将x和y向量左往右拼接。
- 生成ndarray的方式
1.np.array([1,2,3]) #将列表转化为数组 2.np.arange(start,stop,[step]) start~stop-1 3.np.zeros([m,n]) np.ones([m,n]) np.eye(m) #生成m阶单位矩阵