模拟退火算法
简介
在了解模拟退火算法之前,首先介绍爬山算法。
爬山算法(Hill Climbing)
该算法每次从当前解的临近解空间中选择一个最优解作为当前解,直到达到一个局部最优解。这也是其主要缺点:陷入局部最优解。
举例如下:
我们需要寻找这个函数图像的最小值,假设以A为起点,爬山算法搜索到B点这一局部最优解时就会停止搜索,因为在B点无论向那个方向小幅度移动都不能得到更优的解。
模拟退火算法(SA)
模拟退火算法思想来源于固体退火原理,是一种基于概率的算法,将固体加温至充分高,再让其缓慢冷却,加温时,固体内部粒子随温度升高变为无序状,内能增大,而冷却时粒子渐趋有序,在每个温度都达到平衡态,最后在常温时达到基态,内能减为最小。
模拟退火算法从某一较高初温出发,伴随温度参数的不断下降,结合概率突跳特性在解空间中随机寻找目标函数的全局最优解,即在局部最优解能概率性地跳出并最终趋于全局最优。也就是说,模拟退火算法以一定的概率来接受一个比当前解要差的解,因此有可能会跳出这个局部的最优解,达到全局的最优解。
原理
模拟退火算法包含两个部分,即Metropolis算法和退火过程。Metropolis算法保证了其能不被局限于局部最优解。1953年Metropolis提出重要性采样方法,即以概率来接受新状态,而不是使用完全确定的规则,称为Metropolis准则。
Metropolis准则
假设系统前一个状态为
,系统根据某一指标,状态变为
,相应地,系统的能量由
变为
,定义系统由
变为
的接受概率为
,则
从上式我们可以看到,如果能量减小了,那么这种转移就被接受(概率为1),如果能量增大了,就说明系统偏离全局最优值位置更远了,此时算法不会立刻将其抛弃,而是进行概率操作:首先在区间
产生一个均匀分布的随机数
,如果
,则接受此种转移,否则拒绝转移,进入下一步,往复循环。其中能量的变化量和T决定概率P的大小,所以这个值是动态的。
退火算法的参数控制
Metropolis算法是模拟退火算法的基础,在上面的公式中,可以调节的参数就是T,T如果过大,就会导致退火太快,达到局部最优值就会结束迭代,如果取值较小,则计算时间会增加。实际应用中,在退火初期常采用较大的T值,随着退火的进行,逐步降低。
参数控制的具体原则如下:
-
初始的温度T(0)应选的足够高,使的所有转移状态都被接受。初始温度越高,获得高质量的解的概率越大,但耗费的时间越长。
-
退火温度应以合适的速度下降。最简单的下降方式是指数式下降:
其中是小于1的正数,一般取值为0.8到0.99之间。使的对每一温度,有足够的转移尝试,指数式下降的收敛速度比较慢,其他下降方式如下:
-
终止温度:如果在若干次迭代的情况下没有可以更新的新状态或者达到用户设定的阈值,则退火完成。
实现
模拟退火算法的基本思想
(1) 初始化:初始温度T,初始解状态S(是算法迭代的起点),每个T值的迭代次数L
(2) 对 做第(3)至第6步:
(3) 产生新解S′
(4) 计算增量 ,其中 为评价函数
(5) 若 则接受S′作为新的当前解,否则以Metropolis准则接受S′作为新的当前解.
(6) 如果满足终止条件则输出当前解作为最优解,结束程序。终止条件通常取为连续若干个新解都没有被接受时终止算法。否则转第7步
(7) T逐渐减少,且T->0,然后转第2步。
模拟退火算法的伪代码
/*
* C(y):在状态X的评价函数值
* X(i):表示当前状态
* X(i+1):表示新的状态
* r: 用于控制降温的快慢
* T: 系统的温度,系统初始应该要处于一个高温的状态
* T_min :温度的下限,若温度T达到T_min,则停止搜索
*/
while( T > T_min )
{
i=0;
while(i<L)//L为每个温度下的迭代次数
{
dE = C( X(i+1) ) - C( X(i) ) ;
if (dE<=0) //表达移动后得到更优解,则总是接受移动
X(i+1) = X(i) ; //接受移动
else
{
if ( exp( -dE/T ) > random( 0 , 1 ) )
X(i+1) = X(i) ; //接受移动
}//跳出局部最优
i ++ ;
}
T = r * T ; //降温退火 ,0<r<1 。r越大,降温越慢;r越小,降温越快
/*
* 若r过大,则搜索到全局最优解的可能会较高,但搜索的过程也就较长。若r过小,则搜索的过程会很快,但最终可能会达到一个局部最优值
*/
}
应用
使用模拟退火算法解决旅行商问题(TSP)。TSP问题是一个组合优化问题。该问题可以被证明具有NPC计算复杂性
假设有一个旅行商人要拜访n个城市,他必须选择所要走的路径,路径的限制是每个城市只能拜访一次,而且最后要回到原来出发的城市。路径的选择目标是要求得的路径路程为所有路径之中的最小值。
可以使用模拟退火算法寻找一个较优(也许是全局最优)的解法
MATLAB软件实现如下:
function D = Distance(citys)
%% 计算两城市之间的距离
% 输入 citys 各城市的位置坐标
% 输出 D 两两城市之间的距离
n = size(citys,1);
D = zeros(n,n);
for i = 1:n
for j = i+1:n
D(i,j) = sqrt(sum((citys(i,:) - citys(j,:)).^2));
D(j,i) = D(i,j);
end
end
function DrawPath(Route,citys)
%% 绘制路径
%输入
% Route 待画路径
% citys 各城市坐标位置
figure
plot([citys(Route,1);citys(Route(1),1)],...
[citys(Route,2);citys(Route(1),2)],'o-');
grid on
for i = 1:size(citys,1)
text(citys(i,1),citys(i,2),[' ' num2str(i)]);
end
text(citys(Route(1),1),citys(Route(1),2),' 起点');
text(citys(Route(end),1),citys(Route(end),2),'
function p = OutputPath(R)
%% 输出路径
% 输入:R 路径
R = [R,R(1)];
N = length(R);
p = num2str(R(1));
for i = 2:N
p = [p,'―>',num2str(R(i))];
end
disp(p)
function Length = PathLength(D,Route)
%% 计算各路径长度
% 输入:
% D 两两城市之间的距离
% Route 个体的轨迹
Length = 0;
n = size(Route,2);
for i = 1:(n - 1)
Length = Length + D(Route(i),Route(i + 1));
end
Length = Length + D(Route(n),Route(1));
function [S,R] = Metropolis(S1,S2,D,T)
%% Metropolis准则
%% 输入
% S1: 当前解
% S2: 新解
% D: 距离矩阵(两两城市的之间的距离)
% T: 当前温度
%% 输出
% S: 下一个当前解
% R: 下一个当前解的路线距离
R1 = PathLength(D,S1); %计算路线长度
N = length(S1); %得到城市的个数
R2 = PathLength(D,S2); %计算路线长度
dC = R2 - R1; %计算能力之差
if dC < 0 %如果能力降低 接受新路线
S = S2;
R = R2;
elseif exp(-dC/T) >= rand %以exp(-dC/T)概率接受新路线
S = S2;
R = R2;
else %不接受新路线
S = S1;
R = R1;
end
function Sn = NewAnswer(S)
%% 生成新解
p1=unidrnd(length(S));
p2=unidrnd(length(S));
while p1==p2
p1=unidrnd(length(S));
p2=unidrnd(length(S));
end
tmp=S(p1);
S(p1)=S(p2);
S(p2)=tmp;
Sn=S;
end
主函数:
%% I. 清空环境变量
clear
clc
%% II. 导入城市位置数据
X= [[1304,2312];[3639,1315];[4177,2244];[3712,1399];[3488,1535];[3326,1556];[3238,1229];[4196,1004];[4312,790];[4386,570];[3007,1970];[2562,1756];[2788,1491];[2381,1676];[1332,695];[3715,1678];[3918,2179];[4061,2370];[3780,2212];[3676,2578];[4029,2838];[4263,2931];[3429,1908];[3507,2367];[3394,2643];[3439,3201];[2935,3240];[3140,3550];[2545,2357];[2778,2826];[2370,2975]];
%% III. 计算距离矩阵
D = Distance(X); %计算距离矩阵
N = size(D,1); %城市的个数
%% IV. 初始化参数
T0 = 1e10; % 初始温度,10的10次方!需要设定一个很大的温度。
Tend = 1e-30; % 终止温度
L = 2; % 各温度下的迭代次数
q = 0.99; %降温速率
syms x;
f=T0 *(0.9)^x-Tend;
Time = ceil(double(solve([f,x]))); % 计算迭代的次数
% Time = 132;
count = 0; %迭代计数
Obj = zeros(Time,1); %目标值矩阵初始化
track = zeros(Time,N); %每代的最优路线矩阵初始化
%% V. 随机产生一个初始路线
S1 = randperm(N);
DrawPath(S1,X)
disp('初始路径:')
OutputPath(S1);
Rlength = PathLength(D,S1);
disp(['总距离:',num2str(Rlength)]);
%% VI. 迭代优化
while T0 > Tend
count = count + 1; %更新迭代次数
temp = zeros(L,N+1);
%%
% 1. 产生新解
S2 = NewAnswer(S1);
%%
% 2. Metropolis法则判断是否接受新解
[S1,R] = Metropolis(S1,S2,D,T0); %Metropolis 抽样算法
%%
% 3. 记录每次迭代过程的最优路线
if count == 1 || R < Obj(count-1)
Obj(count) = R; %如果当前温度下最优路程小于上一路程则记录当前路程
else
Obj(count) = Obj(count-1);%如果当前温度下最优路程大于上一路程则记录上一路程
end
track(count,:) = S1;
T0 = q * T0; %降温
end
%% VII. 优化过程迭代图
figure
plot(1:count,Obj)
xlabel('迭代次数')
ylabel('距离')
title('优化过程')
%% VIII. 绘制最优路径图
DrawPath(track(end,:),X)
%% IX. 输出最优解的路线和总距离
disp('最优解:')
S = track(end,:);
p = OutputPath(S);
disp(['总距离:',num2str(PathLength(D,S))]);
输出:
初始路径:
23―>22―>10―>31―>26―>30―>11―>29―>7―>25―>24―>13―>15―>6―>21―>16―>17―>14―>1―>8―>4―>19―>27―>20―>28―>12―>3―>5―>18―>2―>9―>23
总距离:41282.0292
最优解:
31―>30―>11―>24―>25―>20―>21―>22―>18―>3―>17―>19―>16―>6―>7―>13―>14―>12―>29―>1―>15―>10―>9―>8―>4―>2―>5―>23―>26―>28―>27―>31
总距离:17984.3228
初始路径:
优化过程:
最优解: