梯度下降法
本文主要是为了讲解 梯度下降法 的原理和实践,至于什么是梯度下降法,他能做什么,相信百度一下你就都知道了,所以下面进入正题
从一元二次方程开始
梯度下降法主要是用来求解某个方程的最小值,这里我们以 凹一元二次方程为例。
准备数据
这里我们用到 matplotlib
和 numpy
,如果你对这两个库不了解也没关系,我们主要是借助它来进行讲解,不会过多涉及相关的东西
import matplotlib.pyplot as plt
import numpy as np
# 生成一个等差数列 plot_x
plot_x = np.linspace(1,5,20)
# plot_x 平方 再加2 生成一个数列 plot_y
plot_y = (plot_x-3)**2+2
# 将 plot_x plot_y 对应位置作为一个点的 x,y 坐标,那么就可以画出如下图的一条一元二次方程的曲线
plt.plot(plot_x,plot_y)
plt.show()
损失函数 和 梯度函数
这里我们首先明确两个概念:
-
目标函数:指导我们求解最值的函数 ,一般来说又可以叫做
- 损失函数:一般情况下,当我们希望损失最小的时候,目标函数会指导我们去求最小值,所以叫损失函数,本次例子我们就是以损失函数为例
- 效用函数:与损失函数相反,当我们希望某种效益最大化的时候,目标函数就会指定我们求最大值,所以叫 效用函数。
本质上其实都是一样的,都是指导我们求最值。
梯度函数:我们知道,梯度下降不是一种可以直接求解的方案,而是一步步尝试,一步步对比来达到最终想到的位置,为了尽快达到最终位置,那么我们就需要一个可靠的方向来指引我们前进,梯度函数就是这个帮我们指引方向的函数,就凹一元二次方程来说,就是某个点的导数,可以指导我们的以最快的速度到达最小值。
并且梯度总是指向损失函数变大的方向,这里因为是梯度下降,所以每次迭代的值应该是梯度的负方向
编程实现梯度下降法
# 梯度函数
def dJ(x):
return (x-3)*2
# 损失函数
def J(x):
return (x-3)**2+2
x = 0.1
# 记录每次梯度下降的点
history_x=[x]
i_iter=1
# 学习率
learn_rate = 0.1
# 进行梯度迭代
while i_iter < 1e4:
i_iter += 1
dj = dJ(x)
last_x = x
x =x -learn_rate *dj
history_x.append(x)
# 如果迭代精确的达到,则结束结算
if abs(J(x)-J(last_x))<0.0000000001 :
break
history_y = J(np.array(history_x))
plt.plot(plot_x,plot_y)
plt.plot(history_x,history_y,color='r',marker='+')
plt.show()
后记
本文讲的并不如何易懂 和 通俗,不过因为 一元二次的 梯度应该是相对很容易的,所以这里也就不啰嗦了,梯度下降其实也不外呼这个原理,只是可能损失函数会不太一样,那么梯度函数也就跟着不太一样了,但是到最后都是通过这两个函数来进行迭代达到最后的标准求出最优解
梯度下降法容易陷入局部最优解的而达不到全局最优解,所以可能需要随机选取多个起始点进行梯度迭代,这样全量的梯度下降法也叫做 批量梯度下降法
对于多元二次方程,因为多元会使得 批量梯度下降法 的梯度函数计算的非常缓慢,所以可以采用随机梯度下降,并且随机梯度下降不容易陷入局部最优解的的陷阱,所谓的随机梯度就是随机选取一个样本进行迭代来实现,但是因为单一样本的偶然性比较大,并且其最后不一定能达到最小值,所以一般也是采取折中的 小批量梯度下降法,即可以随机抽取一部分样本进行迭代。
值得注意的是使用随机梯度下降的时候,我们的 学习率
就不能取一个固定值,这一点从上面的轨迹图可见一般,越是接近底部,其变化应该是越来越小的,如果 学习率 还是一开始的那样,因为样本数不够的原因,会使得最终的结果在真正的最小值附件徘徊,使得很难得到一个比较精确的值。这里可以参考下 模拟退火
的思想,顺便我们可以看下随机梯度下降的 学习率 公式: a/(b+迭代次数)