【数学建模】优化算法 - 模拟退火算法

        摘要:本文介绍了什么是优化算法,主要对模拟退火算法的原理和实现过程进行了详细的分析,并在MATLAB中分别采用代码方式和优化工具箱,演示如何使用模拟退火算法对二元函数的最值问题进行求解。


目录:优化算法 - 模拟退火算法

  • 一、什么是优化算法?
  • 二、爬山算法
  • 三、模拟退火算法
    • 3.1 固体退火的物理原理
    • 3.2 模拟退火的算法原理
    • 3.3 提出一些小问题
    • 3.4 问题的解释与模拟退火的深入分析
      • 3.4.1 模拟退火算法与爬山算法的比较
      • 3.4.2 接收新解的概率p应该与两个因素有关
      • 3.4.3 温度T在搜索过程中怎么体现?
      • 3.4.4 搜索过程什么时候停止?
      • 3.4.5 新解 ω~i~ 是怎么产生的?
  • 四、模拟退火算法的代码实现
  • 五、基于MATLAB内置优化工具箱的实现


一、什么是优化算法?

        近年来,计算机技术的快速发展,为人们解决实际工程应用中遇到的大空间、非线性、全局最优、组合优化等复杂问题提供了极大方便。国内外学者提出了不少的智能优化算法,如遗传算法、差分进化算法、免疫算法、蚁群算法、粒子群算法、模拟退火算法、禁忌搜索算法和神经网络算法等等。这些算法都有一些共同的特性,就是通过程序来模拟自然界中的一些特性和过程,可以分为自然进化类算法、仿生类算法、仿物类算法等等,这些算法都可以用来解决最优化问题。

【数学建模】优化算法 - 模拟退火算法_第1张图片

二、爬山算法

        爬山算法是一种局部贪心的启发式算法。我们以最简单的连续一元函数找最大值为例,其算法原理是:在解空间中随机生成一个初始解,每次拿相邻点(左邻域或右邻域)与当前点进行对比,取两者中使得目标函数取值较大的点,作为爬坡的下一步;重复迭代该过程,直到当前点的邻近点不再有比其大的点,即为爬山算法获得的最优解。
        爬山算法的特点是搜索简单,但很容易陷入局部最优解。其改进方法是使用不同的初始状态,多次运行爬山算法,从最终结果里面选择一个最大的值作为这个问题的解。但如果目标函数的局部最优解特别多时,爬山算法就显得心有余而力不足了,更常用的改进方法是我们接下来将要介绍的 - 模拟退火算法。
【数学建模】优化算法 - 模拟退火算法_第2张图片

三、模拟退火算法

3.1 固体退火的物理原理

        当固体的温度较高时,内能比较大,固体内部的粒子处于快速且无序的运动状态;当温度慢慢降低的过程中,固体的内能减小,粒子逐渐趋于有序;最终,当固体处于常温时,内能达到最小,此时粒子最为稳定。
【数学建模】优化算法 - 模拟退火算法_第3张图片

3.2 模拟退火的算法原理

        寻找最优化问题的解,就可以将其看做是模拟固体退火的过程。我们仍以寻找连续一元函数的最大值为例:将搜索过程的迭代次数看成温度T,将当前的搜索解看成粒子的运动状态,将搜索解对应的目标函数取值看成内能E。在搜索前期,由于温度较高,粒子处于快速且无序的运动状态,所以搜索范围较大;随着迭代次数的不断增多,温度在逐渐下降,粒子的位置逐渐趋于稳定,即搜索范围减小,粒子的内能也即目标函数值f(x)也逐渐趋于稳定。
【数学建模】优化算法 - 模拟退火算法_第4张图片

        我们将上述思想用于改进爬山算法,仍以求一元函数的最大值为例,具体的算法原理如下:
✔ ① i = 0,在解空间中随机生成一个初始解ω0,作为搜索起始点S (S = ω0),计算搜索点S对应的目标函数值 f(S) = f(ω0);
✔ ② i ++,在S附近随机生成一个新解ωi,计算ωi对应的目标函数值 f(ωi);
✔ ③ 若 f(ωi) ≥ f(S),则搜索点S移动到解ωi的位置,然后重复步骤(2);
          若 f(ωi) ≤ f(S),与爬山算法不同,搜索点此时并没有完全拒绝解 ωi,而有一定的概率p接收新解。我们用程序生成一个(0, 1)之间的随机数r,如果r < p,说明这个概率为p的把握成立,则搜索点S移动到 ωi 的位置,反之S不移动,然后重复步骤(2)。

3.3 提出一些小问题

相信有一些同学看到上面的原理已经开始懵逼了,可能会产生以下几个问题的疑惑:
● 模拟退火算法与爬山算法有什么异同?
● 若 f(ωi) ≤ f(S),接收新解B的概率p是多少?
● 温度T在搜索过程中怎么体现?
● 搜索过程什么时候停止?
● 新解 ωi 是怎么产生的?

3.4 问题的解释与模拟退火的深入分析

3.4.1 模拟退火算法与爬山算法的比较

① 相同点:都是根据当前搜索点的位置在解空间中选择下一个搜索点,即在搜索最优解的过程中用到了原来搜索过程的信息,且这个信息会改进并推动我们的搜索过程,这说明模拟退火算法与爬山算法都是启发式算法。
② 不同点:不同的是爬山算法是在当前搜索点的邻域附近找到一个能使得 f(ωi) ≥ f(S) 的爬山点,完全拒绝 f(ωi) ≤ f(S);而模拟退火算法仍有一定的概率p接受 f(ωi) ≤ f(S) 的新解。
③ 模拟退火算法的优点:模拟退火算法仍有一定的概率p接受 f(ωi) ≤ f(S) 的新解,这意味着模拟退火算法提高了搜索能力,不容易陷入局部最优解当中。

3.4.2 接收新解的概率p应该与两个因素有关

① 当前温度T。在搜索前期,温度较高,粒子处于较活跃且不稳定的状态,所以搜索范围应该较大,意味着接收新解的概率p也应该较大;在搜索后期,温度下降,粒子逐渐趋于稳定的状态,p应该较小。
② 当前搜索解S与新解ωi之间的内能差,即目标函数差值 | f(ωi) - f(S) |。内能差越大,说明粒子越难改变当前的状态去选择接受新解,所以p越小。

        基于上述原则,我们定义一个函数来表征p与上面这两个因素之间的函数关系(也称为接受函数),即 Metropolis准则:
在这里插入图片描述

3.4.3 温度T在搜索过程中怎么体现?

● 温度T是我们根据固体退火的过程,人为设定的一个参数。由于固体的温度随着时间的推移在下降,所以温度大小与当前迭代的次数密切相关,它的大小也直接影响了搜索范围和接收函数p的大小。温度的具体设计如下:
① 设定退火温度的初值T0。一般取T0 = 100,有的问题规模较大时可能需要T0 = 1000。为了减少运算量,T0不宜取得太大,而应与其他参数折中选取。
② 设定温度的衰减函数。衰减函数可以有多种形式,常用的一个衰减函数是Tk+1 = αTk,其中 α为一个常数,可以取为0.5~0.95,它的取值决定了降温的过程。α越大,温度衰减的速度越慢,从而使算法进程接收更多的变换,访问更多的领域,搜索更大范围的解空间,返回更好的最终解。但α的增大会使得求解时间有很大的增加,目前使用较多的α一般为0.95。
③ 在每一次外循环中,利用衰减函数对温度进行一次衰减;在每一次内循环中,温度保持不变。有的同学看到这里可能就懵逼了,什么外循环,什么内循环?这是因为我们将搜索最优解的整个过程分为了内外两层循环来实现,每层循环都有一个最大迭代次数(搜索的总次数就是这两层循环的迭代次数相乘),但只有外层循环才控制温度的衰减变化,内层循环为了提高该温度下的搜索利用效率,温度不变。我们将在某温度下的迭代次数称为马尔科夫链长度Lk,对于简单的情况我们可以令Lk = 100·n(n为自变量的个数)。

3.4.4 搜索过程什么时候停止?

① 最简单的一个想法就是设定外层循环的迭代次数,当外层循环结束了,也意味着温度足够低,搜索解已经趋于较为稳定的状态,此时可以停止我们的搜索。
② 我们可以不直接设定外层循环的迭代次数,而是指定一个跳出温度,例如我们可以设定T < 0.0001时就不继续进行迭代,结束搜索。(这种方法本质上和法①是一样的,因为有了初始温度T0和衰减函数Tk+1 = αTk,我们自然地就可以计算出跳出温度对应的外层循环迭代次数)
③ 从第N次迭代开始,以后的每一次迭代前都要计算这次迭代的前N次迭代的最佳函数值(Best Function Value)的一阶差分的和(加绝对值),如果这个和小于某个容忍值(Function tolerance),就认为这次迭代的前N次迭代对Best Function Value的改变很小,我们就可以退出搜索了。(这是MATLAB优化工具箱的内置方法)
    ● 如下图所示,每次迭代都对应着一个最佳函数值,这个最佳函数值就是这次迭代过后当前所能找到的最优解。我们以求函数的最小值为例,Best Function Value关于Iteration的函数一定是个单调不增的函数,如果这个函数在很长的一段时间内基本没有变化(保持平稳),就可以认为此时的Best Function Value已经非常接近或者就是我们所要的目标,继续迭代下去对Best Function Value的影响不大。例如,我们设定N = 1000,当前Iteration = 3888,那么在这次迭代开始之前,我们要看第3888次迭代的前1000次迭代,计算这1000次迭代的Best Function Value的一阶差分(即这个数列两两相邻作差)的和,如果这个和小于我们设定的容忍值,就结束搜索。
【数学建模】优化算法 - 模拟退火算法_第5张图片

3.4.5 新解 ωi 是怎么产生的?

没有固定的准则!不同的问题产生新解的方法灵活多样,如TSP问题、书店买书问题等,但要遵循的基本原则是:新解的产生要用到原来搜索过程的信息,即新解与旧解之间存在关联,这是启发式算法的核心思想。这里我们介绍一种求解n元函数最大/最小值问题产生新解的方法(MATLAB中内置函数的方法):

【数学建模】优化算法 - 模拟退火算法_第6张图片

四、模拟退火算法的代码实现

例:求函数y = 21.5 + x1sin(4πx1) + x2sin(20πx2)的最大值,其中x1 ∈ [-3, 12.1], x2 ∈ [4.1, 5.8]。
注:这个函数含有非常多的局部最大值,怎么设置合适的退火参数需要不断尝试!【参考的最大值:38.8503】
(以下MATLAB代码的实现参考B站UP主:数学建模学习交流)

%% SA 模拟退火: 以求二元函数的最大值为例
% 求解函数y = 21.5 + x1*sin(4*pi*x1) + x2*sin(20*pi*x2) 
% 在x1∈[-3, 12.1], x2∈[4.1, 5.8]内的最大值(可绘图动画演示搜索过程)
clear; clc

%% 绘制函数的图形
x1 = -3: 0.1: 12.1;
x2 = 4.1: 0.1: 5.8;
[x1,x2] = meshgrid(x1,x2);
y = 21.5 + x1.*sin(4*pi*x1) + x2.*sin(20*pi*x2); % 注意这里要点乘的地方 
mesh(x1,x2,y)
xlabel('x1');  ylabel('x2');  zlabel('y');  % 加上坐标轴的标签
axis vis3d % 冻结屏幕高宽比,使得一个三维对象的旋转不会改变坐标轴的刻度显示
hold on  % 不关闭图形,继续在上面画图

%% 参数初始化
narvs = 2; % 变量个数
T0 = 100;   % 初始温度
T = T0; % 迭代中温度会发生改变,第一次迭代时温度就是T0
maxgen = 300;  % 外层循环的最大迭代次数
Lk = 400;  % 每个温度下的迭代次数
alfa = 0.95;  % 温度衰减系数
x_lb = [-3 4.1]; % x的下界
x_ub = [12.1 5.8]; % x的上界

%%  随机生成一个初始解x0,并将当前搜索点记为S
x0 = zeros(1, narvs);
for i = 1: narvs
    x0(i) = x_lb(i) + (x_ub(i)-x_lb(i))*rand(1);    
end
S = x0;
h = scatter3(S(1), S(2), Obj_fun2(S), '*r');  % scatter3是绘制三维散点图的函数(这里返回h是为了得到图形的句柄,未来我们对其位置进行更新)

%% 初始化用来保存中间结果的x和y的取值
iter_x = S;
iter_y = Obj_fun2(S);

%% 模拟退火过程
for iter = 1 : maxgen  % 外循环, 我这里采用的是指定最大迭代次数
    for i = 1 : Lk  % 内循环(迭代次数即马尔科夫链长度),在每个温度下开始迭代
        
        % 计算当前解的函数值
        y_now = Obj_fun2(S); 
        
        % 随机产生一个新解
        y = randn(1, narvs);  % 生成1行narvs列的N(0,1)随机数
        z = y / sqrt(sum(y.^2)); % 根据新解的产生规则计算z
        x_new = S + z*T; % 根据新解的产生规则计算x_new的值
        
        % 判断新解的位置是不是超出了定义域,如果超出了定义域,就对其进行调整
        for j = 1: narvs
            if x_new(j) < x_lb(j)
                r = rand(1);
                x_new(j) = r*x_lb(j)+(1-r)*S(j);
            elseif x_new(j) > x_ub(j)
                r = rand(1);
                x_new(j) = r*x_ub(j)+(1-r)*S(j);
            end
        end
        
        % 计算新解的函数值
        y_new = Obj_fun2(x_new);  % 计算新解的函数值
        
        % 更新搜索点的位置
        if y_new > y_now  % 如果新解函数值大于当前解的函数值
            S = x_new; % 搜索点移动到新解的位置
            iter_x = [iter_x; x_new]; % 将新找到的x1添加到中间结果中
            iter_y = [iter_y; y_new]; % 将新找到的y1添加到中间结果中
        else
            p = exp(-abs(y_new - y_now)/T); % 根据Metropolis准则计算一个概率
            if rand(1) < p   % 生成一个随机数和这个概率比较,如果该随机数小于这个概率
                S = x_new;  % 搜索点移动到新解的位置
            end
        end
        
        % 内循环结束!注意内循环不需要对温度进行衰减
    end
    
    T = alfa * T;  % 温度下降
    pause(0.05)  % 暂停一段时间后(单位:秒)再接着画图
    h.XData = S(1);  % 更新散点图句柄的x轴的数据(此时解的位置在图上发生了变化)
    h.YData = S(2); % 更新散点图句柄的y轴的数据(此时解的位置在图上发生了变化)
    h.ZData = Obj_fun2(S);  % 更新散点图句柄的z轴的数据(此时粒子的位置在图上发生了变化)
    
end

%% 查找搜索全过程的最大值
[best_y, ind] = max(iter_y);  % 找到最大的y的值,以及其在向量中的下标
best_x = iter_x(ind, :); % 根据下标找到此时x的值
disp('最佳的位置是:'); disp(best_x)
disp('此时最优值是:'); disp(best_y)

%% 在图上标注出搜索到的最大值点
h.XData = [];  h.YData = [];  h.ZData = []  % 将原来的散点删除
scatter3(best_x(1), best_x(2), best_y,'*r');  % 在最大值处重新标上散点
title(['模拟退火找到的最小值为', num2str(best_y)])  % 加上图的标题

其中要新建一个目标函数的.m文件,文件命名为Obj_fun2.m,具体代码如下:

function y = Obj_fun2(x)
    %y = x(1)^2 + x(2)^2 - x(1)*x(2) - 10*x(1) - 4*x(2) + 60;
    y = 21.5 + x(1).*sin(4*pi*x(1)) + x(2).*sin(20*pi*x(2));
end

五、基于MATLAB内置优化工具箱的实现

(1)在MATLAB主界面中选择“APP” - “Optimization”,进入优化工具箱;
(2)在左侧面板的“Solver”中选择“simulannealbnd - Simulated annealing algorithm”,即模拟退火算法;

【数学建模】优化算法 - 模拟退火算法_第7张图片


(3)输入求解函数(@ + 函数对应的.m文件名,不带后缀),并设定起始点和自变量的上下界取值,如下图所示:

【数学建模】优化算法 - 模拟退火算法_第8张图片
注意:MATLAB优化工具箱里的模拟退火算法求解的是函数的最小值!如果我们要求最大值,需要在求解函数前添加一个负号!

修改Obj_fun2.m文件如下:

function y = Obj_fun2(x)
    %y = x(1)^2 + x(2)^2 - x(1)*x(2) - 10*x(1) - 4*x(2) + 60;
    y = -((21.5 + x(1).*sin(4*pi*x(1)) + x(2).*sin(20*pi*x(2))));
end

(4)停止准则的设定:

【数学建模】优化算法 - 模拟退火算法_第9张图片
        这里的Stall iteration和Function tolerance分别对应着我们前面介绍搜索停止条件时提到的N和容忍值,即从第N次迭代开始,以后的每一次迭代前都要计算这次迭代的前N次迭代的最佳函数值(Best Function Value)的一阶差分的和(加绝对值),如果这个和小于某个容忍值(Function tolerance),就认为这次迭代的前N次迭代对Best Function Value的改变很小,我们就可以退出搜索了。
        为了提高精确度,我们可以设定Stall iteration大一点,Function tolerance小一点。


(5)退火参数的设置:

【数学建模】优化算法 - 模拟退火算法_第10张图片


【数学建模】优化算法 - 模拟退火算法_第11张图片


【数学建模】优化算法 - 模拟退火算法_第12张图片


【数学建模】优化算法 - 模拟退火算法_第13张图片


(6)接收函数p的设定:(MATLAB默认的函数与我们前面介绍的不一样)
【数学建模】优化算法 - 模拟退火算法_第14张图片


(7)退火过程可视化:(画图会减慢模拟退火的搜索速度)
【数学建模】优化算法 - 模拟退火算法_第15张图片
【数学建模】优化算法 - 模拟退火算法_第16张图片

【数学建模】优化算法 - 模拟退火算法_第17张图片


(8)点击Start就可以开始运行了。我们可以调整参数,多次运行模拟退火算法,找到一个最优的值。
【数学建模】优化算法 - 模拟退火算法_第18张图片

你可能感兴趣的:(数学杂谈)