模拟退火算法(SimulatedAnnealing)是基于Monte-Carlo迭代求解策略的一种随机寻优算法,主要用于组合优化问题的求解。
假设现在有这么一个函数:
现要求其在[0,100]范围内的最小值,如果不求导计算,可能第一反应都是穷举法,把范围内每个值都算一遍再比较大小。如果求的是整数范围,那么要算100遍,但是如果要精确到小数后8位,则要算10000000000次,即便使用计算机依然是一个庞大的运算过程。而优化问题中很多都类似于问题,无法用穷举法解出答案,我们叫这类问题为NP难问题(可查看维基百科:NP-hard),于是,有人提出了爬山法:
但是这个方法的缺点在于最优解的产生依赖于最初值的选取,无法解决非凸函数,即容易收敛于局部最优解:
同时,也无法解决有平台的函数:
于是,Kirkpatrick等提出了模拟退火算法,它是一种启发式搜索算法,即按照预定的控制策略进行搜索,在搜索过程中获取的中间信息将用来改进控制策略
1.模拟退火算法的原理
1.1概念
模拟退火算法的思想借鉴于固体的退火原理,当固体的温度很高的时候,内能比较大,固体的内部粒子处于快速无序运动,当温度慢慢降低的过程中,固体的内能减小,粒子的慢慢趋于有序,最终,当固体处于常温时,内能达到最小,此时,粒子最为稳定。模拟退火算法便是基于这样的原理设计而成。
模拟退火算法从某一高温出发,在高温状态下计算初始解,然后以预设的邻域函数产生一个扰动量,从而得到新的状态,即模拟粒子的无序运动,比较新旧状态下的能量,即目标函数的解。如果新状态的能量小于旧状态,则状态发生转化;如果新状态的能量大于旧状态,则以一定的概率准则发生转化。当状态稳定后,便可以看作达到了当前状态的最优解,便可以开始降温,在下一个温度继续迭代,最终达到低温的稳定状态,便得到了模拟退火算法产生的结果。
1.2状态空间与邻域函数
状态空间也称为搜索空间,它由经过编码的可行解的集合所组成。而邻域函数应尽可能满足产生的候选解遍布全部状态空间。其通常由产生候选解的方式和候选解产生的概率分布组成。候选解一般按照某一概率密度函数对解空间进行随机采样获得,而概率分布可以为均匀分布、正态分布、指数分布等。
1.3状态转移概率(Metropolis准则)
状态转移概率是指从一个状态转换成另一个状态的概率,模拟退火算法中一般采用Metropolis准则,具体如下:
其与当前温度参数T有关,随温度的下降而减小。
1.4冷却进度表
冷却进度表是指从某一高温状态T向低温状态冷却时的降温函数,设时刻的温度为T(t),则经典模拟退火算法的降温方式为:
而快速模拟退火算法的降温方式为:
另外还有几种常用的降温函数个人感觉大同小异,就不过多介绍了。
1.5初始温度
一般来说,初始温度越大,获得高质量解的几率越大,但是花费的时间也会随之增加,因此,初温的确定应该同时考虑计算效率与优化质量,常用的方法包括:
(1)均匀抽样一组状态,以各状态目标值的方差为初温。
(2)随机产生一组状态,确定亮亮状态间的最大目标值差,然后根据差值,利用一定的函数确定初温,如:
其中Pr为初始接受概率。
(3)根据经验公式给出
1.6循环终止准则
内循环终止准则:
(1)检验目标函数的均值是否稳定
(2)连续若干步的目标值变化较小
(3)按一定的步数进行抽样
外循环终止准则
(1)设置终止温度
(2)设置外循环迭代次数
(3)算法搜索到的最优值连续若干步保持不变
(4)检验系统熵是否稳定
Python实现过程:
下面便通过python求解开头提到的问题,首先定义函数,然后通过pyplot看看函数在[0,100]上的大致图像:
from __future__ import division import numpy as np import matplotlib.pyplot as plt import math #define aim function def aimFunction(x): y=x**3-60*x**2-4*x+6 return y x=[i/10 for i in range(1000)] y=[0 for i in range(1000)] for i in range(1000): y[i]=aimFunction(x[i]) plt.plot(x,y)
可以看到最小值大概在40左右,通过求导计算得到最小值为40.033。
接下来便构造SA模型:
定义初温、低温阈值并通过随机得到初始x,同时定义时刻t。通过均匀分布构造邻域函数,同时设定内循环次数为50次,降温函数使用
代码实现如下:
T=1000 #initiate temperature Tmin=10 #minimum value of terperature x=np.random.uniform(low=0,high=100)#initiate x k=50 #times of internal circulation y=0#initiate result t=0#time while T>=Tmin: for i in range(k): #calculate y y=aimFunction(x) #generate a new x in the neighboorhood of x by transform function xNew=x+np.random.uniform(low=-0.055,high=0.055)*T if (0<=xNew and xNew<=100): yNew=aimFunction(xNew) if yNew-y<0: x=xNew else: #metropolis principle p=math.exp(-(yNew-y)/T) r=np.random.uniform(low=0,high=1) if r<p: x=xNew t+=1 print t T=1000/(1+t) print x,aimFunction(x)
经过循环输出x与y,结果如下:
多次运行:
可以看到SA算法很好的逼近了最优解。
Reference: