数值计算
1 上溢和下溢
连续数学在数字计算机上的根本困难是,我们需要通过有限数量的位模式来表示无限多的实数。这意味着我们在计算机中表示实数时,几乎总会引入一些近似误差。在许多情况下,这仅仅是舍入误差。舍入误差会导致一些问题,特别是当许多操作复合时,即使是理论上可行的算法,如果在设计时没有考虑最小化舍入误差的累积,在实践时也可能会导致算法失效。
一种极具毁灭性的舍入误差是下溢(underflow)。当接近零的数被四舍五入为零时发生下溢。许多函数在其参数为零而不是一个很小的正数时才会表现出质的不同。例如,我们通常要避免被零除(一些软件环境将在这种情况下抛出异常,有些会返回一个非数字(not-a-number, NaN) 的占位符)或避免取零的对数(这通常被视为−∞-\infty−∞,进一步的算术运算会使其变成非数字)。
另一个极具破坏力的数值错误形式是上溢(overflow)。当大量级的数被近似为∞\infty∞或−∞-\infty−∞时发生上溢。进一步的运算通常会导致这些无限值变为非数字。
必须对上溢和下溢进行数值稳定的一个例子是softmax函数(softmax func-tion)。softmax函数经常用于预测与Multinoulli分布相关联的概率,定义为:
softmax(x)i=exp(xi)∑j=1nexp(xj).
\begin{gather}
\operatorname{softmax}(x)_i=\frac{\exp \left(x_i\right)}{\sum_{j=1}^n \exp \left(x_j\right)} .
\end{gather}
softmax(x)i=∑j=1nexp(xj)exp(xi).
考虑一下当所有 xix_ixi 都等于某个常数 ccc 时会发生什么。理论分析上,我们可以发现所有的输出都应该为 1n\frac{1}{n}n1 。数值计算上,当 ccc 量级很大时,这可能不会发生。如果 ccc 是很小的负数,exp(c)\exp (c)exp(c)就会下溢。这意味着softmax\operatorname{softmax}softmax函数的分母会变成0,所以最后的结果是未定义的。当 ccc 是非常大的正数时, exp(c)\exp (c)exp(c) 的上溢再次导致整个表达式未定义。这两个困难能通过计算 softmax(z)\operatorname{softmax}(\boldsymbol{z})softmax(z) 同时解决,其中 z=x−maxixi\boldsymbol{z}=\boldsymbol{x}-\max _i x_iz=x−maxixi 。简单的代数计算表明,softmax 解析上的函数值不会因为从输人向量减去或加上标量而改变。减去 maxixi\max _i x_imaxixi 导致 exp\expexp 的最大参数为 0 ,这排除了上溢的可能性。同样地,分母中至少有一个值为 1 的项,这就排除了因分母下溢而导致被零除的可能性。
还有一个小问题。分子中的下溢仍可以导致整体表达式被计算为零。这意味着,如果我们在计算 logsoftmax(x)\log \operatorname{softmax}(\boldsymbol{x})logsoftmax(x) 时,先计算 softmax\operatorname{softmax}softmax 再把结果传给 log\loglog 函数,会错误地得到 −∞-\infty−∞ 。相反,我们必须实现一个单独的函数,并以数值稳定的方式计算 log softmax。我们可以使用相同的技巧来稳定 log softmax 函数。
2 病态条件
条件数表征函数相对于输人的微小变化而变化的快慢程度。输人被轻微扰动而迅速改变的函数对于科学计算来说可能是有问题的,因为输人中的舍人误差可能导致输出的巨大变化。
考虑函数 f(x)=A−1xf(\boldsymbol{x})=\boldsymbol{A}^{-1} \boldsymbol{x}f(x)=A−1x 。当 A∈Rn×n\boldsymbol{A} \in \mathbb{R}^{n \times n}A∈Rn×n 具有特征值分解时,其条件数为
maxi,j∣λiλj∣.
\begin{gather}
\max _{i, j}\left|\frac{\lambda_i}{\lambda_j}\right| .
\end{gather}
i,jmaxλjλi.
这是最大和最小特征值的模之比。当该数很大时,矩阵求逆对输入的误差特别敏感。这种敏感性是矩阵本身的固有特性,而不是矩阵求逆期间舍入误差的结果。即使我们乘以完全正确的矩阵逆,病态条件的矩阵也会放大预先存在的误差。在实践中,该错误将与求逆过程本身的数值误差进一步复合。
3 基于梯度的优化方法
大多数深度学习算法都涉及某种形式的优化。优化指的是改变 xxx 以最小化或最大化某个函数 f(x)f(x)f(x) 的任务。我们通常以最小化 f(x)f(x)f(x) 指代大多数最优化问题。最大化可经由最小化算法最小化−f(x)-f(x)−f(x)来实现。
我们把要最小化或最大化的函数称为目标函数(objective function)或准则 (criterion)。当我们对其进行最小化时,我们也把它称为代价函数(cost function),损失函数(loss function)或误差函数(error function)。虽然有些机器学习著作赋予这些名称特殊的意义,但在这里我们会交替使用这些术语。
我们通常使用一个上标 ∗*∗ 表示最小化或最大化函数的 xxx 值。如我们记 x∗=x^*=x∗= argminf(x)\arg \min f(x)argminf(x) 。
这里简要回顾微积分概念如何与优化联系。
假设我们有一个函数 y=f(x)y=f(x)y=f(x) ,其中 xxx 和 yyy 是实数。这个函数的导数(derivative)记为 f′(x)f^{\prime}(x)f′(x) 或 dydx\frac{d y}{d x}dxdy 。导数 f′(x)f^{\prime}(x)f′(x) 代表 f(x)f(x)f(x) 在点 xxx 处的斜率。换句话说,它表明如何缩放输人的小变化才能在输出获得相应的变化:f(x+ϵ)≈f(x)+ϵf′(x)f(x+\epsilon) \approx f(x)+\epsilon f^{\prime}(x)f(x+ϵ)≈f(x)+ϵf′(x) 。
因此导数对于最小化一个函数很有用,因为它告诉我们如何更改 xxx 来略微地改善 yyy 。例如,我们知道对于足够小的 ϵ\epsilonϵ 来说,f(x−ϵsign(f′(x)))f\left(x-\epsilon \operatorname{sign}\left(f^{\prime}(x)\right)\right)f(x−ϵsign(f′(x))) 是比 f(x)f(x)f(x) 小的。因此我们可以将 xxx 往导数的反方向移动一小步来减小 f(x)f(x)f(x) 。这种技术被称为梯度下降(gradient descent)(Cauchy,1847)。
当 f′(x)=0f^{\prime}(x)=0f′(x)=0 ,导数无法提供往哪个方向移动的信息。 f′(x)=0f^{\prime}(x)=0f′(x)=0 的点称为临界点(critical point)或驻点(stationary point)。一个局部极小点(local minimum)意味着这个点的 f(x)f(x)f(x) 小于所有邻近点,因此不可能通过移动无穷小的步长来减小 f(x)f(x)f(x) 。一个局部极大点(local maximum)意味着这个点的 f(x)f(x)f(x) 大于所有邻近点,因此不可能通过移动无穷小的步长来增大 f(x)f(x)f(x) 。有些临界点既不是最小点也不是最大点,称为鞍点。
使f(x)f(x)f(x)取得绝对的最小值(相对所有其他值)的点是全局最小点(globalminimum)。函数可能只有一个全局最小点或存在多个全局最小点,还可能存在不是全局最优的局部极小点。在深度学习的背景下,我们要优化的函数可能含有许多不是最优的局部极小点,或者还有很多处于非常平坦的区域内的鞍点。尤其是当输入是多维的时候,所有这些都将使优化变得困难。因此,我们通常寻找使fff非常小的点,但这在任何形式意义下并不一定是最小。
我们经常最小化具有多维输入的函数:f:Rn→Rf: \mathbb{R}^n \rightarrow \mathbb{R}f:Rn→R 。为了使"最小化"的概念有意义,输出必须是一维的(标量)。
针对具有多维输人的函数,我们需要用到偏导数(partial derivative)的概念。偏导数 ∂∂xif(x)\frac{\partial}{\partial x_i} f(x)∂xi∂f(x) 衡量点 xxx 处只有 xix_ixi 增加时 f(x)f(x)f(x) 如何变化。梯度(gradient)是相对一个向量求导的导数:fff 的导数是包含所有偏导数的向量,记为 ∇xf(x)\nabla_x f(x)∇xf(x) 。梯度的第 iii 个元素是 fff 关于 xix_ixi 的偏导数。在多维情况下,临界点是梯度中所有元素都为零的点。
在 u\boldsymbol{u}u(单位向量)方向的方向导数(directional derivative)是函数 fff 在 u\boldsymbol{u}u 方向的斜率。换句话说,方向导数是函数 f(x+αu)f(\boldsymbol{x}+\alpha \boldsymbol{u})f(x+αu) 关于 α\alphaα 的导数(在 α=0\alpha=0α=0 时取得)。使用链式法则,我们可以看到当 α=0\alpha=0α=0 时,∂∂αf(x+αu)=u⊤∇xf(x)\frac{\partial}{\partial \alpha} f(\boldsymbol{x}+\alpha \boldsymbol{u})=\boldsymbol{u}^{\top} \nabla_{\boldsymbol{x}} f(\boldsymbol{x})∂α∂f(x+αu)=u⊤∇xf(x) 。
为了最小化 fff ,我们希望找到使 fff 下降得最快的方向。计算方向导数:
minu,u⊤u=1u⊤∇xf(x)=minu,u⊤u=1∥u∥2∥∇xf(x)∥2cosθ \begin{gathered} \min _{u, u^{\top} u=1} u^{\top} \nabla_{\boldsymbol{x}} f(\boldsymbol{x}) \\ =\min _{u, u^{\top} u=1}\|u\|_2\left\|\nabla_x f(x)\right\|_2 \cos \theta \end{gathered} u,u⊤u=1minu⊤∇xf(x)=u,u⊤u=1min∥u∥2∥∇xf(x)∥2cosθ
其中 θ\thetaθ 是 u\boldsymbol{u}u 与梯度的夹角。将 ∥u∥2=1\|\boldsymbol{u}\|_2=1∥u∥2=1 代入,并忽略与 u\boldsymbol{u}u 无关的项,就能简化得到 minucosθ\min _u \cos \thetaminucosθ 。这在 uuu 与梯度方向相反时取得最小。换句话说,梯度向量指向上坡,负梯度向量指向下坡。我们在负梯度方向上移动可以减小 fff 。这被称为最速下降法 (method of steepest descent)或梯度下降(gradient descent)。
最速下降建议新的点为
x′=x−ϵ∇xf(x) \begin{gather} x^{\prime}=x-\epsilon \nabla_x f(x) \end{gather} x′=x−ϵ∇xf(x)
其中 ϵ\epsilonϵ 为学习率(learning rate),是一个确定步长大小的正标量。我们可以通过几种不同的方式选择 ϵ\epsilonϵ 。普遍的方式是选择一个小常数。有时我们通过计算,选择使方向导数消失的步长。还有一种方法是根据几个 ϵ\epsilonϵ 计算 f(x−ϵ∇xf(x)f\left(\boldsymbol{x}-\epsilon \nabla_{\boldsymbol{x}} f(\boldsymbol{x})\right.f(x−ϵ∇xf(x) ),并选择其中能产生最小目标函数值的 ϵ\epsilonϵ 。这种策略被称为线搜索。
最速下降在梯度的每一个元素为零时收敛(或在实践中,很接近零时)。在某些情况下,我们也许能够避免运行该迭代算法,并通过解方程 ∇xf(x)=0\nabla_{\boldsymbol{x}} f(\boldsymbol{x})=0∇xf(x)=0 直接跳到临界点。
虽然梯度下降被限制在连续空间中的优化问题,但不断向更好的情况移动一小步(即近似最佳的小移动)的一般概念可以推广到离散空间。递增带有离散参数的目标函数被称为爬山(hill climbing)算法。
3.1 梯度之上:Jacobian 和Hessian 矩阵
有时我们需要计算输人和输出都为向量的函数的所有偏导数。包含所有这样的偏导数的矩阵被称为 Jacobian 矩阵。具体来说,如果我们有一个函数:f:Rm→Rnf: \mathbb{R}^m \rightarrow \mathbb{R}^nf:Rm→Rn ,fff的Jacobian矩阵 J∈Rn×mJ \in \mathbb{R}^{n \times m}J∈Rn×m 定义为 Ji,j=∂∂xjf(x)iJ_{i, j}=\frac{\partial}{\partial x_j} f(x)_iJi,j=∂xj∂f(x)i 。
有时,我们也对导数的导数感兴趣,即二阶导数。例如,有一个函数 f:Rm→R,ff: \mathbb{R}^m \rightarrow \mathbb{R}, ff:Rm→R,f 的一阶导数(关于 xjx_jxj )关于 xix_ixi 的导数记为 ∂2∂xi∂xjf\frac{\partial^2}{\partial x_i \partial x_j} f∂xi∂xj∂2f 。在一维情况下,我们可以将 ∂2∂x2f\frac{\partial^2}{\partial x^2} f∂x2∂2f 为 f′′(x)f^{\prime \prime}(x)f′′(x) 。二阶导数告诉我们,一阶导数将如何随着输人的变化而改变。它表示只基于梯度信息的梯度下降步骤是否会产生如我们预期的那样大的改善,因此它是重要的。我们可以认为,二阶导数是对曲率的衡量。假设我们有一个二次函数(虽然很多实践中的函数都不是二次的,但至少在局部可以很好地用二次近似)。如果这样的函数具有零二阶导数,那就没有曲率。也就是一条完全平坦的线,仅用梯度就可以预测它的值。我们使用沿负梯度方向大小为 ϵ\epsilonϵ 的下降步,当该梯度是 1 时,代价函数将下降 ϵ\epsilonϵ 。如果二阶导数是负的,函数曲线向下凹陷(向上凸出),因此代价函数将下降的比 ϵ\epsilonϵ 多。如果二阶导数是正的,函数曲线是向上凹陷(向下凸出),因此代价函数将下降的比 ϵ\epsilonϵ 少。
当我们的函数具有多维输人时,二阶导数也有很多。我们可以将这些导数合并成一个矩阵,称为 Hessian 矩阵。Hessian 矩阵 H(f)(x)\boldsymbol{H}(f)(\boldsymbol{x})H(f)(x) 定义为
H(f)(x)i,j=∂2∂xi∂xjf(x). \begin{gather} \boldsymbol{H}(f)(\boldsymbol{x})_{i, j}=\frac{\partial^2}{\partial x_i \partial x_j} f(\boldsymbol{x}) . \end{gather} H(f)(x)i,j=∂xi∂xj∂2f(x).
Hessian 等价于梯度的 Jacobian 矩阵。
微分算子在任何二阶偏导连续的点处可交换,也就是它们的顺序可以互换:
∂2∂xi∂xjf(x)=∂2∂xj∂xif(x).
\begin{gather}
\frac{\partial^2}{\partial x_i \partial x_j} f(x)=\frac{\partial^2}{\partial x_j \partial x_i} f(x) .
\end{gather}
∂xi∂xj∂2f(x)=∂xj∂xi∂2f(x).
这意味着 Hi,j=Hj,iH_{i, j}=H_{j, i}Hi,j=Hj,i ,因此 Hessian 矩阵在这些点上是对称的。在深度学习背景下,我们遇到的大多数函数的 Hessian 几乎处处都是对称的。因为 Hessian 矩阵是实对称的,我们可以将其分解成一组实特征值和一组特征向量的正交基。在特定方向 ddd上的二阶导数可以写成 d⊤Hd\boldsymbol{d}^{\top} \boldsymbol{H d}d⊤Hd 。当 d\boldsymbol{d}d 是 H\boldsymbol{H}H 的一个特征向量时,这个方向的二阶导数就是对应的特征值。对于其他的方向 ddd ,方向二阶导数是所有特征值的加权平均,权重在 0 和 1 之间,且与 ddd 夹角越小的特征向量的权重越大。最大特征值确定最大二阶导数,最小特征值确定最小二阶导数。
我们可以通过(方向)二阶导数预期一个梯度下降步骤能表现得多好。我们在当前点 x(0)\boldsymbol{x}^{(0)}x(0) 处作函数 f(x)f(\boldsymbol{x})f(x) 的近似二阶泰勒级数:
f(x)≈f(x(0))+(x−x(0))⊤g+12(x−x(0))⊤H(x−x(0)), \begin{gather} f(x) \approx f\left(x^{(0)}\right)+\left(x-x^{(0)}\right)^{\top} g+\frac{1}{2}\left(x-x^{(0)}\right)^{\top} \boldsymbol{H}\left(x-x^{(0)}\right), \end{gather} f(x)≈f(x(0))+(x−x(0))⊤g+21(x−x(0))⊤H(x−x(0)),
其中 g\boldsymbol{g}g 是梯度, H\boldsymbol{H}H 是 x(0)\boldsymbol{x}^{(0)}x(0) 点的 Hessian。如果我们使用学习率 ϵ\epsilonϵ ,那么新的点 x\boldsymbol{x}x 将会是 x(0)−ϵg\boldsymbol{x}^{(0)}-\epsilon \boldsymbol{g}x(0)−ϵg 。代人上述的近似,可得
f(x(0)−ϵg)≈f(x(0))−ϵg⊤g+12ϵ2g⊤Hg. \begin{gather} f\left(\boldsymbol{x}^{(0)}-\epsilon \boldsymbol{g}\right) \approx f\left(\boldsymbol{x}^{(0)}\right)-\epsilon \boldsymbol{g}^{\top} \boldsymbol{g}+\frac{1}{2} \epsilon^2 g^{\top} \boldsymbol{H g} . \end{gather} f(x(0)−ϵg)≈f(x(0))−ϵg⊤g+21ϵ2g⊤Hg.
其中有 3 项:函数的原始值,函数斜率导致的预期改善,函数曲率导致的校正。当最后一项太大时,梯度下降实际上是可能向上移动的。当 g⊤Hgg^{\top} H gg⊤Hg 为零或负时,近似的泰勒级数表明增加 ϵ\epsilonϵ 将永远使 fff 下降。在实践中,泰勒级数不会在 ϵ\epsilonϵ 大的时候也保持准确,因此在这种情况下我们必须采取更启发式的选择。当 g⊤Hg\boldsymbol{g}^{\top} \boldsymbol{H g}g⊤Hg 为正时,通过计算可得,使近似泰勒级数下降最多的最优步长为
ϵ∗=g⊤gg⊤Hg. \begin{gather} \epsilon^*=\frac{g^{\top} g}{g^{\top} H g} . \end{gather} ϵ∗=g⊤Hgg⊤g.
最坏的情况下,ggg 与 HHH 最大特征值 λmax \lambda_{\text {max }}λmax 对应的特征向量对齐,则最优步长是 1λmax \frac{1}{\lambda_{\text {max }}}λmax 1 。我们要最小化的函数能用二次函数很好地近似的情况下,Hessian 的特征值决定了学习率的量级。
二阶导数还可以被用于确定一个临界点是否是局部极大点,局部极小点或鞍点。回想一下,在临界点处 f′(x)=0f^{\prime}(x)=0f′(x)=0 。而 f′′(x)>0f^{\prime \prime}(x)>0f′′(x)>0 意味着 f′(x)f^{\prime}(x)f′(x) 会随着我们移向右边而增加,移向左边而减小,也就是 f′(x−ϵ)<0f^{\prime}(x-\epsilon)<0f′(x−ϵ)<0 和 f′(x+ϵ)>0f^{\prime}(x+\epsilon)>0f′(x+ϵ)>0 对足够小的 ϵ\epsilonϵ 成立。换句话说,当我们移向右边,斜率开始指向右边的上坡,当我们移向左边,斜率开始指向左边的上坡。因此我们得出结论,当 f′(x)=0f^{\prime}(x)=0f′(x)=0 且 f′′(x)>0f^{\prime \prime}(x)>0f′′(x)>0 时,xxx 是一个局部极小点。同样,当 f′(x)=0f^{\prime}(x)=0f′(x)=0 且 f′′(x)<0f^{\prime \prime}(x)<0f′′(x)<0 时,xxx 是一个局部极大点。这就是所谓的二阶导数测试(second derivative test)。不幸的是,当 f′′(x)=0f^{\prime \prime}(x)=0f′′(x)=0 时测试是不确定的。在这种情况下,xxx 可以是一个鞍点或平坦区域的一部分。
在多维情况下,我们需要检测函数的所有二阶导数。利用 Hessian 的特征值分解,我们可以将二阶导数测试扩展到多维情况。在临界点处 (∇xf(x)=0\left(\nabla_{\boldsymbol{x}} f(\boldsymbol{x})=0\right.(∇xf(x)=0 ),我们通过检测 Hessian 的特征值来判断该临界点是一个局部极大点,局部极小点还是鞍点。当 Hessian 是正定的(所有特征值都是正的),则该临界点是局部极小点。因为方向二阶导数在任意方向都是正的,参考单变量的二阶导数测试就能得出此结论。同样的,当 Hessian 是负定的(所有特征值都是负的),这个点就是局部极大点。在多维情况下,实际上我们可以找到确定该点是否为鞍点的积极迹象(某些情况下)。如果 Hessian 的特征值中至少一个是正的且至少一个是负的,那么 xxx 是 fff 某个横截面的局部极大点,却是另一个横截面的局部极小点。最后,多维二阶导数测试可能像单变量版本那样是不确定的。当所有非零特征值是同号的且至少有一个特征值是 0 时,这个检测就是不确定的。这是因为单变量的二阶导数测试在零特征值对应的横截面上是不确定的。
多维情况下,单个点处每个方向上的二阶导数是不同。Hessian 的条件数衡量这些二阶导数的变化范围。当Hessian 的条件数很差时,梯度下降法也会表现得很差。这是因为一个方向上的导数增加得很快,而在另一个方向上增加得很慢。梯度下降不知道导数的这种变化,所以它不知道应该优先探索导数长期为负的方向。病态条件也导致很难选择合适的步长。步长必须足够小,以免冲过最小而向具有较强正曲率的方向上升。这通常意味着步长太小,以致于在其他较小曲率的方向上进展不明显。
我们可以使用 Hessian 矩阵的信息来指导搜索,以解决这个问题。其中最简单的方法是牛顿法(Newton's method)。牛顿法基于一个二阶泰勒展开来近似 x(0)x^{(0)}x(0) 附近的 f(x)f(x)f(x) :
f(x)≈f(x(0))+(x−x(0))⊤∇xf(x(0))+12(x−x(0))⊤H(f)(x(0))(x−x(0)). \begin{gather} f(x) \approx f\left(x^{(0)}\right)+\left(x-x^{(0)}\right)^{\top} \nabla_x f\left(x^{(0)}\right)+\frac{1}{2}\left(x-x^{(0)}\right)^{\top} \boldsymbol{H}(f)\left(x^{(0)}\right)\left(x-x^{(0)}\right) . \end{gather} f(x)≈f(x(0))+(x−x(0))⊤∇xf(x(0))+21(x−x(0))⊤H(f)(x(0))(x−x(0)).
接着通过计算,我们可以得到这个函数的临界点:
x∗=x(0)−H(f)(x(0))−1∇xf(x(0)). \begin{gather} x^*=x^{(0)}-\boldsymbol{H}(f)\left(x^{(0)}\right)^{-1} \nabla_x f\left(x^{(0)}\right) . \end{gather} x∗=x(0)−H(f)(x(0))−1∇xf(x(0)).
当 fff 是一个正定二次函数时,牛顿法只要应用一次式(11)就能直接跳到函数的最小点。如果 fff 不是一个真正二次但能在局部近似为正定二次,牛顿法则需要多次迭代应用式(11)。迭代地更新近似函数和跳到近似函数的最小点可以比梯度下降更快地到达临界点。这在接近局部极小点时是一个特别有用的性质,但是在鞍点附近是有害的。当附近的临界点是最小点(Hessian 的所有特征值都是正的)时牛顿法才适用,而梯度下降不会被吸引到鞍点(除非梯度指向鞍点)。
仅使用梯度信息的优化算法被称为一阶优化算法(first-order optimization al- gorithms),如梯度下降。使用 Hessian 矩阵的优化算法被称为二阶最优化算法(second-order optimization algorithms)(Nocedal and Wright,2006),如牛顿法。
在本书大多数上下文中使用的优化算法适用于各种各样的函数,但几乎都没有保证。因为在深度学习中使用的函数族是相当复杂的,所以深度学习算法往往缺乏保证。在许多其他领域,优化的主要方法是为有限的函数族设计优化算法。
在深度学习的背景下,限制函数满足 Lipschitz 连续(Lipschitz continuous)或其导数Lipschitz连续可以获得一些保证。Lipschitz 连续函数的变化速度以 Lipschitz常数(Lipschitz constant) L\mathcal{L}L 为界:
∀x,∀y,∣f(x)−f(y)∣≤L∥x−y∥2. \begin{gather} \forall x, \forall y,|f(x)-f(y)| \leq \mathcal{L}\|x-y\|_2 . \end{gather} ∀x,∀y,∣f(x)−f(y)∣≤L∥x−y∥2.
这个属性允许我们量化我们的假设——梯度下降等算法导致的输人的微小变化将使输出只产生微小变化,因此是很有用的。Lipschitz 连续性也是相当弱的约束,并且深度学习中很多优化问题经过相对较小的修改后就能变得 Lipschitz 连续。
最成功的特定优化领域或许是凸优化(Convex optimization)。凸优化通过更强的限制提供更多的保证。凸优化算法只对凸函数适用,即 Hessian 处处半正定的函数。因为这些函数没有鞍点而且其所有局部极小点必然是全局最小点,所以表现很好。然而,深度学习中的大多数问题都难以表示成凸优化的形式。凸优化仅用作一些深度学习算法的子程序。凸优化中的分析思路对证明深度学习算法的收玫性非常有用,然而一般来说,深度学习背景下凸优化的重要性大大减少。
4 约束优化
有时候,在 x\boldsymbol{x}x 的所有可能值下最大化或最小化一个函数 f(x)f(x)f(x) 不是我们所希望的。相反,我们可能希望在 x\boldsymbol{x}x 的某些集合 S\mathbb{S}S 中找 f(x)f(\boldsymbol{x})f(x) 的最大值或最小值。这被称为约束优化(constrained optimization)。在约束优化术语中,集合 S\mathbb{S}S 内的点 xxx 被称为可行(feasible)点。
我们常常希望找到在某种意义上小的解。针对这种情况下的常见方法是强加一个范数约束,如 ∥x∥≤1\|x\| \leq 1∥x∥≤1 。
约束优化的一个简单方法是将约束考虑在内后简单地对梯度下降进行修改。如果我们使用一个小的恒定步长 ϵ\epsilonϵ ,我们可以先取梯度下降的单步结果,然后将结果投影回 S\mathbb{S}S 。如果我们使用线搜索,我们只能在步长为 ϵ\epsilonϵ 范围内搜索可行的新 xxx 点,或者我们可以将线上的每个点投影到约束区域。如果可能的话,在梯度下降或线搜索前将梯度投影到可行域的切空间会更高效。
一个更复杂的方法是设计一个不同的,无约束的优化问题,其解可以转化成原始约束优化问题的解。例如,我们要在 x∈R2x \in \mathbb{R}^2x∈R2 中最小化 f(x)f(x)f(x) ,其中 x\boldsymbol{x}x 约束为具有单位 L2L^2L2 范数。我们可以关于 θ\thetaθ 最小化 g(θ)=f([cosθ,sinθ]⊤)g(\theta)=f\left([\cos \theta, \sin \theta]^{\top}\right)g(θ)=f([cosθ,sinθ]⊤) ,最后返回 [cosθ,sinθ][\cos \theta, \sin \theta][cosθ,sinθ]作为原问题的解。这种方法需要创造性;优化问题之间的转换必须专门根据我们遇到的每一种情况进行设计。
Karush-Kuhn-Tucker(KKT)方法是针对约束优化非常通用的解决方案。为介绍KKT方法,我们引入一个称为广义 Lagrangian(generalized Lagrangian)或广义Lagrange函数(generalized Lagrange function)的新函数。
为了定义Lagrangian,我们先要通过等式和不等式的形式描述 S\mathbb{S}S 。我们希望通过 mmm 个函数 g(i)g^{(i)}g(i) 和 nnn 个函数 h(j)h^{(j)}h(j) 描述 S\mathbb{S}S ,那么 S\mathbb{S}S 可以表示为 S={x∣∀i,g(i)(x)=\mathbb{S}=\left\{x \mid \forall i, g^{(i)}(x)=\right.S={x∣∀i,g(i)(x)= 0 and ∀j,h(j)(x)≤0}\left.\forall j, h^{(j)}(x) \leq 0\right\}∀j,h(j)(x)≤0} 。其中涉及 g(i)g^{(i)}g(i) 的等式称为等式约束(equality constraint),涉及 h(j)h^{(j)}h(j) 的不等式称为不等式约束(inequality constraint)。
我们为每个约束引入新的变量 λi\lambda_iλi 和 αj\alpha_jαj ,这些新变量被称为 KKT 乘子。广义 Lagrangian 可以如下定义:
L(x,λ,α)=f(x)+∑iλig(i)(x)+∑jαjh(j)(x). \begin{gather} L(x, \boldsymbol{\lambda}, \boldsymbol{\alpha})=f(x)+\sum_i \lambda_i g^{(i)}(x)+\sum_j \alpha_j h^{(j)}(x) . \end{gather} L(x,λ,α)=f(x)+i∑λig(i)(x)+j∑αjh(j)(x).
现在,我们可以通过优化无约束的广义 Lagrangian 解决约束最小化问题。只要存在至少一个可行点且 f(x)f(x)f(x) 不允许取 ∞\infty∞ ,那么
minxmaxλmaxα,α≥0L(x,λ,α)
\begin{gather}
\min _{\boldsymbol{x}} \max _{\boldsymbol{\lambda}} \max _{\boldsymbol{\alpha}, \boldsymbol{\alpha} \geq 0} L(\boldsymbol{x}, \boldsymbol{\lambda}, \boldsymbol{\alpha})
\end{gather}
xminλmaxα,α≥0maxL(x,λ,α)
与如下函数有相同的最优目标函数值和最优点集 xxx
minx∈Sf(x). \begin{gather} \min _{x \in \mathbb{S}} f(x) . \end{gather} x∈Sminf(x).
这是因为当约束满足时,
maxλmaxα,α≥0L(x,λ,α)=f(x), \begin{gather} \max _{\boldsymbol{\lambda}} \max _{\alpha, \alpha \geq 0} L(\boldsymbol{x}, \boldsymbol{\lambda}, \boldsymbol{\alpha})=f(\boldsymbol{x}), \end{gather} λmaxα,α≥0maxL(x,λ,α)=f(x),
而违反任意约束时,
maxλmaxα,α≥0L(x,λ,α)=∞. \begin{gather} \max _{\boldsymbol{\lambda}} \max _{\alpha, \boldsymbol{\alpha} \geq 0} L(\boldsymbol{x}, \boldsymbol{\lambda}, \boldsymbol{\alpha})=\infty . \end{gather} λmaxα,α≥0maxL(x,λ,α)=∞.
这些性质保证不可行点不会是最佳的,并且可行点范围内的最优点不变。
要解决约束最大化问题,我们可以构造 −f(x)-f(x)−f(x) 的广义 Lagrange 函数,从而导致以下优化问题:
minxmaxλmaxα,α≥0−f(x)+∑iλig(i)(x)+∑jαjh(j)(x). \begin{gather} \min _x \max _\lambda \max _{\alpha, \alpha \geq 0}-f(x)+\sum_i \lambda_i g^{(i)}(x)+\sum_j \alpha_j h^{(j)}(x) . \end{gather} xminλmaxα,α≥0max−f(x)+i∑λig(i)(x)+j∑αjh(j)(x).
我们也可将其转换为在外层最大化的问题:
maxxminλminα,α≥0f(x)+∑iλig(i)(x)−∑jαjh(j)(x). \begin{gather} \max _x \min _\lambda \min _{\alpha, \alpha \geq 0} f(x)+\sum_i \lambda_i g^{(i)}(x)-\sum_j \alpha_j h^{(j)}(x) . \end{gather} xmaxλminα,α≥0minf(x)+i∑λig(i)(x)−j∑αjh(j)(x).
等式约束对应项的符号并不重要;因为优化可以自由选择每个 λi\lambda_iλi 的符号,我们可以随意将其定义为加法或减法。
不等式约束特别有趣。如果 h(i)(x∗)=0h^{(i)}\left(x^*\right)=0h(i)(x∗)=0 ,我们就说这个约束 h(i)(x)h^{(i)}(x)h(i)(x) 是活跃 (active)的。如果约束不是活跃的,则有该约束的问题的解与去掉该约束的问题的解至少存在一个相同的局部解。一个不活跃约束有可能排除其他解。例如,整个区域(代价相等的宽平区域)都是全局最优点的凸问题可能因约束消去其中的某个子区域,或在非凸问题的情况下,收敛时不活跃的约束可能排除了较好的局部驻点。然而,无论不活跃的约束是否被包括在内,收敛时找到的点仍然是一个驻点。因为一个不活跃的约束 h(i)h^{(i)}h(i) 必有负值,那么 minxmaxλmaxα,α≥0L(x,λ,α)\min _{\boldsymbol{x}} \max _{\boldsymbol{\lambda}} \max _{\alpha, \boldsymbol{\alpha} \geq 0} L(\boldsymbol{x}, \boldsymbol{\lambda}, \boldsymbol{\alpha})minxmaxλmaxα,α≥0L(x,λ,α) 中的 αi=0\alpha_i=0αi=0 。因此,我们可以观察到在该解中 α⊙h(x)=0\alpha \odot \boldsymbol{h}(\boldsymbol{x})=0α⊙h(x)=0 。换句话说,对于所有的 i,αi≥0i, \alpha_i \geq 0i,αi≥0 或 h(j)(x)≤0h^{(j)}(x) \leq 0h(j)(x)≤0 在收敛时必有一个是活跃的。为了获得关于这个想法的一些直观解释,我们可以说这个解是由不等式强加的边界,我们必须通过对应的 KKT 乘子影响 x\boldsymbol{x}x的解,或者不等式对解没有影响,我们则归零 KKT 乘子。
我们可以使用一组简单的性质来描述约束优化问题的最优点,称为Karush-Kuhn-Tucker(KKT)条件。这些是确定一个点是最优点的必要条件,但不一定是充分条件。这些条件是:
- 广义 Lagrangian 的梯度为零。
- 所有关于 x\boldsymbol{x}x 和 KKT 乘子的约束都满足。
- 不等式约束显示的"互补松弛性": α⊙h(x)=0: ~ \alpha \odot \boldsymbol{h}(\boldsymbol{x})=0: α⊙h(x)=0 。
5 线性最小二乘
假设我们希望找到最小化下式的 xxx 值
f(x)=12∥Ax−b∥22. \begin{gather} f(x)=\frac{1}{2}\|\boldsymbol{A} x-\boldsymbol{b}\|_2^2 . \end{gather} f(x)=21∥Ax−b∥22.
存在专门的线性代数算法能够高效地解决这个问题;但是,我们也可以探索如何使用基于梯度的优化来解决这个问题,这可以作为这些技术是如何工作的一个简单例子。
首先,我们计算梯度:
∇xf(x)=A⊤(Ax−b)=A⊤Ax−A⊤b. \begin{gather} \nabla_x f(x)=\boldsymbol{A}^{\top}(\boldsymbol{A} \boldsymbol{x}-\boldsymbol{b})=\boldsymbol{A}^{\top} \boldsymbol{A} \boldsymbol{x}-\boldsymbol{A}^{\top} \boldsymbol{b} . \end{gather} ∇xf(x)=A⊤(Ax−b)=A⊤Ax−A⊤b.
然后,我们可以采用小的步长,并按照这个梯度下降。
我们也可以使用牛顿法解决这个问题。因为在这个情况下,真实函数是二次的,牛顿法所用的二次近似是精确的,该算法会在一步后收敛到全局最小点。
现在假设我们希望最小化同样的函数,但受 x⊤x≤1\boldsymbol{x}^{\top} \boldsymbol{x} \leq 1x⊤x≤1 的约束。要做到这一点,我们引人 Lagrangian
L(x,λ)=f(x)+λ(x⊤x−1). \begin{gather} L(x, \lambda)=f(x)+\lambda\left(x^{\top} x-1\right) . \end{gather} L(x,λ)=f(x)+λ(x⊤x−1).
现在,我们解决以下问题
minxmaxλ,λ≥0L(x,λ). \begin{gather} \min _x \max _{\lambda, \lambda \geq 0} L(x, \lambda) . \end{gather} xminλ,λ≥0maxL(x,λ).
我们可以用 Moore-Penrose 伪逆:x=A+bx=\boldsymbol{A}^{+} \boldsymbol{b}x=A+b 找到无约束最小二乘问题的最小范数解。如果这一点是可行,那么这也是约束问题的解。否则,我们必须找到约束是活跃的解。关于 xxx 对 Lagrangian 微分,我们得到方程
A⊤Ax−A⊤b+2λx=0. \begin{gather} \boldsymbol{A}^{\top} \boldsymbol{A} \boldsymbol{x}-\boldsymbol{A}^{\top} \boldsymbol{b}+2 \lambda \boldsymbol{x}=0 . \end{gather} A⊤Ax−A⊤b+2λx=0.
这就告诉我们,该解的形式将会是
x=(A⊤A+2λI)−1A⊤b. \begin{gather} x=\left(\boldsymbol{A}^{\top} \boldsymbol{A}+2 \lambda \boldsymbol{I}\right)^{-1} \boldsymbol{A}^{\top} \boldsymbol{b} . \end{gather} x=(A⊤A+2λI)−1A⊤b.
λ\lambdaλ 的选择必须使结果服从约束。我们可以关于 λ\lambdaλ 进行梯度上升找到这个值。为了做到这一点,观察
∂∂λL(x,λ)=x⊤x−1. \begin{gather} \frac{\partial}{\partial \lambda} L(x, \lambda)=x^{\top} x-1 . \end{gather} ∂λ∂L(x,λ)=x⊤x−1.
当 xxx 的范数超过 1 时,该导数是正的,所以为了跟随导数上坡并相对 λ\lambdaλ 增加 Lagrangian,我们需要增加 λ\lambdaλ 。因为 x⊤x\boldsymbol{x}^{\top} \boldsymbol{x}x⊤x 的惩罚系数增加了,求解关于 x\boldsymbol{x}x 的线性方程现在将得到具有较小范数的解。求解线性方程和调整 λ\lambdaλ 的过程将一直持续到 xxx 具有正确的范数并且关于 λ\lambdaλ 的导数是 0。