利用梯度下降法求解函数最小值

在我的上一篇博客给大家从原理上讲述了一下梯度下降法,在这一篇博文里,我就用python代码底层实现利用梯度下降法求解函数的最值问题。以二次函数为例,方便大家理解!
首先我们需要自己创建一些数据:

import numpy as np
import matplotlib.pyplot as plt
plot_x=np.linspace(-1,6,141)   #在-1到6之间等距的生成141个数
plot_y=(plot_x-2.5)**2+3	   # 同时根据plot_x来生成plot_y

由上一段代码可以知道,我们生成了一些二次符合函数y=(x-2.5)²+3的一些点,我们可以用python的matplotlib来绘制一下这个函数图像。

plt.plot(plot_x,plot_y)
plt.show()

利用梯度下降法求解函数最小值_第1张图片
在二次函数中,梯度就是导数的意思,所以我们就需要定义一个求导数的函数和一个求函数值的函数。

###定义一个求二次函数导数的函数dJ
def dJ(x):
    return 2*(x-2.5)

###定义一个求函数值的函数J
def J(x):
    try:
        return (x-2.5)**2+3
    except:
        return float('inf')

定义好了这两个函数后,我们就开始写梯度下降法的代码。

x=0.0							#随机选取一个起始点
eta=0.1						    #学习率
epsilon=1e-8				    #用来判断是否到达二次函数的最小值点的条件
history_x=[x]                   #用来记录使用梯度下降法走过的点的X坐标
while True:
    gradient=dJ(x)				#梯度(导数)
    last_x=x
    x=x-eta*gradient
    history_x.append(x)
    if (abs(J(last_x)-J(x)) 

在上一段编写梯度下降法的代码中,x是随机选取的一个点的x坐标,在这里我选取的是x=0.0。eta是学习率,用来控制步长的大小,经验上来讲设置其值为0.1比较好。在上一篇博文说过,梯度的方向对应着函数增大的方向,而我们是要寻找二次函数的最小值,所以我们就要一直往函数减小的方向走。梯度下降法其实也就是将x的值一步步往函数值减小的方向走,往函数的最低点逼近。函数减小的方向也就是梯度的反方向,及导数乘以 -1 。 那么 x=x-eta*gradient这句代码就好理解了,意思是x的值减小eta*gradient这么多个单位,大家注意哦!这个gradient是带有正负号的哦,当gradient小于0时,x的值就增大了,因为此时导数小于0,函数就往x的负方向增大,即往x的左边增大,那我们自然要往x右边走啦。我们一般称eta*gradient为步长,eta的作用就是来控制步长的,当eta比较小,x减小的幅度也就越小。那我们什么时候判断是否到达最低点了,那就是if语句中代码的作用了。当while循环中上一个x对应的函数值和此时x对应的函数值的差的绝对值小于一个很小的接近于0的值,那就说明函数值已经很难再减小了,我们就认为此时的x就是最低点对应的横坐标。history_x是一个列表,保存了到达最低点过程中的所走过的x的值。那我们在通过绘制代码绘制一下x
的轨迹。

print(history_x)	        #打印到达最低点时x的值
plt.plot(plot_x,plot_y)     
plt.plot(np.array(history_x),J(np.array(history_x)),color='r',marker='*')   #绘制x的轨迹
plt.show()

利用梯度下降法求解函数最小值_第2张图片

由图可以知道,从x=0.0开始,当向最低点逼近的过程中,x的轨迹越来越密集。这是因为向最低点靠近的过程中,x的导数值越来越小,导致x减小的幅度越来越小,所以轨迹会越来越密集,最后停在最低点。根据图中的数据我们也可以知道x具体取了哪些值。
在这里只是利用梯度下降法解决了二维空间的最值问题。转化到多维空间也是类似,梯度也就是对多个自变量x的的偏导数所组成的向量,向量所指的方向也就是函数增大的方向,思想都是一样的。只不过是从数值运算转换成向量运算了。简单吧,hihi!

本文的素材来自于慕课网的liuyubobobo老师的课程!推荐大家去听哦,简单易学!

你可能感兴趣的:(利用梯度下降法求解函数最小值)