模拟退火算法经典实例_《钢铁是怎样炼成的_程序员版》——模拟退火算法原理与实例...

模拟退火算法经典实例_《钢铁是怎样炼成的_程序员版》——模拟退火算法原理与实例..._第1张图片

退火这个词,其实是铁匠发明的。它的意思很简单,就是将铁匠炉烧热后,再把下边的火撤掉,让金属在炉子里边慢慢冷却。

人们发现,这个缓慢的降温过程能消除金属内部的各种缺陷,使得其恢复能量最低的状态。

后来,受到退火工艺的启发,研究人员把将退火的缓慢的降温思路推广开来,用于寻找复杂函数的全局最优值。


举个简单的例子,氦原子在金属中空位附近运动时,其势能函数大概长这样:

模拟退火算法经典实例_《钢铁是怎样炼成的_程序员版》——模拟退火算法原理与实例..._第2张图片
Mo中He在空位附近的能量分布

把势能函数看成一个轨道,再把氦看成一个小球放到这个轨道上。那么,小球的高度就是它的重力势能。求这个函数的全局最小值,其实就是让小球滚到最深那个坑过程。

模拟退火算法经典实例_《钢铁是怎样炼成的_程序员版》——模拟退火算法原理与实例..._第3张图片

由于函数中存在非常多局域极小值(浅坑),常见的贪心算法(如梯度下降法,就是闭着眼睛沿坡往下滚)会陷入最近的局域极小值,很错过到全局最小值(深坑)。

那么,怎么才能让滚进深坑呢?

我们先晃一晃整个体系,让小球随机动起来。

我们把晃动的剧烈程度称为温度T。在足够长的时间内。小球出现在i点的概率呈玻尔兹曼分布,与i点的高度(势能Ei)和温度T密切相关:

越小,
越小,
就越大。

温度为0时,小球出现在全局最小值的概率为100%。


那么,把温度设为0不就行了?

当然不行。上面的概率成立的前提是提供无穷长的时间,使得小球能够遍历整个函数。

实际中,无穷长的时间当然是不现实的。小球从低概率区向高概率区转移,这个过程是需要消耗时间的。

高温下,转移速度快。但另一方面,高温下,小球落在各个坑里的概率差别比较小。

为了让小球能够尽快的转移到最低点,我们可以采取一个降温策略:

  • 先设定一个较高的温度T,使得小球有足够的能量越过能垒,小球到处乱跑的概率比较大。
  • 随机移动小球的位置,检查其移动前后的能量差
  • ,小球能量降低,则接受此次移动。
  • ,小球能量升高,有一定概率接受此次移动,概率为:
    。这个判定方法称为Metropolis判据。
  • 逐渐降低温度T,使得小球滑向低处的概率逐渐增大,直到小球缓缓收敛到最低点,不再晃动。

通过这样一个逐渐降温的过程,小球最终有很大概率(并不是一定)能找到全局最低值。这个算法就是模拟退火算法。

模拟退火算法最大的优势在于其通用性:函数形式如何复杂我不管,我就一步步瞎跑,然后按Metropolis判据概率性的接受这一步就行。

模拟退火搜索全局最小值实例,代码见尾部

模拟退火实现起来也很简单,以下是上图的MATLAB代码示例(核心代码就几行,大部分都是绘图代码):

clear;clc;close all;
set(0,'defaultfigurecolor','w');
figure;
set(gcf,'Position',[200 200 600 600]);
ax=[-1000 1000 -2 0];
%初始化内存、图像

kb=8.6173324e-5;
%玻尔兹曼常数

x=-1000:1000;
f=0.3*sin(x/10).*exp(-abs(x/300));
g=1.5*exp(-abs(x/400));
E=f-g;
%构建具有很多局域极小值的势能函数

pos0=666;
e0=E(pos0);
%随便设个初始位置

T=3000;
%设定初始温度,开始退火
for i=1:500;
    tem=[num2str(T),' K'];
    for k=1:10000
        if(rand()<0.5)
            pos=pos0+1;
        else
            pos=pos0-1;
        end
        %随机迁移一步
        
        e=E(pos);
        %迁移后的能量
        if (rand()

你可能感兴趣的:(模拟退火算法经典实例)