梯度下降算法详解及案例 - 小毅哥哥Bob

时间:2024-03-08 11:51:15

梯度下降算法详解及案例

1.梯度的定义

  • 在单变量的函数中,梯度其实就是函数的微分,代表着函数在某个给定点的切线的斜率
  • 在多变量函数中,梯度是一个向量,向量有方向,梯度的方向就指出了函数在给定点的上升最快的方向

2.梯度下降算法

  迭代寻找下一个点Xi+1,使得f(Xi+1)<=f(Xi),直到 下降的速率为0或者接近零。

3.梯度算法的适用范围

 

  涉及到函数的的最大值与最小值问题都可以求解。

因此判断一个问题能否用“梯度”来解决,就是看这个问题能否转化为“函数最大值和最小值问题求解

4.梯度下降算法的实现(Python)

问题:用梯度下降算法拟合一条直线

分析:拟合点集合的本质就是使这些点尽可能的在这条直线上或者尽可能靠近这些直线,所以评判一条拟合线是否合格,可以通过“均方误差代价函数”来评判,即,该拟合线上的点与该点的真实值要

的差要最小。可以用下面的 公式来解释:

 

此公示中

  • m是数据集中点的个数
  • ½是一个常量,这样是为了在求梯度的时候,二次方乘下来就和这里的½抵消了,自然就没有多余的常数系数,方便后续的计算,同时对结果不会有影响
  • y 是数据集中每个点的真实y坐标的值
  • h 是我们的预测函数,根据每一个输入x,根据Θ 计算得到预测的y值

所以这个问题就转化成:求θ,使得J(θ)的最小值。

其中,θ=[θ01]是一个向量。

我们可以根据代价函数看到,代价函数中的变量有两个,所以是一个多变量的梯度下降问题,求解出代价函数的梯度,也就是分别对两个变量进行微分

 

 
为了便于计算和编程,我们可以将上述的公式转化为矩阵的公式,进而可以利用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阶单位矩阵