03 梯度下降算法

本课程内容是学习刘二大人的《PyTorch深度学习实践》的03梯度下降算法笔记。

上节内容:

我们主要是通过最简单的一个线性模型 Linear model ,了解了如何去选择最优权重,并且对损失loss 有了一定的概念与认知。(比较简单)

本节内容:

目录

1.分治法 引出 优化问题Optimization Problem 

2.梯度下降算法核心公式及相关问题

3.结合上节例子

4.代码

5.训练过程

6.随机梯度下降


1.分治法 引出 优化问题Optimization Problem

由于上节内容里面的权重只有一个,所以我们选用穷举法可以解决,但假设里面包含多个和权重呢?

现在我们提到了另一种方法:分治法

例如:我们现在有两个权重 w1 和 w2 ,我们在搜索的时候先进行稀疏的搜索,就例如我们把 w1 和 w2 都分成100份,我们先去找这10000个点。

如图:我们把 w1 和 w2 都分成4份,那我们将来只需要在这个可能的范围内找这16个点。

然后我们通过比较,找到最小值点,然后在该点处的范围内继续进行4✖4的这样一个搜索,这样经过几轮后,我们就可以把区间划分的非常小。

但是这个方法仍旧有很大的弊端:我们每一次选16个点的时候,不一定能选到最小点的附近,我们可能最终只是在某个极小值点处划分区间。( 如果没有听懂什么意思,可以去看看B站刘二大人03梯度下降算法视频,大概在第7分钟左右。) 而且我们在深度学习里面,不可能说仅仅只有两个权重,一旦权重的数量级完全变了,分治法的缺陷就更加严重了。

这也就是我们要讲的优化问题找到使目标函数最小的这种权重组合

2.梯度下降算法核心公式及相关问题

假设我们现在有一个 cost-function (损失函数),图中标记着我们的初始点和最优点(到达点)。根据下图,那我们要想达到最优点这个位置,我们面临的第一个问题就是:w 往左走还是往右走?

·这个问题,我们可以通过梯度定义来回答这个问题。

显然,我们应该找的是当损失函数对权重求导小于0时的方向。

注意:图中等号左边的 w 是更新后的权重,等候右边的 w 是原来权重。

          图中α表示 学习率,一般取值较小。

而我们经过几次迭代后,都朝着下降最快的这个方向去往前走一步,这个用到的一个算法思想就是:贪心算法。

(贪心算法:一种在每一步选择中都采取在当前状态下最好或最优(即最有利)的选择,从而希望导致结果是最好或最优的算法。)

贪心算法不一定都能够得到一个最优的结果,同样梯度算法也是这样。

但是,我们可以得到一个在局部区域最优的结果。

我们再拿出一个非凸函数的例子:

显然,我们可能只在第一个小窝里打转,就不能取到最优点。也就是说,我们只能达到局部最优,而不能达到全局最优。(如果没有听懂什么意思,可以去看看B站刘二大人03梯度下降算法视频,大概在第14、15分钟左右。)

在神经网络中,本来我们以为,我们可能会遇到很多局部最优点,但实际上我们并不会遇到很多局部最优。

但它存在有一种特殊的点——鞍点,在该点处梯度为0或者为零向量。

在上图中,当我们到达了红色位置,我们就不能继续迭代了。因为此时梯度为0,那么新的权重永远等于旧的权重,这个时候就陷入了鞍点。

所以其实在深度学习里面,我们要解决的最大的问题其实不是局部最优,而是鞍点问题。(鞍点的问题解决在最后一部分)

3.结合上节例子

上节内容中:

代入其中,进行化简:

我们得到最终的解析式后,就可以对我们整个训练过程来进行更新。

4.代码

# 准备好画图所用到的库
import matplotlib.pyplot as plt

# 准备数据集并保存
x_data = [1.0, 2.0, 3.0]
y_data = [2.0, 4.0, 6.0]

# 做一个初始权重的猜测 w = 1.0
w = 1.0


def forward(x):
    return x * w


# 定义一个函数,用来计算 MSE
def cost(xs, ys):
    cost = 0
    for x, y in zip(xs, ys):
        y_pred = forward(x)
        cost += (y_pred - y) ** 2
        return cost / len(xs)


# 将 epoch 和损失保存在列表中
epoch_list = []
loss_list = []


# 定义一个函数,用来计算 梯度
def gradient(xs, ys):
    grad = 0
    for x, y in zip(xs, ys):
        grad += 2 * x * (x * w - y)
        return grad / len(xs)


print('Predict (before training)', 4, forward(4))
# 训练过程
for epoch in range(100):
    cost_val = cost(x_data, y_data)
    grad_val = gradient(x_data, y_data)

    w -= 0.1 * grad_val  # 0.1是学习率
    print('Epcho:', epoch, 'w=', w, 'loss=', cost_val)
    epoch_list.append(epoch)
    loss_list.append(cost_val)
print('Predict (after training)', 4, forward(4))

# 画图
plt.plot(epoch_list, loss_list)
plt.ylabel('loss')
plt.xlabel('epoch')
plt.show()

运行结果:

我们可以得到,随着 w 越来越接近 2,loss 越来越小。

我们预测,当输入为4时,输出为7.99596598....并不是我们认为的理想状态下的8。

生成图像:

从图像中我们可以看出,loss 下降得越来越缓慢,区域收敛状态。而且根据刚才的输出结果我们也可以得知最后loss趋于0,但是并不为0。我们不太可能让loss将为0,因为这个数据里面是有噪声的。

5.训练过程

因为这个数据里面是有噪声的,我们的训练过程其实中间含有小波折:

我们可以观察到,这个训练过程在某些区域会有一些小波动甚至会有大波动,但总体趋势是收敛的,这个过程我们是可以接受的。

因为在某些区域局部震荡很大,所以有时候我们会采用指数加权均值的方法,来把这个cost function 变成一个更为平滑的形式。

公式比较简单:C_{0} 表示原来的第0轮的损失,C_{0}^{'}表示加权后的第0轮的损失

                         C_{i} 表示原来的第 i 轮的损失,C_{i}^{'}表示加权后的第 i 轮的损失

                         C_{i-1}^{'}表示加权后的第 i-1 轮的损失

如果,将来我们的训练过程呈现出下图这样一种趋势,说明这是没办法收敛的,这是训练发散,说明训练失败。

注意,有的同学会认为,上图中的最低点不就代表我们的最优点,但是这种理解是错误的。我们正常状态下,训练过程呈现的趋势应该红色线的那个图。(如果不好理解的话,你想想我们今天写的代码的输出结果和生成图像,loss 越来越接近0,w 权重是越来越接近2的,你可以继续增大epoch ,试验一下,w 是不可能超过2。)

训练失败的原因有很多,其中有一条是:学习率 α 太大。

6.随机梯度下降

实际上在深度学习中,梯度下降还是用的比较少,我们用的是梯度下降的隐身版本:随机梯度下降   

上面的两个公式就是我们今天所用到的,它们是对整体N。而随机梯度下降,是在这 N 个里面随机选一个单个样本。

我们之所以选择随机梯度下降,是为了解决鞍点问题。

我们有这么一个过程,我们知道cost function 是所有样本计算得来,我们随机选择一个样本,由于我们拿到的数据总是有噪声的,那么就会引入一个随机噪声,也就是说,即使我们陷入鞍点,随机噪声可能会把我们向前推动,那么我们就有可能跨过 n 个点,达到一个全新位置,然后继续向我们的最优值前进。

代码修改:

# 准备好画图所用到的库
import matplotlib.pyplot as plt

# 准备数据集并保存
x_data = [1.0, 2.0, 3.0]
y_data = [2.0, 4.0, 6.0]

# 做一个初始权重的猜测 w = 1.0
w = 1.0


def forward(x):
    return x * w


def loss(x, y):
    y_pred = forward(x)
    return (y_pred - y) ** 2


# 将 epoch 和损失保存在列表中
epoch_list = []
loss_list = []


# 定义一个函数,用来计算 梯度
def gradient(x, y):
    return 2 * x * (x * w - y)


print('Predict (before training)', 4, forward(4))
# 训练过程
for epoch in range(100):
    for x, y in zip(x_data, y_data):
        grad = gradient(x, y)
        w = w - 0.01 * grad  # 0.01是学习率
        print('\tgrad:', x, y, grad)
        lo = loss(x, y)
    print('Epoch:', epoch, 'w=', w, 'loss=', lo)
    epoch_list.append(epoch)
    loss_list.append(lo)
print('Predict (after training)', 4, forward(4))
# 画图
plt.plot(epoch_list, loss_list)
plt.ylabel('loss')
plt.xlabel('epoch')
plt.show()

运行结果:

随机梯度下降的性能更好,但是它的运算时间复杂度太高,因为它不能并行运算。(听不懂的话,见第38分钟)

梯度下降可以并行运算,时间复杂度低,但性能不如随机梯度下降。

所以在深度学习上面,我们会选择一个相对折中的方式,这种折中叫 Batch ,讲的是 批量的随机梯度下降 。但是呢,我们在深度学习上, Batch 开始指的全部样本,所以我们谈及批量的随机梯度下降时,讲的是:Mini - Batch 。(因为现在在深度学习里面都用的是 Mini - Batch,所以大家现在都把 Mini 省略了,直接叫成了 Batch 。)


下节内容是刘二大人的《PyTorch深度学习实践》的04反向传播。

  • 32
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值