美文网首页
模拟退火算法

模拟退火算法

作者: Muggle01 | 来源:发表于2018-09-03 11:31 被阅读0次

    算法背景

    退火是指将固体加热到足够高的温度,使分子呈随机排列状态,然后逐步降温使之冷却,最后分子以低能状态排列,固体达到某种稳定状态。物理退火包括一下3个过程:

    1.加温过程——增强粒子的热运动,消除系统原先可能存在的非均匀态;
    2.等温过程——对于与环境换热而温度不变的封闭系统,系统状态的自发变化总是朝自由能减少的方向进行,当自由能达到最小时,系统达到平衡态;
    3.冷却过程——使粒子热运动减弱并渐趋有序,系统能量逐渐下降,从而得到低能的晶体结构。

    算法原理

    基本原理

    模拟退火算法分为三部分:初始解、解空间以及目标函数,分别对应物理退火过程中的初始温度、降温以及最终温度。

    1.初始解:初始解释算法迭代的起点,试验表明,模拟退火算法是健壮的,即最终解的求得最优解并不十分依赖初始解的选取,从而可任意选择一个初始解。当然,如果初始解选择得当可以加快找到全局最优解。
    2.解空间:一般是离散的可行解的集合。
    3.目标函数:对优化目标的量化描述,是解空间到某个数集的一个映射,通常表示为若干优化目标的一个和式,应正确体现问题的整体优化要求且较易计算,当解空间包含不可行解时还应包括罚函数。
    4.算法从初始解或称为初始状态开始,在解空间中进行启发式搜索(通常是随机搜索的方式),最终搜索到最优的目标值。

    基本过程

    初始化:设定初始温度T,初始解状态S,终止温度T0;
    降温过程:如果T>T0,则循环执行3至6步;
    在解空间中随机搜索一个新解S’;
    计算增量ΔE=E(S′)-E(S),其中C(S)为解S对应的目标函数值或称为评价函数;
    若ΔE<0则接受S′作为新的当前解,否则以概率exp(-ΔE/T)接受S′作为新的当前解;
    如果满足终止条件则输出当前解作为最优解,结束程序。终止条件可以有两种情况,一是温度已经达到了最低温度T0;二是在连续的取若干个新解都没有跳出当前最优解。

    退火方式

    模拟退火算法中,退火方式对算法有很大影响。如果温度下降过慢,算法的收敛速度会大大降低。如果温度下降过快,可能会丢失极值点。为了提高模拟退火算法的性能,许多学者提出了退火的各种方式,比较有代表性的有以下几种:

    1. T(t) = T0/ln(1+t)

    该方式的特点是温度下降缓慢,算法收敛速度也较慢,但是最终达到全局最优的可能性是最高的

    1. T(t) = T0/ln(1+at)

    式中a为可调参数,可以改善退火曲线的形态。其特点是高温区温度下降比较快,低温区下降比较慢,这种退火方式主要期望在低温区收敛到全局最优。

    1. T(t) = T0a**t

    式中a为可调参数,其特点是温度下降很快,算法的收敛速度快,但是带来的损失是可能不能充分的收敛到全局最优

    以上三种退火方式各有优缺点以及适用的场景,需针对具体的应用进行选择。

    算法框图

    模拟退火算法流程图

    源代码

    #!/usr/bin/env python 
    # -*- coding: UTF-8 -*-
    
    import matplotlib.pyplot as plt
    import math
    import numpy as np
    
    class SA():
        def __init__ (self, max_steps):
            self.T_max = 100 #最高温度
            self.T_min = 1 #最小温度
            self.T = self.T_max #温度初始化
            self.t=1 #初始化时间
            self.max_steps = max_steps  # 同一温度下迭代次数
            self.dim = 9  # 搜索空间的维度
            self.x_bound_low = np.full(shape = self.dim, fill_value = -10)  #变量取值下边界
            self.x_bound_high = np.full(shape = self.dim, fill_value = 10)  #变量取值上边界
    
        def function_fitness (self, x):
            return np.sum(np.square(x))
        
        def update_value (self, x, y, new_x, new_y,best_x, best_y, flag):
            """要接受这个y_new为当前温度下的理想值,要满足y_new>y_old 或 math.exp(-(y - new_y) / self.T)>random.random()"""
    
            if (new_y < y) or (math.exp(-(new_y - y) / self.T) > np.random.random()):
                x = new_x.copy()
                y = new_y
            if new_y < best_y:
                flag = 1
                best_x = new_x.copy()
                best_y = new_y
    
            return x, y, new_x, new_y,best_x, best_y, flag
    
        def solve (self):
            x = np.random.uniform(self.x_bound_low, self.x_bound_high,size=(self.dim))   #  初始化自变量位置
            y = self.function_fitness(x)
            best_x = x.copy()  #矩阵之间相互赋值需要特别注意,赋值后两者对应的地址还是一样的
            best_y = y
            new_x = x.copy()
            new_y = y
    
            while self.T > self.T_min:
    
                flag = 0 #用以判断有无新值被接受
                for step in range(self.max_steps):
    
                    delta_x = np.random.uniform(low=-0.055,high=0.055,size=(self.dim))*self.T
                    middle_value = x+delta_x
                    for i in range(self.dim):
                        if (self.x_bound_low[i] <= middle_value[i]) and (middle_value[i] <= self.x_bound_high[i]):
                            new_x[i] = x[i] + delta_x[i]
                    new_y = self.function_fitness(new_x)
    
                    x, y, new_x, new_y, best_x, best_y, flag = self.update_value ( x, y, new_x, new_y, best_x, best_y, flag)
    
                if flag == 1:
                    x = best_x
                    y = best_y
                self.t += 1
                self.T = self.T_max/(50+self.t)
            print(best_x, best_y)
    
    sa = SA(100)
    sa.solve()
    

    python tips

    当对数组进行运算和操作时,其数据有时会被拷贝到一个新的数组而有时又不会拷贝。对应有三种情况:完全不拷贝(b=a,两者对应内存地址相同)、视图或浅拷贝(c = a.view(),c随着a变,c不拥有数据,但改变其中任意一个值,两者都会变,矩阵切片是浅拷贝)、深拷贝(d=a.copy(),d和a已经没有任何关系了)!

    本程序中的退火方式为T = T0/(a+t),与随机梯度下降法的学习率取相同的变化规律,仍有比较好的效果。

    python中支持函数中嵌套函数,此时嵌套函数在函数体外不能使用,即归函数私有。

    相关文章

      网友评论

          本文标题:模拟退火算法

          本文链接:https://www.haomeiwen.com/subject/tikbwftx.html