梯度下降

562 阅读2分钟

损失函数是衡量模型预估值和真实值差异的度量,之所以存在差异是因为模型中的参数(比如感知机中的 wwbb)还有待训练,在神经网络中由于参数动辄上亿,如果没有一个策略全凭直觉去调就算到宇宙爆炸也很难优化好。目前常用的策略是反向传播,而梯度下降法就是反向传播中的一种方法,其基本思想是通过迭代的方式,沿着损失函数的梯度的反方向更新参数,从而逐步逼近函数的最小值。

基本概念

在了解梯度下降的算法之前,我们先了解下面一些概念。

  1. 导数:
    1. 意义: 导数衡量了函数在某一点的瞬时变化率,也就是函数在这一点的斜率。直观地说,导数告诉我们函数在某点的变化趋势,是在增加还是减少。
  2. 偏导数:
    1. 意义: 当我们有一个多变量函数时,偏导数表示在一个特定变量的变化方向上的变化率。对于一个二元函数,偏导数就是在其中一个变量上的导数。
  3. 梯度:
    1. 意义: 梯度是一个向量(向量有方向和大小),其中每个元素是在对应维度上的偏导。在多变量函数中,梯度指示了函数在某一点上变化最快的方向,沿着梯度向量的方向,更加容易找到函数的最大值。沿着梯度向量相反的方向,更加容易找到函数的最小值。
    2. 实际计算例子: 假设有一个二元函数:f(x,y)=x2+5yf(x,y) = x^{2} + 5y,我们想计算它在点 (1,3)处的梯度。首先计算偏导数:
      fx=2xfx(1,3)=2\frac{{∂f}}{{∂x}} = 2 x ⇒ \frac{{∂f}}{{∂x}}(1,3)=2
      fy=5fy(1,3)=5\frac{{∂f}}{∂{y}} = 5 ⇒ \frac{{∂f}}{{∂y}}(1,3)=5
      • 梯度f∇f(∇ 读 nabla)就是由偏导数组成的向量:f(13)=(25)∇f(1,3)=(2,5)。这告诉我们在点 (1,3)处,函数变化最快的方向是 (2,5)。
  4. 目标函数: 也称为假设函数(hypothesis function),它是为了拟合输入样本的函数。需要拿它跟真实值计算loss。
    1. 回归任务(线性回归)的目标函数是hθ(x)=θ0+θ1x1+...+θnxn=i=0nθixih_{\theta}(x)=\theta_0+\theta_1{x_1}+...+\theta_n{x_n} = \sum_{i=0}^{n}\theta_{i}x_{i}
    2. 二分类任务(sigmoid)的目标函数是hθ(x)=11+ei=1nθixih_{\theta}(x)=\frac{1}{1+e^{-\sum_{i=1}^{n}\theta_{i}x_{i}}}
    3. 多分类任务:在深度学习中,特别是神经网络的分类层,常使用Softmax函数。对于一个具有K个类别的问题,Softmax 函数将输入的 K 维向量转换为一个表示每个类别概率的 K 维向量。形式如下:Softmax(z)i=ezij=1mezjSoftmax(z)_i=\frac{e^{z_i}}{\sum_{j=1}^{m}{e^{z_j}}}
      1. 其中zz 是输入向量的未归一化分数, Softmax(z)iSoftmax(z)_i表示第 i 个类别的预测概率。
  5. 损失函数:
    1. 交叉熵损失函数(Cross-Entropy Loss):
      1. 定义: 交叉熵是信息论中的概念,用于度量两个概率分布之间的差异。在神经网络中,交叉熵常用于分类问题。对于二分类问题,损失函数为二分类交叉熵;对于多分类问题,损失函数为多分类交叉熵。
      2. 二分类:J(θ)=(ylog(hθ(x))+(1y)log(1hθ(x)))J(\theta)=−(ylog(h_{\theta}(x))+(1−y)log(1−h_{\theta}(x)))
      3. 多分类(softmax): J(θ)=i=1myilog(ai)J(\theta) = -\sum_{i=1}^{m}y_{i}log(a_i),其中 yiy_i表示第i个分类的真实概率,aia_i表示第ii 个分类的预估概率(也就是Softmax求出的第 ii个值)。但在现实中的多分类任务中通常只有一个结果,就是说某一个分类为1其余都为0,假设训练数据的真实输出为第 jj个为1,损失函数变成:J(θ)=log(aj)J(\theta) = -log(a_j)
    2. 均方差损失函数(Mean Squared Error,MSE):
      1. 定义: 均方差损失函数用于回归问题,它度量实际输出与期望输出之间的平方差。在神经网络中,常用于输出是连续数值的问题。
      2. 公式: J(θ)=12ni=1n(yihθ(x)i)2J(\theta) = \frac{1}{2n}\sum_{i=1}^{n}{(y_{i}-h_{\theta}(x)i)^{2}},其中yiy_i表示第ii个样本的真实值,hθ(x)ih_{\theta}(x)_i表示第ii个样本的预估值。
  6. 学习率: 每一步沿梯度反方向前进的长度,该参数过大容易越过最优解,过小则收敛速度慢,在实际应用中可以多取一些值,从大到小分别运行算法,观察迭代效果,如果损失函数在变小说明取值有效,否则要增大步长。

梯度下降法详解

通过上面的介绍,我们已经对损失函数有了一定的了解,并且可以沿着梯度的反方向一步步迭代求解,得到最小化的损失函数,举个下山的例子,人如果要最快下到山底,每一步都沿着当前最陡峭的方向(也就是梯度的反方向)下降,当然这样走下去,有可能我们不能走到山脚,而是到了某一个局部的山峰低处。

1.png

上面的图像(来源:Andrew Ng Machine Learning)是损失函数JJ的曲面,这里的变量有两个θ0\theta_0θ1\theta_1,所以画出来是三维的,如果有更多的参数则是更高维空间的曲面。

接下来我拿线性回归举例一步步演示如何通过梯度下降法实现参数的迭代更新。

  1. 线性回归的目标函数是hθ(x)=i=1nθixih_{\theta}(x)=\sum_{i=1}^{n}\theta_{i}x_{i},损失函数是J(θ)=12ni=1n(yihθ(x)i)2J(\theta) = \frac{1}{2n}\sum_{i=1}^{n}{(y_{i}-h_{\theta}(x)_i)^{2}}
  2. 损失函数的梯度是:
    J(θ0,θ1...,θn)θi=[J(θ0,θ1...,θn)θ0J(θ0,θ1...,θn)θ1...J(θ0,θ1...,θn)θn]=1nj=1n(yjhθ(x)j)xi(j)\frac{∂J(\theta_0,\theta_1...,\theta_n)}{∂\theta_i} = [\frac{∂J(\theta_0,\theta_1...,\theta_n)}{∂\theta_0}, \frac{∂J(\theta_0,\theta_1...,\theta_n)}{∂\theta_1},...,\frac{∂J(\theta_0,\theta_1...,\theta_n)}{∂\theta_n}] = \frac{1}{n}\sum_{j=1}^{n}{(y_{j}-h_{\theta}(x)_j)}x_i^{(j)}
  • 注意这里的jj是第 jj 个样本,xi(j)x_i^{(j)} 是第jj 个样本的第ii个特征。
  • 当前点的梯度方向是由所有的样本决定的。
  1. 有了梯度后就可以结合学习率(步长)去更新 θ\theta参数:θi=θiα1nj=1n(yjhθ(x)j)xi(j)\theta_{i} = \theta_{i} - \alpha\frac{1}{n}\sum_{j=1}^{n}{(y_{j}-h_{\theta}(x)_j)}x_i^{(j)}
    • 其中 α\alpha是学习率
  2. 如果所有的 θ\theta在当次的下降距离都小于阈值 ϵ\epsilon则计算停止。

链式求导

2.png

目前比较火的深度神经网络的隐藏层非常多,在如此多层的网络结构中要想实现反向传播就要用到链式求导,从上面这张图中随便选一个感知机,它是由 wbzaw、b、z和a四部分组成。

  • zi[l]=wi[l]a[l1]+bi[l]z_i^{[l]} = w_i^{[l]} * a^{[l-1]} + b_i^{[l]}
  • wil表示第l层的第i个感知机的w参数,由于是全连接,所以w的个数等于l1层的感知机数量,即wi[l]可拆解为[wi,1[l],wi,2[l],...,wi,n[l]]w_i^{l}表示第 l层的第 i个感知机的 w 参数,由于是全连接,所以w的个数等于 l-1层的感知机数量,即 w_i^{[l]}可拆解为 [w_{i,1}^{[l]},w_{i,2}^{[l]},...,w_{i,n}^{[l]}]
  • a[l1]则是l1层的每个感知机的输出。a^{[l-1]}则是 l-1层的每个感知机的输出。
  • bi[l]是第l层第i个感知机的偏置项。b_i^{[l]}是第 l层第 i个感知机的偏置项。
  • 每个感知机的输出ai[l]=σ(zi[l])a_i^{[l]} = \sigma(z_i^{[l]}),其中 σ\sigma是激活函数,作用是非线性变换,提高模型拟合能力。

3.png

损失函数 J(y(k),a[l](k))J(y^{(k)}, a^{[l](k)})中的y(k)y^{(k)}表示第kk个样本的真实值,a[l](k)a^{[l](k)}表示第kk 个样本的第ll 层的输出(方括号表示网络层,圆括号表示样本)。为了提升理解我把最后的J(y(k),a[l](k))J(y^{(k)},a^{[l](k)})当做第l+1l+1,它的损失是由第ll 层的输出也就是a[l]a^{[l]}导致的,此时求第l+1l+1层损失函数JJ的梯度:

  • J[l+1]=J[l+1]a[l]\nabla{J^{[l+1]}} = \frac{∂{J^{[l+1]}}}{∂a^{[l]}}
  • 由于a[l]=σ(z[l])=σ(w[l]a[l1]+b[l])a^{[l]} = \sigma(z^{[l]}) = \sigma(w^{[l]} * a^{[l-1]} + b^{[l]}),所以JJ的梯度就是分别对w[l]w^{[l]}a[l1]a^{[l-1]}b[l]b^{[l]}求偏导,需要链式求导将其展开,即
    • J[l+1]a[l]=(J[l+1]w[l],J[l+1]a[l1],J[l+1]b[l])=(J[l+1]σσz[l]z[l]w[l],J[l+1]σσz[l]z[l]a[l1],J[l+1]σσz[l]z[l]b[l])\frac{∂J^{[l+1]}}{∂a^{[l]}} = (\frac{∂J^{[l+1]}}{∂w^{[l]}},\frac{∂J^{[l+1]}}{∂a^{[l-1]}},\frac{∂J^{[l+1]}}{∂b^{[l]}}) = (\frac{∂J^{[l+1]}}{∂\sigma}\frac{∂\sigma}{∂z^{[l]}}\frac{∂z^{[l]}}{∂w^{[l]}},\frac{∂J^{[l+1]}}{∂\sigma}\frac{∂\sigma}{∂z^{[l]}}\frac{∂z^{[l]}}{∂a^{[l-1]}}, \frac{∂J^{[l+1]}}{∂\sigma}\frac{∂\sigma}{∂z^{[l]}}\frac{∂z^{[l]}}{∂b^{[l]}})
    • 首先JJ 先对 σ\sigma求导,σ\sigma再对zz 求导,zz最后分别对wabw、a和b求导,由于ww是一个向量,所以对ww求导就是对其中每个元素求偏导,即:J[l+1]w[l]=(J[l+1]w1[l],J[l+1]w2[l],...,J[l+1]wi[l])\frac{∂J^{[l+1]}}{∂w^{[l]}} = (\frac{∂J^{[l+1]}}{∂w_1^{[l]}},\frac{∂J^{[l+1]}}{∂w_2^{[l]}},...,\frac{∂J^{[l+1]}}{∂w_i^{[l]}})aba和b也是这样就先不展开了。

有了梯度后接下来对参数更新:

