导读:猜猜张大爷多大了?
有一天,李立宗碰到了张大爷。他问张大爷,您多大了?
据目测,张大爷在85岁左右!
猜测原则:
- 最开始的猜测要和实际看起来的年龄差不多,而不是完全靠蒙。
- 不要超过实际年龄。
两人的对话基本如下:
此时,李立宗比较正常的做法是将N说成“88岁”而不是85.1岁或者95岁!
此时这个差值可以理解为在深度学习中的学习率(更新梯度的权重),这个学习率也是不能太高或者太低。
问题如下:
- 太低:学习时间过长。每次增加0.1,要猜30次左右,跟张大爷聊10分钟,才知道原来他是88岁。
- 太高:越过了正确值,用从反方向从新来过。例如,猜测95岁,张大爷可能要说,我没那么大。
当然,学过查找算法的同学可能会说先猜一个大值,然后用二分法不断地猜。这里,学习率不适用该算法。所以,我们不讨论通过二分法来提高效率。
当然,随着猜测的进行,需要用更小的差值(学习率)。不然,就猜过头了。
还有一个问题,张大爷可能是非常友善的,他会根据李立宗的回答而给出非常友善的反馈。
上述反馈和现实函数计算最小值是一样的,也就是说越接近最小值点,梯度越小。简单来说,越接近最小值的点,值的变化越小。
需要说明的是:在梯度下降过程中,学习率和梯度值是同时下降的。
上述仅仅是为了方便理解,举的一个不是十分严谨的例子。
梯度下降是什么?
下面,我们从另外一个角度看看梯度下降。
在下面的山林中,家在最低处。
因为眼前的树木遮住了视线,看不到家在哪,所以很容易迷路。家在最低处,要想回家,每次必须不断地向下走,才能最终回家。
从图中我们可以观察到,我们需要注意两点:
- 每次走多远:步子不能太大。我们假设,有一个居然能够一步从山的一边跨到另一边,那么恐怕他回家就困难了;
- 往哪个方向走:不要往山上走,要往山下走;
我们简单整理一个表达式:
新位置 = 原位置 - 每次步长 × 方向
当然,在深度学习中,我们经常需要计算的就是求解最小值。所以,我们看看梯度下降在求解最小值方面是如何应用的。
下面用一个具体的例子,展示一下到底是如何计算最小值的,及它的具体变化过程。
y = x 2 y=x^2 y=x2
如果要计算上述表达式的最小值,我们就可以使用
新x值 = 上一次x值 - 步长 × 方向
根据导数的定义,方向可以用导数来替换。因此,上式就处理为:
xNew = xOld - alpha × 导数
更进一步来说:
针对 y = x 2 y=x^2 y=x2 ,当前x=2,y=4,计算最终y可能的最小值。
下面看看计算最小值表达式中,各个值的情况:
- xNew: 需要计算的值;
- xOld: 上一次的x值,x=2;
- alpha:步长,我们赋予步长一个适当的值,比如0.2;
- 导数: 计算 y = x 2 y=x^2 y=x2的导数,得到 y=2x,导数为“2x",x=2,则:导数=2x=4;
具体来说:
xNew = xOld - alpha × 导数
xNew = 2 - 0.2 * ( 2 × 2 ) = 2 - 0.8 = 1.2
yOld = 2^2 = 4
yNew = 1.2 ^ 2 = 1.44
通过不断地迭代上述过程,求解y的最小值。
xNew = 2 - 0.2 * ( 2 × 2 ) = 2 - 0.8 = 1.2 , 此时 y = x 2 = 1. 2 2 = 1.44 y=x^2=1.2^2=1.44 y=x2=1.22=1.44
xNew = 1.2 - 0.2 * ( 2 × 1.2 ) = 1.2 - 0.48 = 0.72 , 此时 y = x 2 = 0.7 2 2 = 0.518 y=x^2=0.72^2=0.518 y=x2=0.722=0.518
xNew = 0.72 - 0.2 * ( 2 × 0.72 ) = 0.72 - 0.288 = 0.432 , 此时 y = x 2 = 0.43 2 2 = 0.186624 y=x^2=0.432^2=0.186624 y=x2=0.4322=0.186624
xNew = 0.432 - 0.2 * ( 2 × 0.432 ) = 0.432 - 0.1728 = 0.2592 , 此时 y = x 2 = 0.259 2 2 = 0.067185 y=x^2=0.2592^2=0.067185 y=x2=0.25922=0.067185
通过上述推导,可以看到,y的值是在不断减少的,如下图所示。
计算下式的导数, y = x 2 y=x^2 y=x2,得到 y=2x
下面是上述过程的python实现代码,有兴趣的同学可以看看。
附录材料:
# -*- coding: utf-8 -*-
"""
Created on Fri Sep 16 20:34:56 2022
@author: 李立宗
公众号: 计算机视觉之光
"""
import matplotlib.pyplot as plt
import numpy as np
# 函数:y=x^2
def fx(x):
return x**2
# 梯度下降算法(Gradient descent)
def gradient_descent():
times = 5 # 要计算多少次(迭代次数)
alpha = 0.2 # 学习率,步长
x =2 # x初始值
x_axis = np.linspace(-2, 2) #x轴范围
fig = plt.figure(1,figsize=(5,5)) #显示窗口大小
ax = fig.add_subplot(1,1,1) #一个主窗口内仅仅一个子窗口
ax.set_xlabel('X', fontsize=14)
ax.set_ylabel('Y', fontsize=14)
ax.plot(x_axis,fx(x_axis)) #绘图
# 开始多轮计算
for i in range(times): #控制运行次数
x1 = x
y1= fx(x)
xOld=x
x = x - alpha * 2 * x
y = fx(x)
print("第%d次迭代:x=%f=(%f-%f*(2*%f)),y=%f" % (i + 1, x,xOld,alpha,xOld, y1))
ax.plot([x1,x], [y1,y], 'ko', lw=1, ls='-', color='coral')
plt.show()
if __name__ == "__main__":
gradient_descent()```
程序输出的结果如下图:
控制学习率
学习率相当于在山林中找回家的路时所使用的步长,就是每步走多少。
例如,下面的学习率比较适当。
如果让步长(学习率)变得小一点,需要学习更多次。
稍微改小一点学习率,一般来说问题不大。但是更小的学习率意味着更多的计算才能得到最终解。
如果学习率过小,则意味着计算量过大。极端情况下,设置了计算1000次结束,到了1000次,还是没有找到最优解。
学习率过大,可能导致导致错过最优解,但是可能也会找到。
当然,不合适的学习率,总是会浪费很多时间,极容易造成钟摆形,造成浪费。
下面这个是极端情况,当前的学习率正好在一个特定值(此处为1),让寻找最小值的过程在不断地左右摇摆中重复进行,最终无法找到最小值。
上面各个情况的合集。
梯度的理解
梯度会随着学习的不断深入,变得越来越小。
越接近目标时,梯度会变得越来越小。更进一步来说,计算 y = x 2 y=x^2 y=x2,的导数 y=2x。梯度(导数)2x会随着x值的减少而不断减少。
随着y越来越逼近最小值,梯度(导数)也变得越来越小。
如下图所示,x的值在不断地减少,其梯度也在不断在减小。我们回忆一下前面张大爷的例子,随着我们距离目标越来越近,他也会给出越来越精确的提示。
我们猜某人出生时间,开始可能是猜他出生与哪个年代,然后具体到哪一年,然后具体到哪个月,哪天,上下午。
梯度(导数),衡量的山坡的陡峭程度。可以看到如下三条曲线,其所反映的陡峭程度是不一样的。
在往山下移动时,不同的陡峭程度,移动的的趋势(加速度)是不同的。
如果有兴趣,可以运行如下python代码:
# -*- coding: utf-8 -*-
"""
Created on Sun Sep 18 20:53:55 2022
@author: 李立宗
公众号:计算机视觉之光
"""
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(-10,10,500)
y1 = 1/2*x**2
y2 = x**2
y3 = 2*x**2
plt.plot(x,y1,color = 'r',label = 'y1')
plt.plot(x,y2,'-.', color = 'b', label = 'y2')
plt.plot(x,y3,'--', color = 'g', label = 'y3')
plt.legend(loc=' best')
plt.show()
几个疑惑
疑惑1:为什么一定要沿着梯度的反方向走才能找到最小值
梯度的定义就是“值增加最大的方向”,那要想减少值,就只能朝着梯度减少的方向走了。
上式中:
- 2x是增加y值方向(梯度方向)
- -2x是减少y值方向(梯度反方向)
疑惑2:有梯度了为什么还要学习率
这个问题就像,有速度了,为什么还要加速度?
他们不是一回事。
梯度表示的是方向,而学习率表示的是每次要改变的幅度。
疑惑3:欢迎大家补充
可以在公众号“计算机视觉之光”提问。
梯度下降应用
李立宗想买点土豆做酸辣土豆丝。第一步,他想知道目前市场上土豆的价格。
于是,他问了一堆人,不过大多数人其实对土豆价格不是很敏感。
他们都只知道花了多少钱,买到了多少土豆,至于多少钱一斤他们根本不关心。
而我想知道的是土豆的单价(元/斤),以及快递费分别是多少。
由于包含快递费,价格不能简单地使用“价钱/斤”计算得到。实际上,我把问题转换为了求解一元一次方程。土豆的价格是
消费总金额 = 土豆单价 * 土豆重量 + 快递费
用符号表达一下:
y=kx+b
其中:
- y:消费总额
- k:单价
- x:土豆重量
- b:快递费
李立宗找来了很多组“斤、元”,然后开始认真计算土豆大概行情。
一般情况下,求解一元一次方程,仅需要两组数字(两组:斤、元)就能求解了。
经过一番计算,李立宗发现事情并不那么简单,这个一元二次方程不好解。原因在于,土豆的单价、快递费都不是固定的一组值,他们是在一定的区间浮动的。
因此,需要计算的是一个大致价格。更进一步说,需要一个大致的k和b来确定:
y=kx+b
也就是说,要找到一个大致的线,让它尽可能地靠近已知的数值组“斤、元”,如下图的紫色线条所示。
那就有一个问题了,这条线怎么选取呢?
或者说,我找到了一条线,如何衡量这条线是最好的匹配线条呢?
我们找到一个方法,计算每一个点和各条线的距离。距离最短的那条线,就是最有匹配线条。
下面量化一下就好了。
可以看到,均方差最小时,预测值y’是最精准的。
均差如何最小呢?当然可以使用梯度下降方法实现了。
参考资料:
1.马同学、梯度下降的通俗理解
2.King James@zhihu,策略产品经理必读系列—第八讲梯度下降法,https://zhuanlan.zhihu.com/p/335191534
3.深入浅出–梯度下降法及其实现,https://www.jianshu.com/p/c7e642877b0e
4.https://www.jiqizhixin.com/articles/2019-04-07-6
5.https://zhuanlan.zhihu.com/p/107782332?utm_source=wechat_session&utm_medium=social&utm_oi=63655349583872&utm_campaign=shareopn
1.马同学、梯度下降的通俗理解
2.King James@zhihu,策略产品经理必读系列—第八讲梯度下降法,https://zhuanlan.zhihu.com/p/335191534
3.深入浅出–梯度下降法及其实现,https://www.jianshu.com/p/c7e642877b0e
4.https://www.jiqizhixin.com/articles/2019-04-07-6
5.https://zhuanlan.zhihu.com/p/107782332?utm_source=wechat_session&utm_medium=social&utm_oi=63655349583872&utm_campaign=shareopn
6.文中山谷图片:https://pixabay.com/photos/landscape-fjords-norway-moutains-4933256/