与其说线搜法是一个方法,不如说它是一个过程:在算出的下降方向(dk ) 上计算移动步长(α)的过程。既然下降方向不是线搜法算出来的,说明线搜法不是单独使用的,而是需要嵌套在计算下降方向的方法中使用,比如梯度下降法、牛顿法、拟牛顿法。
Armijo方法中需要用到几个参数:
a>0 , σ∈(0,1) ,γ∈(0, 0.5)
PS: a一般取a=1, σ 和 γ 的值需要根据收敛效果调整取值。根据个人的试验发现,σ 越大收敛速度越慢,γ 越大收敛速度越快。
然后得到一个关于步长α的点集:
A = { α ∈ R : α = a σ j , j = 0 , 1 , . . . } A=\{ \alpha\in R: \alpha=a\sigma^j, j=0,1,... \} A={ α∈R:α=aσj,j=0,1,...}
在这个方法中, 我们想要找到A集里最大的α,使得下面不等式成立:
f ( x k + α d k ) − f ( x k ) ≤ γ α ▽ f ( x k ) ′ d k ( 1.1 ) f(x_k+\alpha d_k)-f(x_k) \le \gamma \alpha \bigtriangledown f(x_k)'d_k (1.1) f(xk+αdk)−f(xk)≤γα▽f(xk)′dk(1.1)
综上,代码里面的实现思路可以列为3个步骤:
1. 设 α=a, 设 σ 和 γ 的值。
2. 把上面的参数代入式子(1.1)中检验α是否满足条件;如果满足,则输出该α。
3. 如果不满足,则令 α = σ a \alpha =\sigma a α=σa
然后重复步骤2,检验新的α是否满足条件,直至找到满足条件的α。
function [alpha_armijo] = armijo(x,d,f0,f1)
% x是每次循环中得到的函数的解,d是下降方向
% f0是原目标函数, f1是目标函数的一次导数
alpha = 1; % a>0
gamma = 0.4; % 取值范围(0,0.5)越大越快
sigma = 0.5; % 取值范围(0,1)越大越慢
j = 1; %循环标志
while (j>0)
x_new = x+alpha.*d;
if f0(x_new(1),x_new(2))<=f0(x(1),x(2))+gamma*alpha.*f1(x(1),x(2))'*d %检验条件
j = 0; % 循环break
alpha_armijo = alpha;
else
alpha = alpha*sigma; %缩小alpha,进入下一次循环
end
end
这里我将配合最速下降法来说明如何把Armijo线搜法嵌套在计算下降方向的方法中使用。最速下降法的计算结构就不在这里详细介绍啦~ 有空我再写单独介绍各种计算下降方向的方法。
clc;
clear;
syms x1 x2;
f = 100*(x2-x1^2)^2+(1-x1)^2; %这是一个Rosenbrock函数,用来测试最佳化演算法性能的非凸函数,也被称为香蕉函数。该函数的特点是只有一个全局最低点。
f = matlabFunction(f); % 将符号表达式转换为函数句柄或文件
% 画出函数的水平集,然后hold on,待会会在这个图上显示出每一个迭代步长和迭代结果噢
figure(1); clf; ezcontour(f,[-1.5 1.5 -1.5 1.5]); axis equal; hold on
f_sym = sym(f); %将函数句柄转换回符号表达式
F_td = matlabFunction(gradient(f_sym));% 求一次导数
x0 = [-3/4 1]'; % 给一个收敛的起始点
eps = 1e-5; % 设可容误差为一个很接近0的数
k=0; % 设k=0, 用来记录迭代次数
f_td = F_td(x0(1),x0(2)); %计算一次导数在起始点的值
while norm(f_td) > eps %设置一个条件为一次导数的值大于可容误差的循环
d= - f_td; % 计算下降方向(最速下降法的定义噢)
[alpha_armijo] = armijo_1(x0,d,f,F_td) %嵌套Armijo线搜法
xnew = x0 + alpha_armijo*d; %在起始点上通过Armijo得到的步长迭代出新的点。
% 在上面hold on的水平集里面画出新的迭代结果(点)。
plot([x0(1) xnew(1)],[x0(2) xnew(2)],'ko-')
refresh
x0 = xnew; %用迭代点覆盖起始点,每次循环就覆盖上一个点
f_td = F_td(x0(1),x0(2)) %计算出函数的一次导在迭代点上面的值,用于循环条件的判断
k = k+1; %迭代次数+1
end
x = x0 %最后循环结束得到的最终迭代点就是函数的最优点
result = f(x(1),x(2)) %函数在该最优点的值(局部最小值)
最后,以上的例子得到的图是这样的: