多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
## 无约束最优化方法 最优化(Optimization)是工程技术、经济管理、 科学研究、社会生活中经常遇到的问题, 如:结构设计,资源分配,生产计划,运输方案等等。 最优化: 在一定条件下,寻求使目标最大(小)的决策解决优化问题的手段 • 经验积累,主观判断 • 作试验,比优劣 • 建立数学模型,求解最优策略 ### 优化问题的数学模型 无约束优化问题标准形式: 求n维决策变量x=[x1,x2,…,xn]T在可行域Ω中 使得目标函数f(x)→min,x⊆Ω⊆Rn ⇒ ![这里写图片描述](https://box.kancloud.cn/2016-07-25_5795bdc2f0216.jpg "") **可行解**只满足(2),**最优解**满足(1)(2) **无约束优化**只有(1),**约束优化**需要(1)(2) ### 无约束优化的基本方法 ### 求解无约束优化的基本思路:[下山法](http://blog.csdn.net/u013007900/article/details/43525733) #### 基本思想: 和爬山法基本思想一样,在Rn中某一点,确定一个**搜索放向**然后沿着该方向的**移动步长**,得到使目标函数下降的最新点。 #### 迭代步骤: Step 1 初始化:初始点x0,终止准则等 Step 2 迭代改进:方向dk,步长αk xk+1=xk+(αd)k 且 f(xk+1)<f(xk) Step 3 终止检验:得到近优解或k+1⇒k转2> 选择dk,αk使得f下降更快⇒利用不同的算法 ### 最速下降法(梯度法) 泰勒级数: ![](https://box.kancloud.cn/2016-07-25_5795bdc317591.png "") 其中Δx可正可负,但必须充分接近于0。 X沿D方向移动步长α后,变为X+αD。由泰勒展开式:![](https://box.kancloud.cn/2016-07-25_5795bdc32ec6e.png "") 目标函数:![](https://box.kancloud.cn/2016-07-25_5795bdc3439d9.png "") α确定的情况下即最小化:![](https://box.kancloud.cn/2016-07-25_5795bdc3547a3.png "") 向量的内积何时最小?当然是两向量方向相反时。所以X移动的方向应该和梯度的方向相反。 **下降方向:**∇fT(xk)dk<0 **最速下降方向:**dk=−∇f(xk)负梯度方向 **迭代改进形式:**xk+1=xk−∇f(xk) 算法特点:在初始状态改进较快,在最优解附近改进缓慢。 求函数f(x1,x2)=x21+4x22在极小点,以初始点X0=(1,1)T。 ~~~ #include"matrix.h"//大家自己YY一个矩阵类吧 #include<iostream> #include<iomanip> #include<cmath> #include<limits> #include<cassert> using namespace std; const int SIZE=2; const double ZETA=0.001; inline double func(Matrix<double> &X){ assert(SIZE==X.getRows()); double x1=X.get(0,0); double x2=X.get(1,0); return x1*x1+4*x2*x2; } inline Matrix<double> gradient(Matrix<double> &X){ assert(SIZE==X.getRows()); double x1=X.get(0,0); double x2=X.get(1,0); Matrix<double> rect(SIZE,1); rect.put(0,0,2*x1); rect.put(1,0,8*x2); return rect; } inline Matrix<double> Hesse(Matrix<double> &X){ Matrix<double> rect(SIZE,SIZE); rect.put(0,0,2); rect.put(0,1,0); rect.put(1,0,0); rect.put(1,1,8); return rect; } int main(int agrc,char *argv[]){ Matrix<double> X(SIZE,1); X.put(0,0,1); X.put(1,0,1); int iteration=0; double value=func(X); double newValue=numeric_limits<double>::max(); while(++iteration){ Matrix<double> G=gradient(X); double factor=((G.getTranspose()*G).get(0,0))/((G.getTranspose()*Hesse(X)*G).get(0,0)); for(int i=0;i<G.getRows();++i) for(int j=0;j<G.getColumns();++j) G.put(i,j,G.get(i,j)*factor); Matrix<double> newX=X-G; //cout<<"X=["<<newX.get(0,0)<<","<<newX.get(1,0)<<"]"<<endl; newValue=func(newX); if(fabs(newValue-value)<ZETA) break; else{ X=newX; value=newValue; } //cout<<"本次迭代找到的极小值"<<value<<endl; } cout<<"迭代次数"<<iteration<<endl; cout<<"极小值"<<value<<endl; return 0; } ~~~ > 这份算法使用的是利用Hesse矩阵和泰勒公式计算最优步长 若f(X)具有二阶连续偏导,由泰勒展开式可得: ![](https://box.kancloud.cn/2016-07-25_5795bdc368a0b.png "") H是f(X)的Hesse矩阵。 ![](https://box.kancloud.cn/2016-07-25_5795bdc37ab36.png "") 可得最优步长: ![](https://box.kancloud.cn/2016-07-25_5795bdc38d688.png "") g是f(X)的梯度矩阵。 此时: ![](https://box.kancloud.cn/2016-07-25_5795bdc39f52f.png "") 可见最速下降法中最优步长不仅与梯度有关,而且与Hesse矩阵有关。 ### 牛顿迭代法 将f(xk+1)在xk点作泰勒展开至二阶项,用d替代dk,有 f(xk+1)=f(xk+d)=f(xk)+∇fT(xk)d+12dT∇2f(xk)d 求d使得f(xk+1)极小⇒右端对d的导数为0⇒∇f(xk)+∇2f(xk)d=0 可得到> **牛顿方程**∇2f(xk)d = −∇f(xk) **牛顿方向**dk = −(∇2f(xk))−1∇f(xk) **迭代格式**xk+1 = xk−(∇2f(xk))−1∇f(xk) 其中∇2f(xk)为[Hessen矩阵](http://baike.baidu.com/link?url=E2wdH1BhTKFos1JYd_NhHvkmGAyABsHJDIgSyygvzTuoAs41tvb4OGzzWThbUMwobdBAEPpS7nzia-GQUHHf7a) 可见x的搜索方向是−(∇2f(xk))−1∇f(xk),函数值在此方向上下降,就需要它与梯度方向相反,即−∇f(xk)(∇2f(xk))−1∇f(xk)<0,所以要求在每一个迭代点上Hessian矩阵必须是正定的。 算法特点: 牛顿法是二次收敛的,并且收敛阶数是2。一般目标函数在最优点附近呈现为二次函数,于是可以想像最优点附近用牛顿迭代法收敛是比较快的。而在开始搜索的几步,我们用梯度下降法收敛是比较快的。将两个方法融合起来可以达到满意的效果。 收敛快是牛顿迭代法最大的优点,但也有致命的缺点:Hessian矩阵及其逆的求解计算量大,更何况在某个迭代点Xk处Hessian矩阵的逆可能根本就不存在(即Hessian 矩阵奇异),这样无法求得Xk+1。 求f(x1,x2)=(x1−2)4+(x1−2x2)2的极小点,初始点取X=(0,3)T ~~~ #include"matrix.h" #include<iostream> #include<iomanip> #include<cmath> #include<limits> #include<cassert> using namespace std; const int SIZE=2; const double ZETA=0.001; inline double func(Matrix<double> &X){ assert(SIZE==X.getRows()); double x1=X.get(0,0); double x2=X.get(1,0); return pow(x1-2,4)+pow(x1-2*x2,2); } inline Matrix<double> gradient(Matrix<double> &X){ assert(SIZE==X.getRows()); double x1=X.get(0,0); double x2=X.get(1,0); Matrix<double> rect(SIZE,1); rect.put(0,0,4*pow(x1-2,3)+2*(x1-2*x2)); rect.put(1,0,-4*(x1-2*x2)); return rect; } inline Matrix<double> Hesse(Matrix<double> &X){ Matrix<double> rect(SIZE,SIZE); double x1=X.get(0,0); double x2=X.get(1,0); rect.put(0,0,12*pow(x1-2,2)+2); rect.put(0,1,-4); rect.put(1,0,-4); rect.put(1,1,8); return rect; } int main(int agrc,char *argv[]){ Matrix<double> X(SIZE,1); X.put(0,0,0); X.put(1,0,3); int iteration=0; double value=func(X); double newValue=numeric_limits<double>::max(); while(++iteration){ Matrix<double> G=gradient(X); Matrix<double> H=Hesse(X); Matrix<double> newX=X-H.getInverse()*G; cout<<"X=["<<newX.get(0,0)<<","<<newX.get(1,0)<<"]"<<endl; newValue=func(newX); if(fabs(newValue-value)<ZETA) break; else{ X=newX; value=newValue; } cout<<"本次迭代找到的极小值"<<value<<endl; } cout<<"迭代次数"<<iteration<<endl; cout<<"极小值"<<value<<endl; return 0; } ~~~ ### 拟牛顿法 Hessian矩阵在拟牛顿法中是不计算的,拟牛顿法是构造与Hessian矩阵相似的正定矩阵,这个构造方法,使用了目标函数的梯度(一阶导数)信息和两个点的“位移”(Xk−Xk−1)来实现。 有人会说,是不是用Hessian矩阵的近似矩阵来代替Hessian矩阵,会导致求解效果变差呢?事实上,效果反而通常会变好。 拟牛顿法与牛顿法的迭代过程一样,仅仅是各个Hessian矩阵的求解方法不一样。 在远离极小值点处,Hessian矩阵一般不能保证正定,使得目标函数值不降反升。而拟牛顿法可以使目标函数值沿下降方向走下去,并且到了最后,在极小值点附近,可使构造出来的矩阵与Hessian矩阵“很像”了,这样,拟牛顿法也会具有牛顿法的二阶收敛性。 对目标函数f(X)做二阶泰勒展开: f(x)=f(xk+1)+(x−xk+1)T∇f(xk+1)+12(x−xk+1)TG(xk+1)(x−xk+1) 其中∇2f(xk) ⇔G(xk+1) 上式两边对x求导: ∇f(x)=∇f(xk+1)+G(xk+1)(x−xk+1) 当x=xk的时候,有 G−1(xk+1)[∇f(xk+1)−∇f(xk)]=xk+1−xk 这里我们用Hk表示在点xk处的Hessian矩阵的**逆矩阵** Hk+1[∇fd(xk+1)−∇f(xk)]=xk+1−xk ......(5) (5)式就是**拟牛顿方程** 下面提供两种拟牛顿法 ![这里写图片描述](https://box.kancloud.cn/2016-07-25_5795bdc3b5dd4.jpg "") ### 非线性最小二乘(Least Square)拟合 问题: 给定(ti,yi),i=1,…n, 拟合一个函数y=f(t,x), 其中x为待定的参数向量, f 对x非线性。 记误差ri(x)=yi−f(ti,x)     r(x)=(r1(x),…,rn(x))T 优化模型: minxR(x)=rT(x)r(x) 记r(x)的雅克比行列式为J(x)=(∂ri∂xj)n×m ∇R=2J(x)Tr(x)∇2R=2J(x)TJ(x)+2SS=∑ni=1ri(x)∇2ri(x)∇2ri(x)=(∂2ri∂xk∂xl)n×m 牛顿法要计算Hessian矩阵,其中S计算量大 若f 对x线性, 则化为线性最小二乘拟合, 此时 S=0 特定算法考虑如何忽略或近似矩阵S #### Gauss-Newton算法(GN):忽略矩阵S ∇R=2J(x)Tr(x)∇2R=2J(x)TJ(x) 牛顿方程:∇2f(xk)d=−∇f(xk) f用R代替,下降方向dk满足 J(x)TJ(x)dk=−J(x)Tr(x) GN算法收敛性特点: S=∑ni=1ri(x) 收敛性依赖f对x的线性程度,即偏差r的大小(”小残差问题“) #### LM算法: Levenbery (1944), Marquardt (1963) G-N算法修正 J(x)TJ(x)dk=−J(x)Tr(x) ⇓ (J(x)TJ(x)+αkI)dk=−J(x)Tr(x) 其中αk>0为修正参数,防止JTJ出现病态。 LM算法特点 dk位于GN方向(αk很小)和负梯度方向(αk很大)之间 LM算法的另一种观点 min∥r(xk)+J(xk)(x−xk)∥2 s.t.     ∥x−xk∥2≤hk    (∗)置信域 其解为 (J(x)TJ(x)+αkI)dk=−J(x)Tr(x) 若GN方向满足约束(*),αk=0,否则ak>0 置信域算法特点: 先确定最长步长hk,再确定方向dk