0%

梯度下降算法的推导

2020.09.07更新:42:50,突然发现这个视频又讲梯度下降的底层理论,可以去看看。

梯度下降算法大家都知道,公式是\(\theta = \theta - \alpha * J'(\theta)\),其中J是代价函数。但是这个算法具体是怎么来的,可能不太清楚。 本文参考 微信公众号 梯度-百度百科 由于没有专业的制图工具,所以只能手画了。。。

梯度下降问题

梯度下降草图
梯度下降草图

由图中可以观察到,我们将参数初始化到A点,我们的目标是将点移动到最小值点(或者极小值点)。那么问题就是如何移动了。 先给出梯度下降公式:\(\theta = \theta - \alpha * J'(\theta)\),J是代价函数,这个公式应该不陌生。

一阶泰勒展开式

如果学过高数,应该知道一阶泰勒展开式的公式是:\(f(x) = f(x_0) + (x - x_0) * f'(x_0) + R_n(x)\),其中\(R_n(x)\)是泰勒公式的余项,可以理解为一个无穷小量。既然是无穷小量那么便可以省略不写,但是即使是无穷小,其实等式的左右边还是有点差距的,所以将等式修改为约等于号 \[ f(x) \approx f(x_0) + (x - x_0) * f'(x_0) \] 但是由于我们最小化的代价函数的参数是\(\theta\),所以我们可以将x替换为\(\theta\),即 \[ f(\theta) \approx f(\theta_0) + (\theta - \theta_0) * f'(\theta_0) \] 如果不知道泰勒公式,可以看下图

在点\(\theta_0\)处,找一条极短的直线来表示曲线,则直线的斜率为\(f'(\theta_0)\),并且已知\(\theta_0\),那么根据初中数学,可以获得直线公式\(f(\theta) = f(\theta_0) + (\theta - \theta_0) * f'(\theta_0)\)(还不懂看这个:\(y-y_0=k(x-x_0)\)===>\(y = y_0 + k(x-x_0)\))。

如果仔细看到了上一行的推导,你也许要问:为什么直线斜率是\(f'(\theta_0)\)。百度。

如果对上式没有问题,可能要问为什么这个红线的箭头要向下,不能向上?我有强迫症,我就要让它向上,并且我还要让\(\theta\)\(\theta_0\)右边。这个下面会讲,但是现在假定以下的步骤均围绕上图展开。

至此准备工作完成。

数学原理

我们将 \(f(\theta) \approx f(\theta_0) + (\theta - \theta_0) * f'(\theta_0)\)\(\theta - \theta_0\) 是一个微小矢量,用字母 \(\alpha v\) 代替。其中标量 \(\alpha\) 代表步长,\(\theta - \theta_0\)单位向量用 v 表示。其实 \(\alpha v\) 可以合并成 \(\alpha\) 的,但是为了下面的推导更容易说明梯度下降到底在做什么,还是拆开来表示。 \[ \theta - \theta_0 = \alpha v \] 所以公式被简化为如下形式,并且将导数的表示做一下改变,用倒三角表示 \[ f(\theta) \approx f(\theta_0) + \alpha v * \nabla f(\theta_0) \] 由于我们的目标是使得\(f(\theta)\)\(f(\theta_0)\)小,也就是使得\(f(\theta) - f(\theta_0) < 0\)。那么将公式转变为 \[ f(\theta) - f(\theta_0) \approx \alpha v * \nabla f(\theta_0) < 0 \] 省略一部分 \[ \alpha v * \nabla f(\theta_0) < 0 \] 由于\(\alpha\)一般为正值,所以 \[ v * \nabla f(\theta_0) < 0 \] 由于\(v\)\(\nabla f(\theta_0)\)实际上都是向量。所以上式就转换为两个向量相乘在什么时候是小于0的,并且我们希望\(f(\theta) - f(\theta_0)\)越小越好(注意这里的指的是小于 0 的尺度上,并非在 0~1 的尺度上),也就是\(v * \nabla f(\theta_0)\)越小越好。那么问题又转化为两个向量相乘在什么时候是最小的

问题1:为什么\(v\)\(\nabla f(\theta_0)\)是向量。 以上都是使用二维的图来描述,但是实际上 \(\theta\) 不只有一个,所以是向量而不是一个数。 问题2:为什么希望\(f(\theta) - f(\theta_0)\)越小越好。 因为希望\(f(\theta)\)这一步迈远一点。

以下为向量乘积的三种形式,由初中的知识可以得知,当向量相反时\(cos(\alpha)\)为-1,即cos函数的最小值。

由于公式可以转为如下,其中\(\beta\)是向量夹角 \[ |v| * |\nabla f(\theta_0)| * cos(\beta) < 0 \] 所以当 \(v\)\(\nabla f(\theta_0)\) 正好相反时,\(cos(\beta) = -1\)。也就是说当 \(v\)\(\nabla f(\theta_0)\) 反向,\(v * \nabla f(\theta_0)\)最小。 所以现在的问题就是 v 怎么样才能是梯度方向的反方向?众所周知,\(\nabla f(\theta_0)\) 就是梯度,也就是梯度方向。那么在 \(\nabla f(\theta_0)\) 加个负号不就是相反方向了?所以 \[ v = -\frac{\nabla f(\theta_0)}{|\nabla f(\theta_0)|}\\ \] 之所以要除以 \(\nabla f(\theta_0)\) 的模,是因为 \(v\) 是单位向量。 将 \(v\) 带入到 \(\theta - \theta_0 = \alpha * v\)\[ \theta = \theta_0 - \alpha * \frac{\nabla f(\theta_0)}{|\nabla f(\theta_0)|} \] 一般地,因为\(|\nabla f(\theta_0)|\)是标量,可以并入到中,即简化为: \[ \theta = \theta_0 - \alpha *\nabla f(\theta_0) \]

有点需要说明,我认为 \(\frac{1}{|\nabla f(\theta_0)|}\) 不能并入 \(\alpha\) 因为 \(\frac{1}{|\nabla f(\theta_0)|}\) 是一个变量。它是梯度的模长,但是在执行梯度下降时,每一个 epoch 的梯度都是不一样的。故 \(\frac{1}{|\nabla f(\theta_0)|}\) 也在每个 epoch 不中不同,但是学习率 \(\alpha\) 却是一个定值,比如 0.01, 0.03, 0.1 等。