蛮久前学过了凸优化理论,今天要用到重温了一下。
只是mark一下优秀的博客~
转自华夏35度的无约束最优化方法及 拉格朗日乘子法和KKT条件。
几个重要概念:
梯度:方向与等值面垂直,并且指向函数值提升的方向。
正定二次型函数:
n 阶实对称矩阵
Q ,对于任意的非0向量 X ,如果有XTQX>0 ,则称 Q 是正定矩阵。
对称矩阵Q 为正定的充要条件是: Q 的特征值全为正。
二次函数:f(x)=12XTQX+bTX+c
若 Q 是正定的,则称f(X) 为正定二次函数。二次收敛:指一个算法用于具有正定二次型函数时,在有限步可达到它的极小点。二次收敛与二阶收敛没有尽然联系,更不是一回事,二次收敛往往具有超线性以上的收敛性。一阶收敛不一定是线性收敛。
黄金分割法
黄金分割法适用于任何单峰函数求极小值问题。
求函数在[a, b]上的极小点,我们在[a, b]内取两点c,d,使得 a<c<d<b 。并且有
- 如果 f(c)<f(d) ,则最小点出现在[a, d]上,因此[a, d]成为下一次的搜索区间。
- 如果 f(c)>f(d) ,则[c,b]成为下一次的搜索区间。
假如确定了[a, d]是新的搜索区间,我们并不希望在[a, d]上重新找两个新的点使之满足(1)式,而是利用已经抗找到有c点,再找一个e点,使满足:
可以解得 r=0.382 ,而黄金分割点是0.618。
练习:求函数 f(x)=x2−10⋅x+36 在[1, 10]上的极小值。
#include<stdio.h>
#include<math.h>
#include<limits.h>
double func(double x){
return x*x-10*x+36;
}
void main(){
double zeta=0.001;
double a=1.0,b=10.0;
double t1=a-1;
double t2=b+1;
double v1=0.0;
double v2=0.0;
double min_value=INT_MAX;
int iteration=0;
while(++iteration){
if(t1==a-1){
t1=a+0.382*(b-a);
v1=func(t1);
}
if(t2==b+1){
t2=a+0.618*(b-a);
v2=func(t2);
}
if(v1<v2){
min_value=v1;
b=t2;
t2=t1;
v2=v1;
t1=a-1;
}
else{
min_value=v2;
a=t1;
t1=t2;
v1=v2;
t2=b+1;
}
if(fabs(b-a)<zeta)
break;
printf("当前极小值%f\n",min_value);
}
printf("迭代次数%d\n",iteration);
printf("极小值%f\n",min_value);
}
最速下降法
利用梯度信息不断优化目标函数
泰勒级数告诉我们:
其中 Δx 可正可负,但必须充分接近于0。
X⃗ 沿 D⃗ 方向移动步长 α 后,变为 X⃗ +aD⃗ 。由泰勒展开式:
目标函数:
α 确定的情况下,即最小化:
min∇f(X⃗ )D⃗
向量的内积何时最小?当然是两向量方向相反时。所以 X⃗ 移动的方向应该和梯度的方向相反。
接下来的问题是步长 α 应该怎么定才能使迭代的次数最少?
若 f(X) 具有二阶连续偏导,由泰勒展开式可得: