在坐标轮换法中,可知其收敛速度慢,且受到等值线的形状的影像。原因可归结为其搜索方向总是平行于坐标轴,不适应函数的变换情况。针对这样的问题,共轭方向可以较好解决。
那什么叫共轭方向呢?
共轭方向
这里,我们设为的对称正定矩阵,如果有两个维向量和满足,则和是关于是共轭的。很明显,当时,两向量是正交的,说明正交是共轭的特例。如果一组方向向量两两都关于共轭,那么这一组向量可称为共轭方向向量。
共轭方向有一个重要性质,就是对于正定二次函数,从任意初始点开始出发,一次沿关于 共轭方向进行一维搜索,至多步可以收敛到极小点。这个是可以证明的。这里我们给出简单理解,比如对于坐标轮换法,如果椭圆簇的长短轴和坐标方向一致,迭代步可以收敛到极小值,共轭方向相当于作用于,使得在新的坐标系下和坐标方向一致。可见共轭方向方法重点就在于共轭方向的构建上。一种简单的构建的方式是求的特征向量,但是对于大规模的优化问题,特征向量求解很耗时。还有一种采用改进的Gram-Schmidt正交方法得到共轭方向,然而 这种方法也很耗时,且需要存储整个向量。基于这些问题,Powell提出了加速的方法。
Powell方法
Powell与1964年提出方向加速法,也是一种共轭方向法,针对的问题也是考虑正定二次函数的无约束最优化问题。Powell方法主要有三部分构成,即基本搜索、加速搜索和调整搜索方向。
基本搜索:包括从基点出发沿着已知的 个线性无关的搜索方向进行一维搜索,确定一个新的基点;
加速搜索:指这将第一轮起点和新确定的基点相连构成新的方向,进行一维搜索使得函数值下降;
调整搜索:将这一轮方向组的第一个方向去掉,新的方向补充在最后构成新的方向组,进行下一轮迭代。
如图2所示,针对坐标轮换方法中提到几个问题,Powell方法收敛速度更快。对于具有脊线的问题也能得到优解。然而Powell方法对于维度的能得到满意的结果,高维度的优化问题并不合适,其次不用说对于高维的复杂函数,就是对于二次函数,Powell方法也可能无效。因为算法中,没有衡量过后续的个搜索方向是否变成线性相关。一旦搜索方向存在相关关系,就不能形成共轭方向,从而构不成维空间,导致后续的迭代在降维的空间中进行,发生退化,得不到极小值点。 为此Powell又进行了改进。
Algorithm 1 Powell方法
function [x_min,f_min] = ConjugateDirectionMethod(func,x0,options)
%Powell
if nargin<3
options.tol = 1e-12;
options.iterNum = 1000;
options.bracketMethod = '';
options.linearSrcMethod = '';
options.plot2.Flag = 0;
options.plot2.x = [];
options.plot2.y = [];
options.plot2.z = [];
end
tol = options.tol;
iterNum = options.iterNum;
plot2 = options.plot2;
if length(x0)~=2
plot2.Flag = 0;
end
x_min = x0;
f_min = func(x0);
E = eye(length(x0));
%E = [1,0;-1,1];
xk = x0;
f_pre = func(xk);
f = f_pre+1e10;
if plot2.Flag == 1
figure,subplot(1,2,1),axis equal, hold on;
contourf(plot2.x,plot2.y,plot2.z,30,'linestyle','-')
colormap('jet');
tempf =f_pre;
end
while(iterNum)
x1k = xk;
for i=1:1:length(x0)
d = E(:,i);
lamdaFuncH = @(lamda)(func(xk+lamda.*d));
[a,b,c] = bracketAdvanceBack(lamdaFuncH,0,0.01);
lamda = GoldSection(lamdaFuncH,a,c,1e-12);
xk1 = xk + lamda.*d;
f =func(xk1);
if plot2.Flag == 1
tempf = [tempf,f];
subplot(1,2,1),plot([xk(1),xk1(1)],[xk(2),xk1(2)],'-o','LineWidth',2);
subplot(1,2,2),plot(tempf,'-b.','LineWidth',2); grid on;
axis([0,60,-10,func(x0)]);
xlabel('Step');
ylabel('Objective Function Value');
end
xk = xk1;
iterNum = iterNum - 1;
end
d = xk-x1k;
lamdaFuncH = @(lamda)(func(xk+lamda.*d));
[a,b,c] = bracketAdvanceBack(lamdaFuncH,0,0.01);
lamda = GoldSection(lamdaFuncH,a,c,1e-12);
xk1 = xk + lamda.*d;
f =func(xk1);
if plot2.Flag == 1
tempf = [tempf,f];
subplot(1,2,1),plot([xk(1),xk1(1)],[xk(2),xk1(2)],'-o','LineWidth',2);
subplot(1,2,2),plot(tempf,'-b.','LineWidth',2); grid on;
axis([0,60,-10,func(x0)]);
xlabel('Step');
ylabel('Objective Function Value');
end
xk = xk1;
iterNum = iterNum - 1;
if abs(f-f_pre)
Powell改进方法
为了避免Powell方法中退化问题,Powell进行了改进。在构成的环基本方向组时,首先判断前一环的基本方向组是否需要更换;还要进一步判断前一环的原基本方向组中某一方向作为一维搜索函数值下降量最大,去掉该方向后再将新的方向步入最后。保证第 环基本方向组时线性无关的并最接近共轭。
具体步骤为:
- 给定初始点,选取个线性无关的方向组(初始为坐标单位向量);
- 从这一轮的初始点出发,顺次沿方向进行一维搜索,得到 个点;
- 以最后一点为起点,沿最后一点和第一个点的连线方向移动,最后一点到第一个点的距离。这里就得到三点,即起点、终点和反射点,对应的坐标和函数值我们记作:
- 计算各中间点的函数值,以及下降量,求得下降量最大值以及对应的方向;
- 判断 和 来确定是否要对原方向组进行替换;
- 不满足条件,则下一轮迭代仍用原方向组,并以终点和反射点函数 值小者最为下一轮的迭代始点;
- 满足条件,则将去除,起点和终点的连线方向放入方向组的最后作为下一轮的迭代方向组,而下一轮迭代的起点为以终点为起点沿连线方向一维搜索的最优点。
- 判断终止条件,满足终止,反之进行下一轮迭代。
Algorithm 2 Powell改进方法
function [x_min,f_min] = PowellImprovedMethod(func,x0,options)
%Powell
if nargin<3
options.tol = 1e-12;
options.iterNum = 1000;
options.bracketMethod = '';
options.linearSrcMethod = '';
options.plot2.Flag = 0;
options.plot2.x = [];
options.plot2.y = [];
options.plot2.z = [];
end
tol = options.tol;
iterNum = options.iterNum;
plot2 = options.plot2;
if length(x0)~=2
plot2.Flag = 0;
end
x_min = x0;
f_min = func(x0);
E = eye(length(x0));
xk = x0;
f_pre = func(xk);
f = f_pre+1e10;
if plot2.Flag == 1
figure,subplot(1,2,1),axis equal, hold on;
contourf(plot2.x,plot2.y,plot2.z,30,'linestyle','-')
colormap('jet');
tempf =f_pre;
end
while(iterNum)
x1k = xk;
deltaM_max = -inf;
di = 1;
for i=1:1:length(x0)
d = E(:,i);
lamdaFuncH = @(lamda)(func(xk+lamda.*d));
[a,b,c] = bracketAdvanceBack(lamdaFuncH,0,0.01);
lamda = GoldSection(lamdaFuncH,a,c,1e-12);
xk1 = xk + lamda.*d;
f =func(xk1);
if plot2.Flag == 1
tempf = [tempf,f];
subplot(1,2,1),plot([xk(1),xk1(1)],[xk(2),xk1(2)],'-o','LineWidth',2);
subplot(1,2,2),plot(tempf,'-b.','LineWidth',2); grid on;
axis([0,60,-10,func(x0)]);
xlabel('Step');
ylabel('Objective Function Value');
end
deltaM = func(xk) - f;
if deltaM_max
Powell改进的方法虽然考虑了每轮的方向组的线性相关性,但是如果初始方向给的是单位坐标向量,很可能一直都是坐标方向向量,退化成坐标轮换法,对于存在脊线的优化问题,依然存在问题。