数值优化方法笔记
本文对常见的数值优化方法进行总结,重点关注优化方法的原理、迭代过程和计算复杂度。常见的数值优化方法包括梯度下降法(最速梯度下降法)、牛顿法、共轭梯度下降法等。本笔记的算法思路只是便于对各种优化方法进行理解,并不是完整的逻辑推导,如果想了解其中的数学推导,建议还是查看相关教材。(文章里公式渲染有点慢,需要等一会)
本文相关代码在https://github.com/flztiii/numerical_optimization_test.git
梯度下降算法
算法思路
考虑到以下问题,找到一个x∗使f(x∗)<f(x),∀x∈Rn。梯度下降算法的思路很简单:每一次迭代的点要比上一次次迭代点的值更小。用公式表达就是
$f(x_{k+1})$ < $f(x_{k}) \quad (1)$
接下来就是如何根据这个思路得到从xk到xk+1的增量Δx。可以对f(x)进行一阶泰勒展开,表达式如下所示
$f(x+\Delta x) = f(x) + f^{'}(x) \cdot \Delta x \quad (2)$
再根据公式(2),可以得到
$f(x+\Delta x) - f(x) = f^{'}(x) \cdot \Delta x$ < $0 \quad (3)$
那么,只要满足公式(4)的条件,就可以得到f(x+Δx) < f(x)。为了使公式(4)成立,可以令(总所周知,平方大于0)
$\Delta x = -\alpha \cdot f^{'}(x),\alpha$ > $0 \quad (4)$
所以,可以得到从xk到xk+1的迭代过程满足
$x_{k+1} = x_k + \Delta x = x_k - \alpha \cdot f^{'}(x_k) \quad (5)$
时,始终存在f(xk+1)<f(xk)。也就是一开始谈到的思路,只要不断寻找值更小的点,就可以最终找到最小值。
算法过程
- 给出初始点x0,学习率α
- 计算x0处的梯度f′(x0)
- 判断∣f′(x0)∣是否小于阈值δ,如果小于,停止迭代,算法结束
- 得到下一个迭代点x1=x0−α⋅f′(x0)
- 重复2-4过程
算法总结
梯度下降算法是最为基础的优化方法之一,它只需要知道梯度方法,不需要计算海森矩阵。计算复杂度较低。但是此方法容易陷入局部极小值,收敛结果对初始点和学习率的要求较高。
最速梯度下降
算法思路
最速梯度下降算法与梯度下降算法思路相似,都是希望每一次迭代的点要比上一次次迭代点的值更小。但是最速梯度下降算法与梯度下降算法的不同之处在于,它对学习率进行了调整,使学习率并不是一个固定值,而是不断变化的。
最速梯度下降算法希望在xk处沿梯度方法f(xk)下降时,找到一个学习率αk,使得沿f(xk)下降量比选择其他α都要大。用公式表达就是
$\alpha_k = argmin_{\alpha} f(x_k - \alpha \cdot f^{'}(x_k)) \quad (6)$
以上就是最速梯度下降算法的核心。接下来,使用二次型为例子,继续进行说明。(因为二次型具有比较好的性质)我们假设
$f(x) = \frac{1}{2} x^T A x - b^T x \quad (7)$
则可以计算得到f(x)的梯度和海森矩阵分别为
$f^{'}(x) = Ax - b \quad (8)$
$f^{''}(x) = A \quad (9)$
同时我们可以令
$g(\alpha) = f(x_{k+1})= f(x_k - \alpha f^{'}(x_k)) \quad (10)$
则公式(6)的必要条件为dαdg(α)=0。因此,我们通过公式(10)中可以得到
$ g^{'}(\alpha) = -f^{'}(x_{k+1})^T f^{'}(x_k)=0 \quad (11)$
将公式(8)代入公式(11)可以得到
$ f^{'}(x_{k+1})^T f^{'}(x_k) = (Ax_{k+1} - b)^T f^{'}(x_k) $
$ f^{'}(x_{k+1})^T f^{'}(x_k) = (A(x_k - \alpha f^{'}(x_k)) - b)^T f^{'}(x_k) $
$ f^{'}(x_{k+1})^T f^{'}(x_k) = (A x_k - b)^T f^{'}(x_k) - \alpha f^{'}(x_k)^T A f^{'}(x_k)$
$ f^{'}(x_{k+1})^T f^{'}(x_k) = f^{'}(x_k)^T f^{'}(x_k) - \alpha f^{'}(x_k)^T A f^{'}(x_k) = 0$
$ \alpha = \frac{f^{'}(x_k)^T f^{'}(x_k)}{ f^{'}(x_k)^T A f^{'}(x_k)} \quad (12) $
所以当待优化函数为二次型时,每一次的学习率的计算公式为公式(12)。梯度下降方法就变成最速梯度下降算法。
算法过程
- 给出初始点x0
- 计算x0处的梯度f′(x0)
- 判断∣f′(x0)∣是否小于阈值δ,如果小于,停止迭代,算法结束
- 计算当前梯度f^{’}(x_0)下的学习率,计算公式为α0=argminαf(x0−α⋅f′(x0))(如果f(x)为二次型,则计算公式为α0=f′(x0)TAf′(x0)f′(x0)Tf′(x0))(也可以使用Armijo-Goldstein准则或Wolfe-Powell准则)
- 得到下一个迭代点x1=x0−α0⋅f′(x0)
- 重复2-5过程
算法总结
最速梯度下降算法是在梯度下降算法基础上的改进,通过修改学习率,可以提高算法的收敛速度。但是仍然无法避免梯度下降容易被困于局部极小值的问题。
牛顿法
算法思路
牛顿法的思想与梯度下降不同,它并不是寻找比当前点具有更小值的点,而是从极小值的必要条件出发。我们知道,极小值的必要条件为梯度为0,也就是
$ f^{'}(x) = 0 \quad (13) $
从这一点出发,我们可以对f(x)进行二阶泰勒展开,如下所示
$ f(x + \Delta x) = f(x) + f^{'}(x) \Delta x + \Delta x^T f^{''}(x) \Delta x \quad (14)$
如果满足公式(13),则可以得到f(x+Δx)=f(x)。将其代入公式(14)可以得到
$ f^{'}(x) \Delta x + \Delta x^T f^{''}(x) \Delta x = 0$
$ \Delta x = -\frac{f^{'}(x)}{f^{''}(x)} \quad (15)$
这样可以得到每一次迭代的更新量。随着迭代的不断进行,最终可以找到待优化函数的极小值。
算法过程
- 给出初始点x0
- 计算x0处的梯度f′(x0)和海森矩阵f′′(x0)
- 判断∣f′(x0)∣是否小于阈值δ,如果小于,停止迭代,算法结束
- 得到下一个迭代点x1=x0−f′′(x0)f′(x0)
- 重复2-4过程
算法总结
相比于梯度下降方法,牛顿法收敛速度更快。但是,它需要计算海森矩阵,计算复杂度较高。如果待优化函数为最小二乘,则可以利用高斯-牛顿法,避免计算海森矩阵。
共轭梯度下降算法
算法思路
共轭梯度下降算法也是一种梯度下降。但与普通梯度下降、最速梯度下降不同之处在于,它下降的方向并不是梯度方向。其思路涉及到线性代数相关知识,比普通梯度下降要更加复杂。为了简化后续的说明,我们还是以二次型作为例子进行讲解,即
$f(x) = \frac{1}{2} x^T A x - b^T x \quad (16)$
在讲解之前,需要先说明一下什么是共轭。设A为n阶实对称正定矩阵,如果有两个n维向量d1和d2满足
$d_1^T A d_2 = 0$
则称向量d1和d2对于矩阵A共轭。若一组非零向量d0,d1,...,dn−1满足
$d_i^T A d_j = 0, i \neq j$
则称向量系di,(i=0,1,...,n−1)为关于矩阵A共轭。了解了共轭向量的概念后,可以很容易知道一组共轭向量di,(i=0,1,...,n−1)是线性无关的,证明如下。我们构造一组参数ai,(i=0,1,...,n−1),计算以下表达式成立时的ai。只要ai全部为0,则di,(i=0,1,...,n−1)是线性无关的。
$a_0 d_0 + a_1 d_1 + ... + a_{n-1} d_{n - 1} = 0$
我们让等式两边左侧同时乘上diTA,∀i,根据共轭的条件可以得到
$a_i d_i^T A d_i = 0, \forall i$
由于A为正定矩阵,diTAdi>0必然成立,因此,要让等式成立,必须ai=0,∀i。则可以证明di,(i=0,1,...,n−1)是线性无关的。
再回到待优化函数f(x)上。其中,x是n维向量,且公式(16)中的矩阵A为正定矩阵。我们可以假设,待优化函数f(x)取得最小值时的x为x∗,并且存在一组di,(i=0,1,...,n−1)关于矩阵A共轭。由之前的描述可以得到di是线性无关的。则可以使用di对x∗进行表达,表达式为
$x^* - x_0= \alpha_0 d_0 + \alpha_1 d_1 + ... + \alpha_{n-1} d_{n-1} \quad (17)$
那么,可以这样来看,从初始点x0开始,不断在上一个点基础上增加αidi,经过n次迭代,就可以得到最终解x∗,用公式表达就是
$x_{k+1} = x_k + \alpha_k d_k \quad (18)$
可以看到,与梯度下降的迭代公式一致。其中αk就是第k次迭代的学习率,而dk是下降方向。那么,下一步就是找到一组关于矩阵A共轭的方向向量dk。经过推导可以认为
$d_{k+1} = -g_{k+1} + \beta_k d_k \quad (19)$
$g_{k+1} = f^{'}(x_{k+1})$
接下来只要计算出βk即可。在公式(19)左侧同时乘上dkTA可以得到
$d_k^T A d_{k+1} = -d_k^T A g_{k+1} +\beta_k d_k^T A d_k=0 $
$\beta_k = \frac{-d_k^T A g_{k+1}}{d_k^T A d_k} \quad (20)$
下降方向已经得到了,迭代过程中唯一未知的量还有学习率αk。学习率的计算方法与公式(12)相同,最后计算得到的学习率为
$\alpha_k = -\frac{g_k^T d_k}{d_k^T A d_k}$
当然,以上公式只有在f(x)是二次型的时候才成立,路过不是二次型,需要借助其他方法进行求解。
算法过程
如果f(x)是二次型
- 设定k:=0,选择优化初始点x0
- 计算x0处的梯度g0=f′(x0),判断g0是否为0,如果是,结束迭代;反之,令d0=−g0
- 计算学习率αk=−dkTAdkgkTdk
- 得到新的点xk+1=xk+αkdk
- 计算梯度gk+1=f′(xk+1),判断gk+1是否为0,如果是,结束迭代
- 计算新的下降方向参数βk=dkTAdkgk+1TAdk
- 计算新的梯度下降方向dk+1=−gk+1+βkdk
- 重复3-7过程
如果f(x)不是二次型
- 设定k:=0,选择优化初始点x0
- 计算x0处的梯度g0=f′(x0),判断g0是否为0,如果是,结束迭代;反之,令d0=−g0
- 计算学习率αk=argminαf(xk+α⋅dk)(可以使用Armijo-Goldstein准则或Wolfe-Powell准则)
- 得到新的点xk+1=xk+αkdk
- 计算梯度gk+1=f′(xk+1),判断gk+1是否为0,如果是,结束迭代
- (a) 计算新的下降方向参数βk=gkTgkgk+1Tgk+1(Fletcher-Reeves Formula) (b) 计算新的下降方向参数βk=gkTgkgk+1T(gk+1−gk)(Polak-Ribiere Formula) © 计算新的下降方向参数βk=dkT(gk+1−gk)gk+1T(gk+1−gk)(Hestenes-Stiefel Formula)
- 计算新的梯度下降方向dk+1=−gk+1+βkdk
- 重复3-7过程
算法总结
共轭梯度下降算法对传统梯度下降算法的下降方向进行了优化,其收敛速度介于梯度下降算法和牛顿法之间。并且只需要计算梯度方向,计算复杂度较低。