李宏毅机器学习[2]-DL优化

SGD-Stochastic Gradient Descent随机梯度下降

首先回顾一下梯度下降公式:
θ 1 θ^1 θ1= θ 0 θ^0 θ0 ∂ ( L ) ∂ ( θ 0 ) \frac{∂(L)}{∂(θ^0)} (θ0)(L)
θ 2 θ^2 θ2= θ 1 θ^1 θ1 ∂ ( L ) ∂ ( θ 1 ) \frac{∂(L)}{∂(θ^1)} (θ1)(L)

θ t + 1 θ^{t+1} θt+1= θ t θ^t θt ∂ ( L ) ∂ ( θ t ) \frac{∂(L)}{∂(θ^t)} (θt)(L)

每次计算出梯度方向,然后把该点朝梯度的相反方向移动。反复操作直到计算出梯度值为0,即η ∂ ( L ) ∂ ( θ t ) \frac{∂(L)}{∂(θ^t)} (θt)(L)=0时,达到local minimal。
当loss function作用在整个训练集上的时候,此时函数上会存在很多个local minimal。最原始使用的是BGD批量梯度下降,使用的是整个数据集。每进行一次梯度下降,就会遍历整个数据集,当数据集特别大的时候,效率就特别低。因此SGD每次选择一部分数据集进行梯度下降,这部分数据集可能也就只有几百条数据而已。由于BGD使用的是整个数据集,因此函数图像上就会存在很多个local minimal,并且BGD每次下降方式是梯度的相反方向,因此BGD很容易陷入一个local minimal,并且整个local minimal并不是一个最优的minimal或者说不是一个global minimal,此时就很难再跳出这个local minimal;但是SGD使用的是部分数据集,当陷入一个local minimal时,进行下一次梯度下降会使用另一组数据集,此时就可以跳出local minimal。
来自课程视频截图
但是SGD会产生震荡。这是因为在选择部分数据集时,如果选择的数据集包含的数据特别少,则下降到global minimal时所经历的曲线就会很曲折,此时我们就要适当增大所选择的部分数据集,即适当增大batch size。但是特别注意,当batch size达到一定的数量级时,SGD就会变成BGD。减少震荡的方法比如SGDM,即在梯度下降时增加一个动量momentum。

SGD-Stochastic Gradient Descent Momentum带动量的梯度下降

所谓带动量的梯度下降,就是每次下降时,都要带上前一次下降的动量。这就是为了解决在SGD中当batch size特别小时会产生动荡的问题。
来自课程视频截图

在SGD中,我们是这样进行下降的:

θ t + 1 θ^{t+1} θt+1= θ t θ^t θt ∂ ( L ) ∂ ( θ t ) \frac{∂(L)}{∂(θ^t)} (θt)(L)

在SGDM中,我们设置初始动量 v 0 v^{0} v0。即
第一次下降时的动量: v 1 v^{1} v1= λ v 0 λv^0 λv0 ∂ ( L ) ∂ ( θ 0 ) \frac{∂(L)}{∂(θ^0)} (θ0)(L)
然后移动 θ 0 θ^{0} θ0 θ 1 θ^{1} θ1= θ 0 θ^{0} θ0+ v 1 v^{1} v1
第二次下降时的动量: v 2 v^{2} v2= λ v 1 λv^1 λv1 ∂ ( L ) ∂ ( θ 1 ) \frac{∂(L)}{∂(θ^1)} (θ1)(L)
然后移动 θ 1 θ^{1} θ1 θ 2 θ^{2} θ2= θ 1 θ^{1} θ1+ v 2 v^{2} v2

第t次下降时的动量: v t v^{t} vt= λ v t − 1 λv^{t-1} λvt1 ∂ ( L ) ∂ ( θ t − 1 ) \frac{∂(L)}{∂(θ^{t-1})} (θt1)(L)
然后移动 θ t − 1 θ^{t-1} θt1 θ t θ^{t} θt= θ t − 1 θ^{t-1} θt1+ v t v^{t} vt
来自课程视频截图
简单的梯度下降应用-对函数y=0.5* ( x − 0.25 ) 2 (x-0.25)^{2} (x0.25)2求最小值

import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt

mpl.rcParams['font.family'] = 'sans-serif'
mpl.rcParams['font.sans-serif'] = 'SimHei'
mpl.rcParams['axes.unicode_minus'] = False


# 构建函数
def func(x):
    return 0.5 * (x-0.25) ** 2


# 构建该函数的一阶导数
def derivative(x):
    return x-0.25


GD_X = []
GD_Y = []
x = 2  # 初始值
step = 0.05  # 步长
y = func(x)  # 求y
temp = y  # 记录当前y的值以便计算变化率
GD_X.append(x)
GD_Y.append(y)
rateY = temp  # 初始变化率
iter_num = 0


# 构造x变化函数
def changeX(x):
    return x - step * derivative(x)


# 梯度下降
while rateY > 1e-10 and iter_num < 1000:
    iter_num += 1
    temp = y  # 上次y的值存在temp中
    x = changeX(x)  # 移动x
    y = func(x)  # 移动x之后y的值
    rateY = np.abs(y - temp)  # y的变化率,
    GD_X.append(x)  # 变化率太大,迭代次数增加,变化率太小,产生震荡
    GD_Y.append(y)

print("最终计算结果:(%.5f,%.5f)" % (x, temp))
print("迭代次数:%d" % iter_num)

print(GD_X)
print(GD_Y)

X = np.arange(-4.5, 4.5, 0.05)
Y = np.array(list(map(lambda t: func(t), X)))

plt.figure(facecolor="w")
plt.plot(X, Y, "r-", linewidth=2)
plt.plot(GD_X, GD_Y, "bo--", linewidth=2)
plt.title(u"一元函数0.5 * (x - 0.25)^2进行梯度下降求函数最小值\n 学习率:%.3f,最终值:%.3f,迭代次数:%d" % (step, y, iter_num))

plt.show()

图像如下:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值