梯度下降基础——薪火培训 视觉组 第二讲
本文最后更新于 625 天前,其中的信息可能已经有所发展或是发生改变。
!注意
本片文章记录了完成作业过程中对梯度下降的理解。
我的理解很有可能是不准确的,故本篇文章只做记录分享作用,读者请勿将本文当作教程学习。

题1:梯度下降基础


  • 刚看到这个题目,大家可能会想:为什么不直接遍历呢?其实,对于复杂的函数来说,遍历需要计算的次数过多,训练起来会很慢。因此,我们引入了梯度下降算法。
  • 学长提供了计算 y=x^2-2x+1 在 [-100,100] 区间内极小值点的例程,我们先来看一下:
import numpy as np
from matplotlib import pyplot as plt
from random import randint

# 返回函数值
def f(x):
    return x**2 -2*x +1

# 绘制函数图像
x = np.linspace(-100,100,2001)
y = f(x)
plt.plot(x,y)

# 参数
LEARNING_RATE = 0.1 #步长
ITERATIONS = 100 #循环次数
EPS = 1e-5 #定义一个极小数

# 梯度计算
def cal_grad(x,f):
    return (f(x+EPS)-f(x))/EPS #求导数

ext_point = float(randint(-100,100)) #随机获取一个初始值
print("initial ext_point:{:.2f}".format(ext_point))
log = []

# 根据当前点的梯度来调整ext_point
for iter in range(ITERATIONS):
    log.append(ext_point)
    ext_point -= LEARNING_RATE * cal_grad(ext_point,f)

print("ext_point is {:.2f}".format(ext_point))
plt.plot(range(ITERATIONS),log)
plt.show()

  • 我们可以发现,例程中的核心代码是:
for iter in range(ITERATIONS):
    log.append(ext_point)
    ext_point -= LEARNING_RATE * cal_grad(ext_point,f)

即下一个点的坐标由步长梯度决定,当梯度为正时,ext会减少,即向低处移动;梯度为负时,ext会增加,也会向低处移动。接下来,我们从网络中更详细地了解一下梯度下降。

什么是梯度下降?

梯度下降通过不断迭代计算函数的梯度,判断该点的某一方向和目标之间的距离,最终求得最小的损失函数和相关参数,为建立线性模型提供支持。

梯度下降是一种广泛用于求解线性和非线性模型最优解的迭代算法,它的中心思想在于通过迭代次数的递增,调整使得损失函数最小化的权重

它的作用是用于优化一个目标函数,如果要最小化一个损失函数,使用的就是梯度下降法,如果要最大化一个效用函数,使用的是梯度上升法。

版权声明:本文为CSDN博主「kuokay」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_45066628/article/details/123761421

接下来,我们来理解一下最简单的使用r*g来更新参数

ext_point -= LEARNING_RATE * cal_grad(ext_point,f)

新的参数由原值-步长*梯度决定。

def cal_grad(x,f):
    return (f(x+EPS)-f(x))/EPS #求导数

个人看来,我们可以把梯度当作导数,因此通过r*g方法来更新参数,参数的值会不断向”低处“移动,最终梯度会变得十分小,使得参数的值稳定。

由此,我们可以初步写出本作业的代码:

import numpy as np
from matplotlib import pyplot as plt
from random import randint

#定义函数
def f(x):
    return x**4+3*x**3-7*x**2+2*x-1

#绘制函数
sx = np.linspace(-5,5,1000) 
y = f(sx)
plt.plot(sx,y)

#参数
LEARNING_RATE = 0.0001 #步长
ITERATIONS = 10000 #次数
#EPS = 1e-8 #极小值

#梯度计算
def cal_grad(x,f):
    return 4*x**3+9*x**2-14*x+2

ext_point = float(randint(-100,100)) #随机设置初始点
print("initial ext_point:{:.2f}".format(ext_point))
log = []

#梯度下降
for iter in range(ITERATIONS):
    if ext_point>=-5 and ext_point<=5:
        log.append(ext_point)
    ext_point -= LEARNING_RATE * cal_grad(ext_point,f)

#输出
print("ext_point is {:.2f}".format(ext_point))
y = f(np.array(log))
plt.scatter(log,y,c="r")
plt.scatter(ext_point,f(ext_point),c="g",s="10")

plt.show()

但是经过几次测试,发现参数容易停留在”局部最优点“,即0.93左右(如图)

显然,代码需要进行优化。

经过简单的思考,我们不难发现lr*gr的算法只能找出区间内的所有(或部分)极小值点,而有可能无法找出最小值点,这对于有局部最优解的情况并不友好。

RMProp法:

经过查阅资料,我找到了RMProp这一算法。

这个算法的核心思想便是自适应学习率。在训练初期,以较高学习率加快模型训练,后期通过降低学习率以提高精度。同时,他的实现数学公式如下:

这个算法可以综合考虑之间的梯度值,从而确定更为合理的学习率。更改代码,我们得到:

import numpy as np
import math
from matplotlib import pyplot as plt
from random import randint

#定义函数
def f(x):
    return x**4+3*x**3-7*x**2+2*x-1

#打印函数图像
sx = np.linspace(-5,5,1000)
y = f(sx)
plt.plot(sx,y)

#参数
LEARNING_RATE = 1 #步长
ITERATIONS = 100000 #次数
DECLINE_RATE = 0.99 #衰减

grad_sum = 0 #梯度和
EPS = 1e-6 #极小值

#梯度计算
def cal_grad(x,f):
    return 4*x**3+9*x**2-14*x+2 #导数

ext_point = float(randint(0,100)) # 初始值
print("initial ext_point:{:.2f}".format(ext_point))
log = []

for iter in range(ITERATIONS):
    if ext_point>=-5 and ext_point<=5:
        log.append(ext_point)
    grad_sum = grad_sum*DECLINE_RATE+(1-DECLINE_RATE)*cal_grad(ext_point,f)*cal_grad(ext_point,f)
    ext_point -= LEARNING_RATE * cal_grad(ext_point,f) / math.sqrt(EPS+grad_sum)
    
print("ext_point is {:.2f}".format(ext_point))
y = f(np.array(log))
plt.scatter(log,y,c="r",s=10)
plt.scatter(ext_point,f(ext_point),c="#66ccff",marker="*",s=200)
plt.title("EXT_POINT: {:.2f}".format(ext_point))
plt.show()

结果也成功得到最小值点。


欢迎通过E-mail:blog#drinkcat.com 与我进行交流。
关注我的微信订阅号:饮猫DrinkCat在BIT,即是对我最大的支持~


上一篇
下一篇