一种随机搜索算法,跟遗传算法差不多,简单看看吧
通俗解释
假设有下面这样一个函数,现在想求函数的(全局)最优解(最小值)。
如果采用Greedy策略,那么从A点开始试探,如果函数值继续减少,那么试探过程就会继续。而当到达点B时,显然我们的探求过程就结束了(因为无论朝哪个方向努力,结果只会越来越大)。最终我们只能找到一个局部最后解B。这就是爬山算法
模拟退火其实也是一种Greedy算法,但是它的搜索过程引入了随机因素。模拟退火算法以一定的概率来接受一个比当前解要差的解,因此有可能会跳出这个局部的最优解,达到全局的最优解。
以下图为例,模拟退火算法在搜索到局部最优解B后,会以一定的概率接受向右继续移动。也许经过几次这样的不是局部最优的移动后会到达B 和C之间的峰点,于是就跳出了局部最小值B 【一旦到达BC间的峰点,也就意味着跳出局部最优B,因为它向右会一直减小,最终到达C点】
算法评价
缺点:模拟退火算法不一定能找到全局最优;
优点:搜索效率较高
示例
整段代码主要看 solve 方法,这个方法才是 模拟退火,其他都是配料,solve 的思路就是 给 x 一个 很小的扰动,看看 扰动前,扰动后 哪个好,然后以 一定概率 接受 那个不好的解,否则接受更好的解,就这么简单
import random import numpy as np import matplotlib.pyplot as plt class SA(object): def __init__(self, interval, tab='min', T_max=10000, T_min=1, iterMax=1000, rate=0.95): self.interval = interval # 给定状态空间 - 即待求解空间 x的范围 self.T_max = T_max # 初始退火温度 - 温度上限 self.T_min = T_min # 截止退火温度 - 温度下限 self.iterMax = iterMax # 定温内部迭代次数 self.rate = rate # 退火降温速度 ############################################################# self.x_seed = random.uniform(interval[0], interval[1]) # 解空间内的种子,初始解 self.tab = tab.strip() # 求解最大值还是最小值的标签: 'min' - 最小值;'max' - 最大值 ############################################################# self.solve() # 完成主体的求解过程 self.display() # 数据可视化展示 def solve(self): temp = 'deal_' + self.tab # 采用反射方法提取对应的函数 if hasattr(self, temp): deal = getattr(self, temp) else: exit('>>>tab标签传参有误:"min"|"max"<<<') x1 = self.x_seed # 随机产生初始解 T = self.T_max # if 1: # for _ in range(10000): # 这样也可以得到最优解 while T >= self.T_min: # T 和 x y 没有任何关系,其实就是指定了迭代次数 for i in range(self.iterMax): f1 = self.func(x1) delta_x = random.random() * 2 - 1 # [-1, 1] 之间的随机数 if x1 + delta_x >= self.interval[0] and x1 + delta_x <= self.interval[1]: # 将随机解束缚在给定状态空间内 x2 = x1 + delta_x else: x2 = x1 - delta_x f2 = self.func(x2) delta_f = f2 - f1 x1 = deal(x1, x2, delta_f, T) # deal = deal_min or deal_max T *= self.rate self.x_solu = x1 # 提取最终退火解 def func(self, x): # 状态产生函数 - 即待求解函数 value = np.sin(x**2) * (x**2 - 5*x) return value def p_min(self, delta, T): # 计算最小值时,容忍解的状态迁移概率 # 产生一个概率,想简单点就设置为固定值 probability = np.exp(-delta/T) return probability def p_max(self, delta, T): # 产生一个概率,想简单点就设置为固定值 probability = np.exp(delta/T) # 计算最大值时,容忍解的状态迁移概率 return probability def deal_min(self, x1, x2, delta, T): if delta < 0: # 更优解 return x2 else: # 容忍解 P = self.p_min(delta, T) if P > random.random(): return x2 else: return x1 def deal_max(self, x1, x2, delta, T): if delta > 0: # 更优解 return x2 # 如果是更优解,就返回 x2 else: # 容忍解 P = self.p_max(delta, T) # 如果不是更优解,随机返回 x1 或者 x2 if P > random.random(): return x2 else: return x1 def display(self): print('seed: {}\nsolution: {}'.format(self.x_seed, self.x_solu)) # plt.figure(figsize=(6, 4)) x = np.linspace(self.interval[0], self.interval[1], 300) y = self.func(x) plt.plot(x, y, 'g-', label='function') plt.plot(self.x_seed, self.func(self.x_seed), 'bo', label='seed') plt.plot(self.x_solu, self.func(self.x_solu), 'r*', label='solution') plt.title('solution = {}'.format(self.x_solu)) plt.xlabel('x'); plt.ylabel('y') plt.legend() # plt.savefig('SA.png', dpi=500) plt.show() plt.close() if __name__ == '__main__': SA([-5, 5], 'max')
输出
特点
模拟退火算法 经常与其他算法 结合使用,用于 跳出 局部最优
参考资料:
http://blog.chinaunix.net/uid-9162199-id-5840190.html 模拟退火算法(Simulated Annealing,SA)的全面讲解及python实现
https://www.cnblogs.com/xxhbdk/p/9192750.html 模拟退火算法(1) - Python实现
https://zhuanlan.zhihu.com/p/47375952 模拟退火算法从原理到实战【基础篇】
https://www.cnblogs.com/heaad/archive/2010/12/20/1911614.html 大白话解析爬山算法、模拟退火算法