模拟退火算法

模拟退火算法(SimulatedAnnealing)是基于Monte-Carlo迭代求解策略的一种随机寻优算法,主要用于组合优化问题的求解。

假设现在有这么一个函数:
$$
f(x) = x^3-72x^2+4x+5
$$
现要求其在[0,100]范围内的最小值,如果不求导计算,可能第一反应都是穷举法,把范围内每个值都算一遍再比较大小。如果求的是整数范围,那么要算100遍,但是如果要精确到小数后8位,则要算10000000000次,即便使用计算机依然是一个庞大的运算过程。而优化问题中很多都类似于问题,无法用穷举法解出答案,我们叫这类问题为NP难问题(可查看维基百科:NP-hard),于是,有人提出了爬山法

也可以参考下争取几句话描述一下爬山法,模拟退火,遗传算法他的博客文章博客文章

但是这个方法的缺点在于最优解的产生依赖于最初值的选取,无法解决非凸函数,即容易收敛于局部最优解;同时,也无法解决有平台的函数的问题

于是,Kirkpatrick等提出了模拟退火算法,它是一种启发式搜索算法,即按照预定的控制策略进行搜索,在搜索过程中获取的中间信息将用来改进控制策略

1. 模拟退火算法的原理

1.1 概念

模拟退火算法的思想借鉴于固体的退火原理,当固体的温度很高的时候,内能比较大,固体的内部粒子处于快速无序运动,当温度慢慢降低的过程中,固体的内能减小,粒子的慢慢趋于有序,最终,当固体处于常温时,内能达到最小,此时,粒子最为稳定。模拟退火算法便是基于这样的原理设计而成。

模拟退火算法从某一高温出发,在高温状态下计算初始解,然后以预设的邻域函数产生一个扰动量,从而得到新的状态,即模拟粒子的无序运动,比较新旧状态下的能量,即目标函数的解。如果新状态的能量小于旧状态,则状态发生转化;如果新状态的能量大于旧状态,则以一定的概率准则发生转化。当状态稳定后,便可以看作达到了当前状态的最优解,便可以开始降温,在下一个温度继续迭代,最终达到低温的稳定状态,便得到了模拟退火算法产生的结果。

1.2 状态空间与邻域函数

状态空间也称为搜索空间,它由经过编码的可行解的集合所组成。而邻域函数应尽可能满足产生的候选解遍布全部状态空间。其通常由产生候选解的方式和候选解产生的概率分布组成。候选解一般按照某一概率密度函数对解空间进行随机采样获得,而概率分布可以为均匀分布、正态分布、指数分布等。

1.3 状态转移概率(Metropolis准则)

状态转移概率是指从一个状态转换成另一个状态的概率,模拟退火算法中一般采用Metropolis准则,具体如下:
$$
P = \begin{cases}
1 & E(x_{new})<E(x_{old}) \
exp(-E(x_{new})<E(x_{old})\over{T} & E(x_{new})\geq E(x_{old})
\end{cases}
$$
其与当前温度参数T有关,随温度的下降而减小。

1.4 冷却进度表

冷却进度表是指从某一高温状态T向低温状态冷却时的降温函数,设时刻的温度为T(t),则经典模拟退火算法的降温方式为:
$$
T(t)={T_0\over{lg(t+1)}}
$$
快速模拟退火算法的降温方式为:
$$
T(t) = {T_0\over{t+1}}
$$
另外还有其他的降温函数,其实只是收敛的速度不同罢了。

1.5 初始温度

一般来说,初始温度越大,获得高质量解的几率越大,但是花费的时间也会随之增加,因此,初温的确定应该同时考虑计算效率与优化质量,常用的方法包括:

(1)均匀抽样一组状态,以各状态目标值的方差为初温。

(2)随机产生一组状态,确定亮亮状态间的最大目标值差,然后根据差值,利用一定的函数确定初温,如:
$$
T_0 = -{\Delta_{max}\over P_r}
$$
其中Pr为初始接受概率。

(3)根据经验公式给出

1.6 循环终止准则

内循环终止准则:

(1)检验目标函数的均值是否稳定

(2)连续若干步的目标值变化较小

(3)按一定的步数进行抽样

外循环终止准则

(1)设置终止温度

(2)设置外循环迭代次数

(3)算法搜索到的最优值连续若干步保持不变

(4)检验系统熵是否稳定

Python实现过程:

下面便通过python求解开头提到的问题,首先定义函数,然后通过pyplot看看函数在[0,100]上的大致图像:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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)
plt.show()
img
img

可以看到最小值大概在48左右,通过求导计算得到最小值为48.45。

接下来便构造SA模型:

定义初温、低温阈值并通过随机得到初始x,同时定义时刻t。通过均匀分布构造邻域函数,同时设定内循环次数为50次,降温函数使用
$$
T(t) = {T_0\over{t+1}}
$$
代码实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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)
print(aimFunction(x))

经过循环输出x与y,结果如下:

​ 48.45411386249023 -55082.24210065413

可以看到SA算法很好的逼近了最优解。

参考文章

模拟退火算法与python实现