模拟退火,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
,比较这两个函数值,取最小值。即使后者的函数值比前者大,也可以以一定的概率保留,只是说这个概率定义成了玻尔兹曼分布中的概率形式。和其他的启发式算法(遗传算法)一样,它们都是以概率为导向的迭代算法,说白了这个世界就是这么奇妙,冥冥之中自有概率在安排。
参考: