模拟退火算法

算法背景

退火是指将固体加热到足够高的温度,使分子呈随机排列状态,然后逐步降温使之冷却,最后分子以低能状态排列,固体达到某种稳定状态。物理退火包括一下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中支持函数中嵌套函数,此时嵌套函数在函数体外不能使用,即归函数私有。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,001评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,210评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,874评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,001评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,022评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,005评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,929评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,742评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,193评论 1 309
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,427评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,583评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,305评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,911评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,564评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,731评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,581评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,478评论 2 352

推荐阅读更多精彩内容