模拟退火,Simulated Annealing,SA
模拟退火算法名字的由来是其参考了金属冶炼的退火过程
模拟退火可以解决TSP旅行商问题
引入
当我们遇到一个爬山问题的时候
首先肯定是最简单的贪心法,但是贪心会陷入局部最优解,不一定能搜索出全局最优解
如图,假设C点为当前位置,贪心搜索到A点这个局部最优解就会停止搜索,因为在A点无论向那个方向小幅度移动都不能得到更优的解。
模拟退火算法
模拟退火其实也是一种贪心算法,但是它的搜索过程引入了随机因素。
模拟退火算法以一定的概率来接受一个比当前解要差的解,因此有可能会跳出这个局部的最优解,达到全局的最优解。
以图中为例,模拟退火算法在搜索到局部最优解A后,会以一定的概率接受到E的移动。也许经过几次这样的不是局部最优的移动后会到达D点,于是就跳出了局部最大值A。
这里的“一定的概率”的计算参考了金属冶炼的退火过程,这也是模拟退火算法名称的由来。
实战演示
假设现在我们有一个函数,形式为其函数图像为
通过求导我们也能发现,在
x=10
处该函数取到最小值,有全局最优解。
接下来我们通过拟退火算法实现整个寻优过程。
①解空间
解空间就是我们所要求的定义域的空间范围,在这里我们定为
[0, 100]
。②目标函数
目标函数就是我们要求的函数,这里即为
y=3x2-60x+9
。③新解的产生
通过当前的解产生一个新解的方法有很多,在这里我们直接通过加上一个微小的偏差bias来微调这个值。
x_new = x + np.random.uniform(-1, 1)
增加一个
[-1,1]
之间的实数。④代价函数差
代价函数差就是前后两次函数值的差值:
E(j)-E(i)
。⑤接受准则
接受准则就是算法最核心的地方:
如果
E(j) <E(i)
,就接受新的值;否则,以一定的概率接受新的值,即概率大于0-1
之间的随机数则接受。在实际使用当中,我们可以把K
看作1
处理,甚至温度T
都可以是任意尺度的值。比如初始T=1
。⑥降温
利用选定的降温系数
a
进行降温处理,T=a*T
,从而得到一个新的温度。比如a=0.999
。⑦结束条件
可以选定一个结束的温度,当温度
T
不断衰减到某个值时,算法结束,输出当前状态。比如std=0.0000001
。
import numpy as np
import matplotlib.pyplot as plt
def x_function(x):
return 3*x**2 - 60*x + 9
x = [i for i in np.linspace(0, 100)]
y = map(x_function, x)
plt.plot(x, list(y))
plt.show()
T = 1 # 初始温度
x = np.random.uniform(0, 100)
std = 0.00000001 # 终止温度
a = 0.999 # 衰减率
while T > std:
y = x_function(x)
# 新值通过扰动产生
x_new = x + np.random.uniform(-1, 1)
if 0 <= x_new <= 100:
y_new = x_function(x_new)
if y_new < y:
x = x_new
else:
p = np.exp((y - y_new) / T)
r = np.random.uniform(0, 1)
if p > r:
x = x_new
# print(x)
T = T * a
print(x, x_function(x))
可见,我们通过模拟退火的算法寻找到了全局最优的最小值
x=10
总结
怎么来理解这个过程?事实上就是在解空间中先随机的选择一个解
x
,计算它的函数值,然后以一定的方式(可以是增减一个扰动)得到一个新的解x1
,比较这两个函数值,取最小值。即使后者的函数值比前者大,也可以以一定的概率保留,只是说这个概率定义成了玻尔兹曼分布中的概率形式。和其他的启发式算法(遗传算法)一样,它们都是以概率为导向的迭代算法,说白了这个世界就是这么奇妙,冥冥之中自有概率在安排。