模拟退火 | 启发式算法运筹

模拟退火算法是一种优化技术,灵感来源于固体退火过程。它通过在高温下允许较大移动并在低温下逐渐限制,以寻找函数的全局最优解。算法包括设置初始温度和降温系数,随机选择初始点,然后进行迭代,接受更好或在一定概率下接受更差的解。其优点在于能跳出局部最优,但缺点是可能需要较长的计算时间。文章还展示了如何使用模拟退火解决旅行商问题(TSP)的例子。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、原理

模拟退火算法的思想借鉴于固体的退火原理,当固体的温度很高的时候,内能比较大,固体的内部粒子处于快速无序运动,当温度慢慢降低的过程中,固体的内能减小,粒子的慢慢趋于有序,最终,当固体处于常温时,内能达到最小,此时,粒子最为稳定。通过n次迭代,求一个函数的最值。
温度高->运动速度快(温度低->运动速度慢),温度是缓慢(想象成特别慢的那种)降低的,温度基本不再变化后,趋于有序(最后内能达到最小,也就是接近最优),我们通过模拟这个操作,使得我们需要的答案“趋于有序”,也就是最靠近需要的值(最值)。

2、流程

我们先设定一个初始的温度T(这个温度会比较高,比如2000),每次循环都退火一次。然后降低T,我们通过让T和一个“降温系数”ΔT(一个接近1的小数,比如0.99)相乘,达到慢慢降低温度的效果,直到接近于0(我们用eps来代表一个接近0的数(比如0.00001),只要T<eps,就可以退出循环了)

  • 1、我们先随机找一点x0 ,不论是哪个点都可以,随机!(不超过定义域就行)。这个点作为我们的初始值(相当于物体里的一个粒子)
    在这里插入图片描述

  • 2、再找到一点f(x0),来代表x0所对应的函数值

在这里插入图片描述

  • 3、开始退火!

刚才我们说了x0,相当于是一个粒子,所以我们会进行一个无序运动,也就是向左或者向右随机移动,请记住一个关键点:移动的幅度和当前的温度T有关。其中温度T越大,移动的幅度越大。温度T越小,移动的幅度就越小。这是在模拟粒子无序运动的状态。

  • 4、接受(Accept)更"好"的状态

在这里插入图片描述
假设我们移动到了x1处,那么这个点对应的f(x1)很明显答案是优于(大于)当前的f(x0)的
在这里插入图片描述
因此我们将答案进行更新。也就是将初始值进行替换:x0=x1,f(x0)=f(x1)。这是一种贪心的思想。

  • 5、以一定概率接受(Accept)更差的状态

为什么我们要接受一个更加差的状态呢?因为可能在一个较差的状态旁边会出现一个更加高的山峰。如果我们鼠目寸光,只盯着右半区,很容易随着温度的下降、左右跳转幅度的减小而迷失自己,最后困死在小山丘中。
而我们如果找到了左边山峰的低点,以一定的概率接受了它(概率大小和温度以及当前的值的关键程度有关),会在跳转幅度减少之前,尽可能找到最优点。那么我们以多少的概率去接受它呢?我们用一个公式表示(这个公式我们只需记住,这是科学家推导出来的结论):
在这里插入图片描述
e是自然对数,约等于2.71。
Δf是新解与当前解目标函数值的差异,k是Boltzmann常数,T是当前温度。我们可以把右上角这一坨值Δf/kT看成一个整体x:ex的图形画出来是这样的(当差异值越大):
在这里插入图片描述
因为我们想要函数ex来代表一个概率值,所以我们只需要关注x为负数的部分即可:负数部分的值域是在(0,1)开区间内,x越小,越接近0,越大越靠近1。
因为在0到1之间,所以这个值相当于是概率了。比如ex=0.97,那么我们接受差解的概率就是97%。而正数部分的值域会大于1,也就是说概率会超过100%,所以会一定选(其实是上一种找到更优的情况)

所以总结一下就是:

  • 随机后的函数值如果结果更好,我们一定选择它(即x0=x1,f(x0)=f(x1))
  • 随机后的函数值如果结果更差,我们以eΔfkT的概率接受它

3、模拟退火优缺点

(1)优点

1、模拟退火算法不需要初始解过好,因此可以用于多种问题。
模拟退火算法的基本思路是从一个随机的解开始,在其周围随机抖动,直到找到最优解或达到一定的终止条件。初始解的好坏只是影响了算法的收敛速度和搜索方向,而并不影响算法的正确性。
2、模拟退火算法可以以一定概率接受更劣的解,
从而避免陷入全局最优解的周围,使搜索更全面,更有可能找到真正的最优解。那么模拟退火怎么跳出局部最优解的呢?如果当前解是一个局部最优解,即在附近的解中没有比它更好的解,那么一般情况下,该算法仍然会接受这个解,并以一定的概率接受更劣的解,这样就有可能跳出局部最优解并进一步找到全局最优解。这是因为模拟退火算法维护了一个全局搜索的历史信息,从而可以在全局范围内移动搜索的位置,而不仅限于局部最优解附近的解。在搜索过程中,模拟退火算法会不断改变温度,并决定是否接受更劣的解,从而让搜索过程向全局最优解更有可能靠近。

(2)缺点

找到最优解所耗费的时间较长,主要有跟以下几个原因有关: 初始温度过高、降温速度过慢
1、温度降低慢:
模拟退火算法的核心是温度下降,随着温度的降低,接受劣解的概率逐渐降低,最终趋于0。但是,如果温度降低的过于慢,那么算法将需要更长的时间才能达到较低的温度,也就意味着算法需要更多的迭代次数,时间成本也会增加。
2、跳出局部最优解缓慢:
模拟退火算法的另一个核心是可以接受更劣的解,在大部分时间里,接受一个劣解可能是能够跳出局部最优解的唯一方法。但是,当处于局部最优解时,算法可能会被唤醒到其他区域的几率非常小,如果算法陷入了某个较差的局部最优解,它也需要很长时间才能跳出去。
在温度下降和接受劣解的概率上找到一个合适的权衡,以及在跳出局部最优解上增加多样性和随机性,这些技巧可以加速算法的收敛速度。

4、模拟退火算法求解TSP模型

以下图为例,求从0号城市出发访问每一座城市并回到0号城市的最短回路
在这里插入图片描述
模拟退火算法的基本步骤如下:
(1) 初始化:初始温度T(充分大),初始解状态S(是算法迭代的起点),每个T值的迭代次数L
(2) 对k=1, …, L做第(3)至第6步:
(3) 产生新解S′
(4) 计算增量ΔT=C(S′)-C(S),其中C(S)为评价函数
(5) 若ΔT<0则接受S′作为新的当前解,否则以概率exp(-ΔT/T)接受S′作为新的当前解.
(6) 如果满足终止条件则输出当前解作为最优解,结束程序。
(终止条件通常取为连续若干个新解都没有被接受时终止算法。)
(7) T逐渐减少,且T->0,然后转第2步。
#模拟退火算法解TSP问题

import numpy as np
import random as rd
​
def lengthCal(path,distmat):             #计算距离
    length = 0
    for i in range(len(path) - 1):
        length += distmat[path[i]][path[i + 1]]
    length += distmat[path[-1]][path[0]]
    return  length
​
def exchange(path,exchangeSeq):        #交换路径中的两点得到新路径
    newPath = []
    for i in range(len(path)):
        newPath.append(path[i])
    temp = newPath[exchangeSeq[0]]
    newPath[exchangeSeq[0]] = newPath[exchangeSeq[1]]
    newPath[exchangeSeq[1]] = temp
    return newPath
​
distmat = np.array([[0,35,29,67,60,50,66,44,72,41,48,97],
                 [35,0,34,36,28,37,55,49,78,76,70,110],
                 [29,34,0,58,41,63,79,68,103,69,78,130],
                 [67,36,58,0,26,38,61,80,87,110,100,110],
                 [60,28,41,26,0,61,78,73,103,100,96,130],
                 [50,37,63,38,61,0,16,64,50,95,81,95],
                 [66,55,79,61,78,16,0,49,34,82,68,83],
                 [44,49,68,80,73,64,49,0,35,43,30,62],
                 [72,78,103,87,103,50,34,35,0,47,32,48],
                 [41,76,69,110,100,95,82,43,47,0,26,74],
                 [48,70,78,100,96,81,68,30,32,26,0,58],
                 [97,110,130,110,130,95,83,62,48,74,58,0]])
​
T = 100              #初始温度
α = 0.97              #温度变化率
iters = 1000          #每个温度的迭代次数
path= [i for i in range(12)]    #随机初始化路径
rd.shuffle(path)
while T > 10:
    for i in range(iters):
        exchangeSeq = rd.sample(range(0,12),2)
        newPath = exchange(path,exchangeSeq)       #随机交换路径中的两个点
        distanceDif = lengthCal(newPath,distmat) - lengthCal(path,distmat)
        if distanceDif < 0:
            path = newPath                         #接受新的解
        else:
            if rd.random() < np.exp(- distanceDif / T):  #以概率exp(-ΔT/T)接受新的解
                path = newPath
    T = α * T
print("满意解为")
print(path)
print("距离为")
print(lengthCal(path,distmat))

参考链接
模拟退火原理
模拟退火解决TSP问题
模拟退火解决TSP问题案例
https://blog.youkuaiyun.com/qq_40894102/article/details/105605228?spm=1001.2014.3001.5502

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值