w1[l]=w1[l]αJ[l+1]w1[l]b1[l]=b1[l]αJ[l+1]b1[l]w_1^{[l]} = w_1^{[l]} - \alpha{\frac{∂J^{[l+1]}}{∂w_1^{[l]}}}, b_1^{[l]} = b_1^{[l]} - \alpha{\frac{∂J^{[l+1]}}{∂b_1^{[l]}}}
w2[l]=w2[l]αJ[l+1]w2[l]b2[l]=b2[l]αJ[l+1]b2[l]w_2^{[l]} = w_2^{[l]} - \alpha{\frac{∂J^{[l+1]}}{∂w_2^{[l]}}}, b_2^{[l]} = b_2^{[l]} - \alpha{\frac{∂J^{[l+1]}}{∂b_2^{[l]}}}

.

.

wi[l]=wi[l]αJ[l+1]wi[l]bi[l]=bi[l]αJ[l+1]bi[l]w_i^{[l]} = w_i^{[l]} - \alpha{\frac{∂J^{[l+1]}}{∂w_i^{[l]}}}, b_i^{[l]} = b_i^{[l]} - \alpha{\frac{∂J^{[l+1]}}{∂b_i^{[l]}}}

由于J[l+1]a[l1]\frac{∂J^{[l+1]}}{∂a^{[l-1]}}没有办法直接更改,它依赖前面l1l-1层的输出也就是a[l1]a^{[l-1]}的改变,所以可以把J[l+1]a[l1]\frac{∂J^{[l+1]}}{∂a^{[l-1]}}当做第ll层损失函数的值,也就是J[l]=J[l+1]a[l1]J^{[l]} = \frac{∂J^{[l+1]}}{∂a^{[l-1]}},这样就实现了损失值从l+1l+1层到ll层的传导,整个过程循环迭代起来。

常见梯度下降法

根据更新参数时使用的样本量,梯度下降法可以分为批量、小批量和随机梯度下降法。

  1. 批量梯度下降法(BGD)
    • 该方法的标志是使用该batch的所有样本来进行更新:

      θi=θiα1nj=1n(yjhθ(x)j)xi(j)\theta_{i} = \theta_{i} - \alpha\frac{1}{n}\sum_{j=1}^{n}{(y_{j}-h_{\theta}(x)_j)}x_i^{(j)}

    • 当训练样本量级非常大时,每次参数更新都要使用所有的样本显然会花费较长计算时间,导致整体的训练效率低下,这种方法仅存在理论层面。

  2. 随机梯度下降法(SGD)
    • 该方法的标志是从该batch中随机选取一个样本$$j$$来求梯度。对应的更新公式是:

      θi=θiα(yjhθ(x)j)xi(j)\theta_{i} = \theta_{i} - \alpha{(y_{j}-h_{\theta}(x)_j)}x_i^{(j)}

    • 由于每次随机选一个样本计算梯度更新参数,训练速度很快,但由于随机选的样本有一定的不确定性,可能会导致非最优解。

  3. 小批量梯度下降法(MBGD)
    • 这种方法是批量和随机两种方法的折中,比如统计一个地区居民的平均身高,现实中不太可能把所有的用户都统计到,而是随机选出一批用户,计算这批用户的平均身高来代表这一地区,更新公式是:

      θi=θiα1mj=1m(yjhθ(x)j)xi(j)\theta_{i} = \theta_{i} - \alpha\frac{1}{m}\sum_{j=1}^{m}{(y_{j}-h_{\theta}(x)_j)}x_i^{(j)},其中mm表示随机选出的mm个用户。

在实际业务中,如果数据集非常大但内存有限,或者需要处理在线学习问题,那么随机梯度下降可能是一个合适的选择。如果有足够的计算资源,且数据集规模适中,那么可以尝试小批量梯度下降甚至批量梯度下降。

最后

通过前面的介绍,我相信大家对梯度下降法有了深入的了解。在实际应用中,我们通常对模型的训练和收敛速度有着较高的要求。除了前面提到的从样本集大小的角度考虑,还有一些优化方法可以在提升收敛速度方面发挥重要作用,其中包括动量法、Adagrad、RMSprop 和 Adam 等。

在接下来的文章中,我将深入介绍梯度下降中的各类优化改进方法,以帮助大家更好地理解如何调整模型的训练过程,提高训练效率。敬请期待。