模拟退火算法(SA)简介及Python实现

一、概述

  模拟退火算法(Simulated Annealing,SA)是一种模拟物理退火过程而设计的优化算法。它的基本思想最早在1953年就被Metropolis提出,但直到1983年,Kirkpatrick等人才设计出真正意义上的模拟退火算法并进行应用。
  模拟退火算法采用类似于物理退火的过程。先在一个高温状态下,然后逐渐退火,在每个温度下慢慢冷却,最终达到物理基态(相当于算法找到最优解)。模拟退火算法源于对固体退火过程的模拟,采用Metropolis准则,并用一组称为冷却进度表的参数控制算法的进程,使得算法在多项式时间里可以给出一个近似最优解。
  模拟退火算法在某一初温下,伴随温数的不断下降,结合概率突跳特性在解空间中随机寻找目标函数的全局最优解。即在局部最优解的空间内能概率性地跳出并最终趋于全局最优

二、模拟退火算法

一、算法的主要流程:

step1: 设定当前解(即为当前的最优解):令 T T T = T 0 T_0 T0 ,即开始退火的初始温度,随机生成一个初始解 x 0 x_0 x0 ,并计算相应的目标函数值E( x 0 x_0 x0)。
step2: 产生新解与当前解差值:根据当前解 x i x_i xi进行扰动,产生一个新解 x j x_j xj,计算相应的目标函数值E( x j x_j xj),得到𝜟𝑬=𝑬( x j x_j xj)−𝑬( x i x_i xi)。
step3: 判断新解是否被接受 :若𝜟𝑬<𝟎,则新解 x j x_j xj被接受;若𝜟𝑬>𝟎 ,则新解 x j x_j xj按概率e − ( 𝑬 ( x j ) − 𝑬 ( x i ) ) T i -(𝑬(x_j)−𝑬(x_i)) \over T_i Ti(E(xj)E(xi))接受, T i T_i Ti为当前温度。
step4: 当新解被确定接受时:新解 x j x_j xj被作为当前解
step5: 循环以上四个步骤:在温度 T i T_i Ti下,重复k次的扰动和接受过程,接着执行下一步骤。
step6: 最后找到全局最优解:判断T是否已经达到终止温度 T f T_f Tf,是,则终止算法;否,则转到循环步骤继续执行。

二、冷却进度表

  退火过程由一组初始参数,即冷却进度表控制。它的目的是尽量使系统达到平衡,以使算法在有限的时间内逼近最优解。它包括:

1.控制温度参数的初值 T 0 T_0 T0
  一般来说,只有足够大的 才能满足算法要求,但是由于不同问题处理的规模不同,所以这个“足够大”也是不同的,有的可能 T 0 T_0 T0 =100就好了,但是有的可能 T 0 T_0 T0 =1000还不够。实验表明:初温越大,获得全局最优解的机率越大,但花费的时间也会越长。

Metropolis准则:
  在某个温度下固体分子从一个状态转移到另一个状态时,如果新状态的内能小,则无条件接受;如果新状态的内能大,则以一定的概率接受它。

2.马尔科夫链的长度 L k L_k Lk:任意温度T的迭代次数
  算法在马尔科夫链长度内持续进行”产生新解—判断—接受/舍弃”的迭代过程,对应着固体在某一恒定温度下趋于热平衡的过程。若在一定的温度下做无限次迭代,相应的马尔科夫链可以达到平稳分布概率。
  马尔科夫链的选取还与温度控制参数 T k T_k Tk的下降密切相关,缓慢下降可以避免过长的马尔科夫链。在控制参数的衰减函数已经选定的前提下,让每个取值都能够达到准平衡状态。
  根据这一原则一般取 L k L_k Lk=100N,其中N为问题的规模。


3. 控制参数T的终值 T f T_f Tf(停止准则):
  合理的停止准则既能保证算法收敛于某一近似解,又能使最终解具有一定的全局性。通常可以根据迭代的次数或者终止的温度或者迭代过程在若干个相继的链中的解没有任何变化等条件来判断迭代的终止。
  最终温度通常是0,但会耗掉许多模拟时间。温度趋近于0,其周围状态几乎是一样的。所以找寻一个低到可接受的温度即可。


4. 控制温度T的衰减函数(温度的更新)
   不同退火方法的温度下降速度是不一样的,其中指数降温是最常用的一种退火策略,其温度变化很有规律,直接与参数相关,衰减函数:t k _k k+ 1 _1 1 t k t_k tk,k=0,1,2… 其中α是一个接近1的常数。一般取0.5~0.99。该衰减函数对控制参数的衰减量是随算法进程递减的。

注意:小的衰减量可能导致算法进程迭代次数的增加,从而使算法进程接受更多的变换,从而访问更多的邻域,搜索更大范围的解空间,返回更高质量的最终解。

三、算法的优缺点

   模拟退火算法的应用很广泛,可以高效地求解NP完全问题,如货郎担问题(Travelling Salesman Problem,简记为TSP)、最大截问题(Max Cut Problem)、0-1背包问题(Zero One Knapsack Problem)、图着色问题(Graph Colouring Problem)等等,但其参数难以控制,不能保证一次就收敛到最优值,一般需要多次尝试才能获得(大部分情况下还是会陷入局部最优值)。观察模拟退火算法的过程,具有以下主要优势:

  1. 迭代搜索效率高,并且可以并行化;
  2. 算法中有一定概率接受比当前解较差的解,因此一定程度上可以跳出局部最优;
  3. 算法求得的解与初始解状态S无关,因此有一定的鲁棒性;
  4. 具有渐近收敛性,已在理论上被证明是一种以概率l 收敛于全局最优解的全局优化算法。

三、python实现

代码我参考了别人的代码,如下

import numpy as np

# =================初始化参数===============
D = 10  # 变量维数
Xs = 20  # 上限
Xx = -20  # 下限
# ====冷却表参数====
L = 200  # 马可夫链长度 #在温度为t情况下的迭代次数
K = 0.95  # 衰减参数
S = 0.01  # 步长因子
T = 100  # 初始温度
YZ = 1e-7  # 容差
P = 0  # Metropolis过程中总接受点
# ====随机选点初值设定====
PreX = np.random.uniform(size=(D, 1)) * (Xs - Xx) + Xx
PreBestX = PreX  # t-1代的全局最优X
PreX = np.random.uniform(size=(D, 1)) * (Xs - Xx) + Xx
BestX = PreX  # t时刻的全局最优X

# ==============目标函数=============
def func1(x):
    return np.sum([i ** 2 for i in x])

# ====每迭代一次退火一次(降温), 直到满足迭代条件为止===
deta = np.abs(func1(BestX) - func1(PreBestX))  # 前后能量差

trace = []  # 记录
while (deta > YZ) and (T > 0.1):  # 如果能量差大于允许能量差 或者温度大于阈值
    T = K * T  # 降温

    # ===在当前温度T下迭代次数====
    for i in range(L):  #
        # ====在此点附近随机选下一点=====
        NextX = PreX + S * (np.random.uniform(size=(D, 1)) * (Xs - Xx) + Xx)
        # ===边界条件处理
        for ii in range(D):  # 遍历每一个维度
            while NextX[ii] > Xs or NextX[ii] < Xx:
                NextX[ii] = PreX[ii] + S * (np.random.random() * (Xs - Xx) + Xx)

        # ===是否全局最优解 ===
        if (func1(BestX) > func1(NextX)):
            # 保留上一个最优解
            PreBestX = BestX
            # 此为新的最优解
            BestX = NextX

        # ====Metropolis过程====
        if (func1(PreX) - func1(NextX) > 0):  # 后一个比前一个好
            # 接受新解
            PreX = NextX
            P = P + 1
        else:
            changer = -1 * (func1(NextX) - func1(PreX)) / T
            p1 = np.exp(changer)
            # 接受较差的解
            if p1 > np.random.random():
                PreX = NextX
                P = P + 1
        trace.append(func1(BestX))
    deta = np.abs(func1(BestX) - func1(PreBestX))  # 修改前后能量差

print('最小值点\n', BestX)
print('最小值\n', func1(BestX))
  • 12
    点赞
  • 74
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
### 回答1: 模拟退火算法(Simulated Annealing,SA)是一种全局优化算法,常用于解决各种复杂的组合优化问题。下面是一个基本的模拟退火算法Python 实现: ```python import random import math # 目标函数 def objective_function(x): return math.sin(x) # 初始解 def initial_solution(): return random.uniform(-math.pi, math.pi) # 定义温度函数 def temperature(k, T0): alpha = 0.95 return T0 * (alpha ** k) # 定义状态产生函数 def neighbor(x, delta): return x + random.uniform(-delta, delta) # 定义接受准则 def acceptance_criterion(delta, temperature): if delta < 0: return True else: p = math.exp(-delta / temperature) return random.random() < p # 模拟退火算法 def simulated_annealing(kmax, T0, delta): # 初始化当前解和最优解 x_curr = initial_solution() x_best = x_curr # 迭代过程 for k in range(kmax): # 产生新的状态 x_new = neighbor(x_curr, delta) # 计算能量差 delta_E = objective_function(x_new) - objective_function(x_curr) # 如果新状态更优,则接受 if acceptance_criterion(delta_E, temperature(k, T0)): x_curr = x_new # 更新最优解 if objective_function(x_curr) < objective_function(x_best): x_best = x_curr return x_best # 测试 x_best = simulated_annealing(kmax=1000, T0=100, delta=0.5) print("最优解:", x_best) print("最优值:", objective_function(x_best)) ``` 这个实现中,目标函数是 `math.sin(x)`,初始解是在区间 `[-π, π]` 内随机生成的,温度函数为 $T_k = T_0 \times \alpha^k$,其中 $\alpha = 0.95$,状态产生函数是在当前解的基础上,加上一个在 $[-\delta, \delta]$ 内随机产生的扰动,接受准则使用了 Boltzmann 分布的形式,即 $\mathrm{P}(\Delta E) = \exp(-\Delta E/T)$。在每次迭代中,首先产生一个新状态,然后计算能量差 $\Delta E$,如果新状态更优,则接受。最后,输出最优解和最优值。 需要注意的是,模拟退火算法的结果可能受到很多参数的影响,比如初始温度 $T_0$、温度下降速率 $\alpha$、状态产生函数的扰动范围 $\delta$ 等等,需要根据具体问题进行调整。 ### 回答2: 模拟退火算法是一种基于概率的全局优化算法,常用于求解复杂问题。 简单来说,模拟退火算法通过模拟固体退火的过程来逐渐降低系统能量,从而找到最优解。其基本思路是通过在初始解附近进行随机搜索,并接受部分劣解,从而有机会跳出当前局部最优解并找到潜在的全局最优解。 使用Python实现模拟退火算法的基本步骤如下: 1. 初始化:定义问题的初始解、温度和冷却率。 2. 外循环:反复迭代,直到满足终止条件(例如温度降至某个阈值或达到最大迭代次数)。 3. 内循环:在当前温度下,进行随机扰动并得到新的解。 4. 接受准则:根据一定的概率接受新解,一般采用Metropolis准则:若新解优于当前解,则直接接受;否则以一定概率接受差解,概率与温度和差解程度有关。 5. 更新温度:根据设定的冷却率逐渐降低温度。 6. 返回最优解。 以下是一个基本的模拟退火算法Python实现示例: ```python import random import math def simulated_annealing(initial_solution, initial_temperature, cooling_rate): current_solution = initial_solution best_solution = current_solution temperature = initial_temperature while temperature > 1: for i in range(cooling_rate): new_solution = get_neighbor(current_solution) energy_delta = calculate_energy(new_solution) - calculate_energy(current_solution) if energy_delta < 0 or random.random() < math.exp(-energy_delta / temperature): current_solution = new_solution if calculate_energy(current_solution) < calculate_energy(best_solution): best_solution = current_solution temperature *= cooling_rate return best_solution def get_neighbor(solution): # 实现获取相邻解的逻辑 pass def calculate_energy(solution): # 实现计算解的能量的逻辑 pass # 调用示例 initial_solution = ... initial_temperature = ... cooling_rate = ... best_solution = simulated_annealing(initial_solution, initial_temperature, cooling_rate) print(best_solution) ``` 在实际应用中,需要根据具体问题定义相邻解的生成方法和能量计算方法,并根据问题特性调整初始温度和冷却率等参数,以获得更好的求解效果。 ### 回答3: 模拟退火算法(Simulated Annealing)是一种启发式优化算法,常用于求解最优化问题。该算法的基本思想源于固体退火原理,通过模拟物质退火过程中的冷却过程,以一定的概率接受劣质解,从而避免陷入局部最优解,寻找全局最优解。 以下是使用Python实现模拟退火算法的步骤: 1. 初始化当前解和初始解温度: - 将当前解设为初始解。 - 设置初始解温度。 2. 迭代更新当前解: - 在当前解的邻域中生成一个新解。 - 计算新解的目标函数值与当前解的目标函数值的差值。 - 如果新解的目标函数值较好,则接受新解作为当前解。 - 如果新解的目标函数值较差,则以一定的概率接受新解作为当前解(概率公式通常为exp(-delta/T),其中delta为目标函数值差值,T为当前解温度)。 - 更新当前解温度。 3. 判断停止条件: - 当达到停止条件(如迭代次数、目标函数值变化很小等)时,停止迭代并输出结果。 - 否则,返回步骤2继续迭代更新当前解。 通过以上步骤,我们可以实现一个基本的模拟退火算法。 代码示例: ```python import math import random def simulated_annealing(): # 初始化当前解和初始解温度 current_solution = initial_solution() current_temp = initial_temperature() while not stop_condition(): # 在当前解的邻域中生成一个新解 new_solution = get_neighbor(current_solution) # 计算新解的目标函数值与当前解的目标函数值的差值 delta = calculate_delta(current_solution, new_solution) # 如果新解的目标函数值较好,则接受新解作为当前解 if delta > 0: current_solution = new_solution else: # 如果新解的目标函数值较差,则以一定的概率接受新解作为当前解 accept_prob = math.exp(delta / current_temp) if random.random() < accept_prob: current_solution = new_solution # 更新当前解温度 current_temp = update_temperature(current_temp) return current_solution # 根据具体问题定义初始化当前解和初始解温度的函数 def initial_solution(): # 初始化当前解 pass def initial_temperature(): # 初始化初始解温度 pass # 根据具体问题定义获取当前解邻域的函数 def get_neighbor(current_solution): # 获取当前解的邻域中的一个新解 pass # 根据具体问题定义计算目标函数值差值的函数 def calculate_delta(current_solution, new_solution): # 计算新解的目标函数值与当前解的目标函数值的差值 pass # 根据具体问题定义停止条件的函数 def stop_condition(): # 判断是否满足停止条件 pass # 根据具体问题定义更新当前解温度的函数 def update_temperature(current_temp): # 更新当前解温度 pass ``` 以上是使用Python实现模拟退火算法的基本步骤,具体在每个函数中需要根据实际问题做进一步的定义和实现

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值