• 模拟退火算法简介


    一种随机搜索算法,跟遗传算法差不多,简单看看吧

    通俗解释

    假设有下面这样一个函数,现在想求函数的(全局)最优解(最小值)。

    如果采用Greedy策略,那么从A点开始试探,如果函数值继续减少,那么试探过程就会继续。而当到达点B时,显然我们的探求过程就结束了(因为无论朝哪个方向努力,结果只会越来越大)。最终我们只能找到一个局部最后解B。这就是爬山算法

    模拟退火其实也是一种Greedy算法,但是它的搜索过程引入了随机因素。模拟退火算法以一定的概率来接受一个比当前解要差的解,因此有可能会跳出这个局部的最优解,达到全局的最优解。

    以下图为例,模拟退火算法在搜索到局部最优解B后,会以一定的概率接受向右继续移动。也许经过几次这样的不是局部最优的移动后会到达B 和C之间的峰点,于是就跳出了局部最小值B    【一旦到达BC间的峰点,也就意味着跳出局部最优B,因为它向右会一直减小,最终到达C点】

    算法评价

    缺点:模拟退火算法不一定能找到全局最优;

    优点:搜索效率较高

    示例

    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: {}
    solution: {}'.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  大白话解析爬山算法、模拟退火算法

  • 相关阅读:
    【Android开发学习笔记】【高级】【随笔】插件化——初探
    【Android测试】【第十三节】Uiautomator——如何组织好你的测试代码(项目实战)
    【Android测试】【第十二节】Uiautomator——API详解
    【Android测试】【第十一节】Uiautomator——简介
    【Android测试】【第十节】MonkeyRunner—— 录制回放
    【Android测试】【第九节】MonkeyRunner—— 初识
    poj 1475 推箱子
    leetcode Ch3-DFS & Backtracking I
    Windows Socket和Linux Socket编程的区别 ZZ
    Linux网络编程入门 (转载)
  • 原文地址:https://www.cnblogs.com/yanshw/p/14648070.html
Copyright © 2020-2023  润新知