7.2 梯度下降和随机梯度下降

在本节中,我们将介绍梯度下降(gradient descent)的工作原理。虽然梯度下降在深度学习中很少被直接使用,但理解梯度的意义以及沿着梯度反方向更新自变量可能降低目标函数值的原因是学习后续优化算法的基础。随后,我们将引出随机梯度下降(stochastic gradient descent)。

7.2.1 一维梯度下降

我们先以简单的一维梯度下降为例,解释梯度下降算法可能降低目标函数值的原因。假设连续可导的函数 f : R → R f: \mathbb{R} \rightarrow \mathbb{R} f:R→R的输入和输出都是标量。给定绝对值足够小的数 ϵ \epsilon ϵ,根据泰勒展开公式,我们得到以下的近似:

f ( x + ϵ ) ≈ f ( x ) + ϵ f ′ ( x ) . f(x + \epsilon) \approx f(x) + \epsilon f'(x) . f(x+ϵ)≈f(x)+ϵf′(x).

这里 f ′ ( x ) f'(x) f′(x)是函数 f f f在 x x x处的梯度。一维函数的梯度是一个标量,也称导数。

接下来,找到一个常数 η > 0 \eta > 0 η>0,使得 ∣ η f ′ ( x ) ∣ \left|\eta f'(x)\right| ∣ηf′(x)∣足够小,那么可以将 ϵ \epsilon ϵ替换为 − η f ′ ( x ) -\eta f'(x) −ηf′(x)并得到

f ( x − η f ′ ( x ) ) ≈ f ( x ) − η f ′ ( x ) 2 . f(x - \eta f'(x)) \approx f(x) - \eta f'(x)^2. f(x−ηf′(x))≈f(x)−ηf′(x)2.

如果导数 f ′ ( x ) ≠ 0 f'(x) \neq 0 f′(x)​=0,那么 η f ′ ( x ) 2 > 0 \eta f'(x)^2>0 ηf′(x)2>0,所以

f ( x − η f ′ ( x ) ) ≲ f ( x ) . f(x - \eta f'(x)) \lesssim f(x). f(x−ηf′(x))≲f(x).

这意味着,如果通过

x ← x − η f ′ ( x ) x \leftarrow x - \eta f'(x) x←x−ηf′(x)

来迭代 x x x,函数 f ( x ) f(x) f(x)的值可能会降低。因此在梯度下降中,我们先选取一个初始值 x x x和常数 η > 0 \eta > 0 η>0,然后不断通过上式来迭代 x x x,直到达到停止条件,例如 f ′ ( x ) 2 f'(x)^2 f′(x)2的值已足够小或迭代次数已达到某个值。

下面我们以目标函数 f ( x ) = x 2 f(x)=x^2 f(x)=x2为例来看一看梯度下降是如何工作的。虽然我们知道最小化 f ( x ) f(x) f(x)的解为 x = 0 x=0 x=0,这里依然使用这个简单函数来观察 x x x是如何被迭代的。首先,导入本节实验所需的包或模块。

%matplotlib inline
import numpy as np
import torch
import math
import sys
sys.path.append("..")
import d2lzh_pytorch as d2l

接下来使用 x = 10 x=10 x=10作为初始值,并设 η = 0.2 \eta=0.2 η=0.2。使用梯度下降对 x x x迭代10次,可见最终 x x x的值较接近最优解。

def gd(eta):x = 10results = [x]for i in range(10):x -= eta * 2 * x  # f(x) = x * x的导数为f'(x) = 2 * xresults.append(x)print('epoch 10, x:', x)return resultsres = gd(0.2)

输出:

epoch 10, x: 0.06046617599999997

下面将绘制出自变量 x x x的迭代轨迹。

def show_trace(res):n = max(abs(min(res)), abs(max(res)), 10)f_line = np.arange(-n, n, 0.1)d2l.set_figsize()d2l.plt.plot(f_line, [x * x for x in f_line])d2l.plt.plot(res, [x * x for x in res], '-o')d2l.plt.xlabel('x')d2l.plt.ylabel('f(x)')show_trace(res)

7.2.2 学习率

上述梯度下降算法中的正数 η \eta η通常叫作学习率。这是一个超参数,需要人工设定。如果使用过小的学习率,会导致 x x x更新缓慢从而需要更多的迭代才能得到较好的解。

下面展示使用学习率 η = 0.05 \eta=0.05 η=0.05时自变量 x x x的迭代轨迹。可见,同样迭代10次后,当学习率过小时,最终 x x x的值依然与最优解存在较大偏差。

show_trace(gd(0.05))

输出:

epoch 10, x: 3.4867844009999995

如果使用过大的学习率, ∣ η f ′ ( x ) ∣ \left|\eta f'(x)\right| ∣ηf′(x)∣可能会过大从而使前面提到的一阶泰勒展开公式不再成立:这时我们无法保证迭代 x x x会降低 f ( x ) f(x) f(x)的值。

举个例子,当设学习率 η = 1.1 \eta=1.1 η=1.1时,可以看到 x x x不断越过(overshoot)最优解 x = 0 x=0 x=0并逐渐发散。

show_trace(gd(1.1))

输出:

epoch 10, x: 61.917364224000096

7.2.3 多维梯度下降

在了解了一维梯度下降之后,我们再考虑一种更广义的情况:目标函数的输入为向量,输出为标量。假设目标函数 f : R d → R f: \mathbb{R}^d \rightarrow \mathbb{R} f:Rd→R的输入是一个 d d d维向量 x = [ x 1 , x 2 , … , x d ] ⊤ \boldsymbol{x} = [x_1, x_2, \ldots, x_d]^\top x=[x1​,x2​,…,xd​]⊤。目标函数 f ( x ) f(\boldsymbol{x}) f(x)有关 x \boldsymbol{x} x的梯度是一个由 d d d个偏导数组成的向量:

∇ x f ( x ) = [ ∂ f ( x ) ∂ x 1 , ∂ f ( x ) ∂ x 2 , … , ∂ f ( x ) ∂ x d ] ⊤ . \nabla_{\boldsymbol{x}} f(\boldsymbol{x}) = \bigg[\frac{\partial f(\boldsymbol{x})}{\partial x_1}, \frac{\partial f(\boldsymbol{x})}{\partial x_2}, \ldots, \frac{\partial f(\boldsymbol{x})}{\partial x_d}\bigg]^\top. ∇x​f(x)=[∂x1​∂f(x)​,∂x2​∂f(x)​,…,∂xd​∂f(x)​]⊤.

为表示简洁,我们用 ∇ f ( x ) \nabla f(\boldsymbol{x}) ∇f(x)代替 ∇ x f ( x ) \nabla_{\boldsymbol{x}} f(\boldsymbol{x}) ∇x​f(x)。梯度中每个偏导数元素 ∂ f ( x ) / ∂ x i \partial f(\boldsymbol{x})/\partial x_i ∂f(x)/∂xi​代表着 f f f在 x \boldsymbol{x} x有关输入 x i x_i xi​的变化率。为了测量 f f f沿着单位向量 u \boldsymbol{u} u(即 ∥ u ∥ = 1 \|\boldsymbol{u}\|=1 ∥u∥=1)方向上的变化率,在多元微积分中,我们定义 f f f在 x \boldsymbol{x} x上沿着 u \boldsymbol{u} u方向的方向导数为

D u f ( x ) = lim ⁡ h → 0 f ( x + h u ) − f ( x ) h . \text{D}_{\boldsymbol{u}} f(\boldsymbol{x}) = \lim_{h \rightarrow 0} \frac{f(\boldsymbol{x} + h \boldsymbol{u}) - f(\boldsymbol{x})}{h}. Du​f(x)=h→0lim​hf(x+hu)−f(x)​.

依据方向导数性质[1,14.6节定理三],以上方向导数可以改写为

D u f ( x ) = ∇ f ( x ) ⋅ u . \text{D}_{\boldsymbol{u}} f(\boldsymbol{x}) = \nabla f(\boldsymbol{x}) \cdot \boldsymbol{u}. Du​f(x)=∇f(x)⋅u.

方向导数 D u f ( x ) \text{D}_{\boldsymbol{u}} f(\boldsymbol{x}) Du​f(x)给出了 f f f在 x \boldsymbol{x} x上沿着所有可能方向的变化率。为了最小化 f f f,我们希望找到 f f f能被降低最快的方向。因此,我们可以通过单位向量 u \boldsymbol{u} u来最小化方向导数 D u f ( x ) \text{D}_{\boldsymbol{u}} f(\boldsymbol{x}) Du​f(x)。

由于 D u f ( x ) = ∥ ∇ f ( x ) ∥ ⋅ ∥ u ∥ ⋅ cos ( θ ) = ∥ ∇ f ( x ) ∥ ⋅ cos ( θ ) \text{D}_{\boldsymbol{u}} f(\boldsymbol{x}) = \|\nabla f(\boldsymbol{x})\| \cdot \|\boldsymbol{u}\| \cdot \text{cos} (\theta) = \|\nabla f(\boldsymbol{x})\| \cdot \text{cos} (\theta) Du​f(x)=∥∇f(x)∥⋅∥u∥⋅cos(θ)=∥∇f(x)∥⋅cos(θ),
其中 θ \theta θ为梯度 ∇ f ( x ) \nabla f(\boldsymbol{x}) ∇f(x)和单位向量 u \boldsymbol{u} u之间的夹角,当 θ = π \theta = \pi θ=π时, cos ( θ ) \text{cos}(\theta) cos(θ)取得最小值 − 1 -1 −1。因此,当 u \boldsymbol{u} u在梯度方向 ∇ f ( x ) \nabla f(\boldsymbol{x}) ∇f(x)的相反方向时,方向导数 D u f ( x ) \text{D}_{\boldsymbol{u}} f(\boldsymbol{x}) Du​f(x)被最小化。因此,我们可能通过梯度下降算法来不断降低目标函数 f f f的值:

x ← x − η ∇ f ( x ) . \boldsymbol{x} \leftarrow \boldsymbol{x} - \eta \nabla f(\boldsymbol{x}). x←x−η∇f(x).

同样,其中 η \eta η(取正数)称作学习率。

下面我们构造一个输入为二维向量 x = [ x 1 , x 2 ] ⊤ \boldsymbol{x} = [x_1, x_2]^\top x=[x1​,x2​]⊤和输出为标量的目标函数 f ( x ) = x 1 2 + 2 x 2 2 f(\boldsymbol{x})=x_1^2+2x_2^2 f(x)=x12​+2x22​。那么,梯度 ∇ f ( x ) = [ 2 x 1 , 4 x 2 ] ⊤ \nabla f(\boldsymbol{x}) = [2x_1, 4x_2]^\top ∇f(x)=[2x1​,4x2​]⊤。我们将观察梯度下降从初始位置 [ − 5 , − 2 ] [-5,-2] [−5,−2]开始对自变量 x \boldsymbol{x} x的迭代轨迹。我们先定义两个辅助函数,第一个函数使用给定的自变量更新函数,从初始位置 [ − 5 , − 2 ] [-5,-2] [−5,−2]开始迭代自变量 x \boldsymbol{x} x共20次,第二个函数对自变量 x \boldsymbol{x} x的迭代轨迹进行可视化。

def train_2d(trainer):  # 本函数将保存在d2lzh_pytorch包中方便以后使用x1, x2, s1, s2 = -5, -2, 0, 0  # s1和s2是自变量状态,本章后续几节会使用results = [(x1, x2)]for i in range(20):x1, x2, s1, s2 = trainer(x1, x2, s1, s2)results.append((x1, x2))print('epoch %d, x1 %f, x2 %f' % (i + 1, x1, x2))return resultsdef show_trace_2d(f, results):  # 本函数将保存在d2lzh_pytorch包中方便以后使用d2l.plt.plot(*zip(*results), '-o', color='#ff7f0e')x1, x2 = np.meshgrid(np.arange(-5.5, 1.0, 0.1), np.arange(-3.0, 1.0, 0.1))d2l.plt.contour(x1, x2, f(x1, x2), colors='#1f77b4')d2l.plt.xlabel('x1')d2l.plt.ylabel('x2')

然后,观察学习率为 0.1 0.1 0.1时自变量的迭代轨迹。使用梯度下降对自变量 x \boldsymbol{x} x迭代20次后,可见最终 x \boldsymbol{x} x的值较接近最优解 [ 0 , 0 ] [0,0] [0,0]。

eta = 0.1def f_2d(x1, x2):  # 目标函数return x1 ** 2 + 2 * x2 ** 2def gd_2d(x1, x2, s1, s2):return (x1 - eta * 2 * x1, x2 - eta * 4 * x2, 0, 0)show_trace_2d(f_2d, train_2d(gd_2d))

输出:

epoch 20, x1 -0.057646, x2 -0.000073

7.2.4 随机梯度下降

在深度学习里,目标函数通常是训练数据集中有关各个样本的损失函数的平均。设 f i ( x ) f_i(\boldsymbol{x}) fi​(x)是有关索引为 i i i的训练数据样本的损失函数, n n n是训练数据样本数, x \boldsymbol{x} x是模型的参数向量,那么目标函数定义为

f ( x ) = 1 n ∑ i = 1 n f i ( x ) . f(\boldsymbol{x}) = \frac{1}{n} \sum_{i = 1}^n f_i(\boldsymbol{x}). f(x)=n1​i=1∑n​fi​(x).

目标函数在 x \boldsymbol{x} x处的梯度计算为

∇ f ( x ) = 1 n ∑ i = 1 n ∇ f i ( x ) . \nabla f(\boldsymbol{x}) = \frac{1}{n} \sum_{i = 1}^n \nabla f_i(\boldsymbol{x}). ∇f(x)=n1​i=1∑n​∇fi​(x).

如果使用梯度下降,每次自变量迭代的计算开销为 O ( n ) \mathcal{O}(n) O(n),它随着 n n n线性增长。因此,当训练数据样本数很大时,梯度下降每次迭代的计算开销很高。

随机梯度下降(stochastic gradient descent,SGD)减少了每次迭代的计算开销。在随机梯度下降的每次迭代中,我们随机均匀采样的一个样本索引 i ∈ { 1 , … , n } i\in\{1,\ldots,n\} i∈{1,…,n},并计算梯度 ∇ f i ( x ) \nabla f_i(\boldsymbol{x}) ∇fi​(x)来迭代 x \boldsymbol{x} x:

x ← x − η ∇ f i ( x ) . \boldsymbol{x} \leftarrow \boldsymbol{x} - \eta \nabla f_i(\boldsymbol{x}). x←x−η∇fi​(x).

这里 η \eta η同样是学习率。可以看到每次迭代的计算开销从梯度下降的 O ( n ) \mathcal{O}(n) O(n)降到了常数 O ( 1 ) \mathcal{O}(1) O(1)。值得强调的是,随机梯度 ∇ f i ( x ) \nabla f_i(\boldsymbol{x}) ∇fi​(x)是对梯度 ∇ f ( x ) \nabla f(\boldsymbol{x}) ∇f(x)的无偏估计:

E i ∇ f i ( x ) = 1 n ∑ i = 1 n ∇ f i ( x ) = ∇ f ( x ) . E_i \nabla f_i(\boldsymbol{x}) = \frac{1}{n} \sum_{i = 1}^n \nabla f_i(\boldsymbol{x}) = \nabla f(\boldsymbol{x}). Ei​∇fi​(x)=n1​i=1∑n​∇fi​(x)=∇f(x).

这意味着,平均来说,随机梯度是对梯度的一个良好的估计。

下面我们通过在梯度中添加均值为0的随机噪声来模拟随机梯度下降,以此来比较它与梯度下降的区别。

def sgd_2d(x1, x2, s1, s2):return (x1 - eta * (2 * x1 + np.random.normal(0.1)),x2 - eta * (4 * x2 + np.random.normal(0.1)), 0, 0)show_trace_2d(f_2d, train_2d(sgd_2d))

输出:

epoch 20, x1 -0.047150, x2 -0.075628

可以看到,随机梯度下降中自变量的迭代轨迹相对于梯度下降中的来说更为曲折。这是由于实验所添加的噪声使模拟的随机梯度的准确度下降。在实际中,这些噪声通常指训练数据集中的无意义的干扰。

小结

  • 使用适当的学习率,沿着梯度反方向更新自变量可能降低目标函数值。梯度下降重复这一更新过程直到得到满足要求的解。
  • 学习率过大或过小都有问题。一个合适的学习率通常是需要通过多次实验找到的。
  • 当训练数据集的样本较多时,梯度下降每次迭代的计算开销较大,因而随机梯度下降通常更受青睐。

参考文献

[1] Stewart, J. (2010). Calculus: early transcendentals. 7th ed. Cengage Learning.


注:本节与原书基本相同,原书传送门

7.2_gd-sgd相关推荐

  1. 批量梯度下降(BGD)、随机梯度下降(SGD)以及小批量梯度下降(MBGD)的理解

    批量梯度下降(BGD).随机梯度下降(SGD)以及小批量梯度下降(MBGD)的理解 </h1><div class="clear"></div> ...

  2. Pytorch实现MNIST(附SGD、Adam、AdaBound不同优化器下的训练比较) adabound实现

     学习工具最快的方法就是在使用的过程中学习,也就是在工作中(解决实际问题中)学习.文章结尾处附完整代码. 一.数据准备   在Pytorch中提供了MNIST的数据,因此我们只需要使用Pytorch提 ...

  3. 从 SGD 到 Adam —— 深度学习优化算法概览 各种优化器 重点

    20210701 https://blog.51cto.com/u_15064630/2571266 [机器学习基础]优化算法详解 详细 https://blog.csdn.net/u01338501 ...

  4. Adam那么棒,为什么还对SGD念念不忘 (1) —— 一个框架看懂优化算法

    机器学习界有一群炼丹师,他们每天的日常是: 拿来药材(数据),架起八卦炉(模型),点着六味真火(优化算法),就摇着蒲扇等着丹药出炉了. 不过,当过厨子的都知道,同样的食材,同样的菜谱,但火候不一样了, ...

  5. Adam那么棒,为什么还对SGD念念不忘 (3)—— 优化算法的选择与使用策略

    在前面两篇文章中,我们用一个框架梳理了各大优化算法,并且指出了以Adam为代表的自适应学习率优化算法可能存在的问题.那么,在实践中我们应该如何选择呢? 本文介绍Adam+SGD的组合策略,以及一些比较 ...

  6. 一个框架看懂优化算法之异同 SGD/AdaGrad/Adam

    Adam那么棒,为什么还对SGD念念不忘 (1) -- 一个框架看懂优化算法 机器学习界有一群炼丹师,他们每天的日常是: 拿来药材(数据),架起八卦炉(模型),点着六味真火(优化算法),就摇着蒲扇等着 ...

  7. Adam那么棒,为什么还对SGD念念不忘 (2)—— Adam的两宗罪

    在上篇文章中,我们用一个框架来回顾了主流的深度学习优化算法.可以看到,一代又一代的研究者们为了我们能炼(xun)好(hao)金(mo)丹(xing)可谓是煞费苦心.从理论上看,一代更比一代完善,Ada ...

  8. 深度学习中的随机梯度下降(SGD)简介

    随机梯度下降(Stochastic Gradient Descent, SGD)是梯度下降算法的一个扩展. 机器学习中反复出现的一个问题是好的泛化需要大的训练集,但大的训练集的计算代价也更大.机器学习 ...

  9. Adam 那么棒,为什么还对 SGD 念念不忘?一个框架看懂深度学习优化算法

    作者|Juliuszh 链接 | https://zhuanlan.zhihu.com/juliuszh 本文仅作学术分享,若侵权,请联系后台删文处理 机器学习界有一群炼丹师,他们每天的日常是: 拿来 ...

  10. pytorch .item_pytorch + SGD

    梯度下降是模型优化常用方法,原理也比较简单,简言之就是参数沿负梯度方向更新,参数更新公式如下. ,其中 表示的是步长,用于控制每次更新移动的步伐. 我们将使用pytorch来试验下这个方法. 首先先生 ...

最新文章

  1. 数据库分库分表(sharding)系列
  2. 利用边缘灰度变化建模,来提高圆环直径求取精度
  3. 路要怎么走?关于程序员成长的一点思考
  4. ooooo123123emabc
  5. 如何发布GAE的应用(一)
  6. Linux: 系统结构详解
  7. 华为回应“WIFI联盟撤销会员资格”:不会受个别组织影响
  8. Adhesive框架系列文章--报警处理流程使用实践
  9. 零基础如何用 15 行 Python 代码搞定网易云热门歌单?
  10. 自家公司关于git commit 的规范
  11. 淘宝开源的代码质量检测工具,太强大了!!
  12. 安装驱动省心办法:驱动总裁
  13. GNSS精密星历读取(matlab)
  14. 利用Excel批量快速发送电子邮件
  15. 浅谈数据治理与成本管理
  16. 数据库学习——10-13-聚合函数+GROUP BY+HAVING学习
  17. 减少银行和金融机构的客户流失
  18. 为什么阿里巴巴天天招人,但又很难进,真的缺人吗?
  19. 论文查重格式有什么影响?
  20. python写wordcount_Python开发Spark应用之Wordcount词频统计

热门文章

  1. 组一套《头号玩家》里的 VR 套装,要多少钱?
  2. 如何用uni-app做一个领优惠券H5、小程序商城(一)
  3. 随着新时代的5G来临,中国半导体行业落后,中国看到了以AI芯片取代美国的机会
  4. 《算法笔记》4.3小节——算法初步->递归
  5. 深信服超融合数据通讯口地址冲突报错处理
  6. 这场乌镇互联网饕餮盛宴,大佬们都说了啥?
  7. DFRobot离线语音识别模块真实测评
  8. kong插件开发-完全版
  9. 面试请假攻略,不用裸辞也能找到工作
  10. 《信息物理融合系统(CPS)设计、建模与仿真——基于 Ptolemy II 平台》——1.8 域和指示器概述...