模拟退火算法(Simulated Annealing,SA)最早的思想是由N. Metropolis [1] 等人于1953年提出。1983 年,S. Kirkpatrick 等成功地将退火思想引入到组合优化领域。它是基于Monte-Carlo迭代求解策略的一种随机寻优算法,其出发点是基于物理中固体物质的退火过程与一般组合优化问题之间的相似性。 从某一较高初温出发,伴随温度参数的不断下降,结合概率突跳特性在求解空间中随机寻找目标函数的全局最优解,即在局部最优解能概率性地跳出并最终趋于全局最优。
优点:
应用:VLSI(超大规模集成电路)最优设计、图像处理、组合优化问题、生产调度、控制工程、机器学习、神经网络、信号处理等领域。
模拟退火算法的思想借鉴于固体的退火过程,当固体的温度很高时,内能比较大,固体内的粒子处于快速无序运动状态,当温度慢慢降低,固体的内能减小,粒子逐渐趋于有序,最终固体处于常温状态,内能达到最小,此时粒子最为稳定。
模拟退火算法包含两个部分即Metropolis算法和退火过程。Metropolis算法就是如何在局部最优解的情况下让其跳出来,是退火的基础。
1953年Metropolis提出重要性采样方法,即以概率来接受新状态,而不是使用完全确定的规则,称为Metropolis准则,可以显著减小计算量。
假设前一状态为 x(n),系统受到一定扰动,状态变为 x(n+1),相应地,系统能量由 E(n) 变为 E(n+1)。 定义系统由 x(n)) 变为 x(n+1) 的接收概率为 p(probability of acceptance):
公式解释:当状态转移之后,如果能量减小了,那么这种转移就被接受了(以概率 1 发生)。如果能量增大了,就说明系统偏离全局最优位置(能量最低点,模拟退火算法所要寻找的就是密度最高能量最低的位置)更远了,此时算法不会立即将其抛弃,而是进行概率判断:首先在区间 [0,1]产生一个均匀分布的随机数 ε ,如果 ε
其核心思想是当能量增加时以一定概率接收,而不是一味的拒绝,即陷入局部最优时有一定概率能跳出局部最优,其中以能量的变化量和 T 进行决定概率 p 的大小,所以这个 p 值是动态的。
Metropolis算法可以调整 T 的大小,控制算法收敛速度。T 如果过大,就会导致退火太快,达到局部最优值就会结束迭代,如果取值较小,则计算时间会增加。实际应用中采用退火温度表,在退火初期采用较大的T值,随着退火的进行,逐步降低,具体如下:
固体退火 | 模拟退火算法 |
粒子状态 | 可行解 |
粒子能量最低状态 | 最优解 |
设置初始温度 | 初始解 |
能量 | 目标函数 |
冷却 | 控制参数的下降 |
等温过程 | Metropolis抽样过程 |
算法实质分两层循环,在任一温度水平下,随机扰动产生新解,并计算目标函数值的变化,决定是否被接受。由于算法初始温度比较高,这样,使 E 增大的新解在初始时也可能被接受,因而能跳出局部极小值,然后通过缓慢地降低温度,算法就最终可能收敛到全局最优解,具体流程为:
算法流程图:
% 模拟退火算法解决SA解决TSP问题
clear all; close all; clc;
%% 初始化
load('city.mat'); % 导入城市数据
C=city;
n=size(city,1); % 得到TSP问题的规模,即城市数目
T=100*n; % 设置初始温度
L=100; % 马可夫链长度
K=0.99; % 衰减参数(退火速率)
l=1; % 初始化统计迭代次数为1
len(l)=distance(city,n); % 每次迭代后的路线长度(目标函数值)
figure(1);
% 多次迭代扰动,温度降低之前多次实验
while T>0.01 % 停止迭代温度
% 内层循环得到新的解
for i=1:L
len1=distance(city,n);
p1=floor(1+n*rand()); % 随机选择两个不同的城市的坐标
p2=floor(1+n*rand());
while p1==p2 % 确保选择的两个城市不一样
p1=floor(1+n*rand());
p2=floor(1+n*rand());
end
tmp_city=city; % 置换两个不同的城市的坐标
tmp=tmp_city(p1,:);
tmp_city(p1,:)=tmp_city(p2,:);
tmp_city(p2,:)=tmp;
len2=distance(tmp_city,n); % 计算新路线的距离
delta_e=len2-len1; % 新老距离的差值,相当于能量的差值
% 新路线好于旧路线,用新路线代替旧路线
if delta_e<0
city=tmp_city;
else
% 以概率选择是否接受新解
if exp(-delta_e/T)>rand()
city=tmp_city;
end
end
end
l=l+1; % 更新迭代次数
len(l)=distance(city,n); % 计算新路线距离
T=T*K; % 更新温度
for i=1:n-1
plot([city(i,1),city(i+1,1)],[city(i,2),city(i+1,2)],'bo-');
hold on;
end
plot([city(n,1),city(1,1)],[city(n,2),city(1,2)],'ro-');
title(['最短距离:',num2str(len(l))]);
hold off;
pause(0.002);
end
figure(2);
for i=1:n-1
plot([city(i,1),city(i+1,1)],[city(i,2),city(i+1,2)],'bo-');
hold on;
end
plot([city(n,1),city(1,1)],[city(n,2),city(1,2)],'ro-');
for i=1:n
text(C(i,1)+0.5,C(i,2),num2str(i)); %标号
end
text(city(1,1),city(1,2),' 起点');
text(city(n,1),city(n,2),' 终点');
title('最终路线图');
figure(3);
plot(len)
xlabel('迭代次数')
ylabel('目标函数值')
title('适应度进化曲线')
function len=distance(City,n)
len=0;
for i=1:n-1
len=len+sqrt(sum((City(i,:)-City(i+1,:)).^2));
end
len=len+sqrt(sum((City(n,:)-City(1,:)).^2));
end
代码中的city.mat文件,和脚本放同一个文件夹即可,懒得下文件的可以自己定义一个30x2的矩阵
链接:https://pan.baidu.com/s/1j7omLCzx1uIJS0VdBbR-eA
提取码:1234
% 模拟退火算法SA 解01背包问题
clc;clear;close all
weight = [2,5,18,3,2,5,10,4,11,7,14,6]; % 每个货物重量
price = [5,10,13,4,3,11,13,10,8,16,7,4]; % 每个货物单价
weight_cons = 46; % 背包重量约束
%初始化
alpha = 0.95; % 退火系数
t_begin = 200; % 最高温度
t_end = 0.1; % 结束温度
t = t_begin; % 当前退火温度
solution_new = ones(1,length(weight)); % 新解
solution_current = zeros(1,length(weight)); % 当前解
value_current = 0; % 当前解的价值
value_best =0; % 最大的价值
solution_best = solution_new;
counter = 0; % 记录迭代次数
while t>t_end
counter = counter+1;
for i = 1:100 % 马尔科夫长度
%生成新的解
index = randi([1,length(weight)],1,1); %随机生成1~10的一个整数
solution_new(1,index) =~solution_new(1,index);
% 判断是否满足约束
while sum(solution_new.*weight) > weight_cons
index = randi([1,length(weight)],1,1);
solution_new(1,index) =~solution_new(1,index);
end
% 判断是否接受当前解
value_new = sum(solution_new.*price); % 计算最新价值
probability = exp((value_new-value_current)/t); % 当前概率
if (value_new>value_current)||probability>rand % 新解更好或者劣解满足概率
value_current = value_new;
solution_current = solution_new;
else
solution_new = solution_current;
end
% 与最优解对比
if value_current>value_best
value_best = value_current;
solution_best = solution_current;
end
end
%保存每个过程的最优解
value_list(counter,:)= value_best;
solution_list(counter,:) = solution_best;
t = t*alpha;
end
%显示当前最优解
figure(3);
plot(value_list)
xlabel('迭代次数')
ylabel('目标函数值')
title('适应度进化曲线')
fprintf('最大价值:%f, 货物重量:%d\n',value_best,sum(solution_best.*weight));
disp(['解:',num2str(solution_best)]);
原文作者:Handsome_Zpp
原文地址:模拟退火算法(SA)_Handsome_Zpp的博客-CSDN博客(版权归原文作者所有,侵权留言联系删除)