智能优化算法之模拟退火(Simulated Annealing,SA)-附源码

在这里插入图片描述
获取更多资讯,赶快关注上面的公众号吧!

模拟退火(Simulated Annealing,SA)

本章将介绍模拟退火算法,它是受冶金中退火过程的启发而提出的一种元启发式优化算法。首先回顾退火算法的发展和应用,然后描述物理退火的过程及其与退火算法的映射关系,并详细描述算法的步骤,最后给出SA算法的伪代码和java代码实现。

灵感

SA由Kirkpatrick等人于1983年提出,其揭示了如何利用模拟固体退火过程的模型求解优化问题,在优化问题中,最小化目标函数对应于固体中的能量状态。

在物理退火过程中,固体首先被加热,然后慢慢冷却,直到到达最规则的晶格排列而没有晶格缺陷。加热会改变物质的物理甚至是化学特性,以增加其延展性并降低其硬度。固体中的粒子具有与最稳定状态下最小能量排列相对应的几何构型,物理退火是通过熔化一种物质,然后缓慢降低其温度来实现固体的低能排列的过程,值得注意的是,在冷却阶段,物质的温度必须缓慢下降,否则,生成的固体就会凝固成存在结构缺陷的晶体。

当应用SA时,物质的不同状态表示优化问题的不同解,该物质的能量相当于待优化的适应度函数,原子的移动引入新的解。在SA中,引入更优解的原理移动将被接受,引入更劣解的非改进移动以概率接受,此概率取决于接受函数。下表列出了模拟退火与优化算法之间的对应关系。

优化算法模拟退火
决策变量物质原子位置
物质状态
旧解物质当前状态
新解物质新的状态
最优解最优状态
适应度函数物质能量
初始解随机位置
选择接受函数
生成新解的过程原子移动

SA首先生成一个初始解,也就是物质的当前状态,通过适当的机制在当前状态的邻域中生成新的状态,并评估其适应度值,如果新的状态优于当前状态,则接受新的状态,否则以一定概率接受,此概率与系统温度有关,该算法在温度逐渐降低的同时,在每个温度下生成一定数量的新状态,不断尝试一部分解,直达每个温度下都达到热平衡准则,此时再次降低温度。随着温度的降低,选择非改进原子移动的概率也随之降低。整个生成新解的过程随着系统冷却逐渐重复,直到满足终止条件。SA的算法流程图如下所示。

图1 SA流程图

生成初始状态

SA生成的每个优化问题的解对应于物质原子的一种排列。系统状态包括在N维空间中的N个决策变量,可以表示为一个大小为 1 × N 1\times N 1×N的数组,如下:

State = X = ( x 1 , x 2 , … , x i , … , x N ) (1) \text {State}=X=\left(x_{1}, x_{2}, \ldots, x_{i}, \ldots, x_{N}\right)\tag {1} State=X=(x1,x2,,xi,,xN)(1)

其中 X X X为优化问题的一个解, x i x_{i} xi为解中 X X X的第 i i i个决策变量, N N N为决策变量的个数。对于连续问题和离散问题,决策变量值 ( x 1 , x 2 , … , x i , … , x N ) \left(x_{1}, x_{2}, \ldots, x_{i}, \ldots, x_{N}\right) (x1,x2,,xi,,xN)可以表示为实数或一组预定义的值。初始时随机生成一个初始化状态,该状态就是系统的当前状态。

生成新的状态

在退火过程中,原子移动到新的位置,以降低系统能量,实现稳定状态。在当前状态基础上生成新的系统可能状态,有多种确定性的和随机性的机制可以根据给定的解生成邻域解。最常用的一种机制就是随机行走,即:

x i ′ = x i + R n d ( − ε , ε ) , i = 1 , 2 , … , N (2) x_{i}^{\prime}=x_{i}+ Rnd(-\varepsilon, \varepsilon), \quad i=1,2, \ldots, N\tag{2} xi=xi+Rnd(ε,ε),i=1,2,,N(2)

其中 x i x_{i} xi i i i个决策变量的新值, R n d ( a , b ) Rnd(a,b) Rnd(a,b) [ a , b ] [a,b] [a,b]范围内的随机值, ε \varepsilon ε为一个较小的数。

所有决策变量的新值在生成新解 之前先进行评估,然后新解按下式生成:
X ( n e w ) = ( x 1 ′ , x 2 ′ , … , x i ′ , … , x N ′ ) (3) X^{(n e w)}=\left(x_{1}^{\prime}, x_{2}^{\prime}, \ldots, x_{i}^{\prime}, \ldots, x_{N}^{\prime}\right)\tag{3} X(new)=(x1,x2,,xi,,xN)(3)

接受函数

接受函数用于确定是否使用新生成的解替换当前解,新解代表物质的一种可能的排列,其接受与否取决于旧解和新解的适应度值。当新解适应度值优于旧解时,新解替换旧解,否则新解一定概率替换旧解,该概率根据新旧解适应度值之间的差异计算得到。针对最小化问题,根据如下的接受概率函数来接受新解:
P ( X , X ( n e w ) ) = { 1  if  F ( X ( n e w ) ) < F ( X ) e − Δ F λ  Otherwise  } (4) P\left(X, X^{(n e w)}\right)=\left\{\begin{array}{ll} 1 & \text { if } F\left(X^{(n e w)}\right)<F(X) \\ e^{\frac{-\Delta F}{\lambda}} & \text { Otherwise } \end{array}\right\}\tag{4} P(X,X(new))={1eλΔF if F(X(new))<F(X) Otherwise }(4)

Δ F = ∣ F ( X ( n e w ) ) − F ( X ) ∣ (5) \Delta F=\left|F\left(X^{(n e w)}\right)-F(X)\right|\tag{5} ΔF=F(X(new))F(X)(5)

其中 X X X为旧解, X ( n e w ) X^{(new)} X(new)为新生成的解, P ( X , X ( n e w ) ) P\left( {X,{X^{(new)}}} \right) P(X,X(new))大于等于 R a n d ∈ [ 0 , 1 ] Rand\in[0,1] Rand[0,1]为使用 X ( n e w ) X^{(new)} X(new)替换 X X X的概率, F ( X ) F(X) F(X)为解 X X X的适应度值, λ \lambda λ为控制参数,对应于物理退火中的温度。如果 P ( X , X ( n e w ) ) P\left( {X,{X^{(new)}}} \right) P(X,X(new))大于等于 R a n d ∈ [ 0 , 1 ] Rand\in[0,1] Rand[0,1],则使用 X ( n e w ) X^{(new)} X(new)替换 X X X,否则就不接受新解。式(4)和式(5)定义的接受函数为玻尔兹曼分布,当适应度值差异较大时,概率将变小,因此适应度值差异较小时更容易被接受。同理, λ \lambda λ较大时非改进改变更容易被接受,即当 λ \lambda λ较大时选择压力较小。参数 λ \lambda λ对于算法正确收敛起着重要的作用,算法初期 λ \lambda λ应该较大,以避免陷入局部最优,随着算法逐渐进行其也应该逐渐下降。

热平衡

当在每一温度下发生大量的邻域运动时,系统在每一温度下达到热平衡,可以证明,在热平衡时,系统状态的概率分布服从玻尔兹曼分布。SA通过尝试在每个温度下的多个邻域移动来进行,换言之,对于每个温度 λ \lambda λ,在温度降低之前,需要生成多个新的状态(不管是接受还是拒绝),这些新的状态需要通过接受函数进行测试,至于需要生成多少个新的状态,是用户定义的算法参数,通常表示为 β \beta β。当生成了 β \beta β个新解并由接受函数测试后,就满足了热平衡。

温度下降

在测试多个新的状态后,系统温度逐渐下降:

lim ⁡ t → + ∞ λ t = 0 , t > 0 (6) \lim _{t \rightarrow+\infty} \lambda_{t}=0, \quad t>0\tag{6} t+limλt=0,t>0(6)
其中 t t t为算法迭代次数。

两种常见的降低 λ \lambda λ的方法分别是线性法和几何法。

线性法使用下式在每次迭代中更改 λ \lambda λ
λ t = λ 0 − α × t (7) \lambda_{t}=\lambda_{0}-\alpha \times t\tag{7} λt=λ0α×t(7)

α = λ 0 − λ T T (8) \alpha=\frac{\lambda_{0}-\lambda_{T}}{T}\tag{8} α=Tλ0λT(8)

其中 λ 0 \lambda_{0} λ0为初始温度, λ t \lambda_{t} λt为第 t t t次迭代时的温度, T T T为总迭代次数, α \alpha α为冷却因子。

系统冷却的几何法如下:
λ t = λ 0 × α t , 0 < α < 1 (9) \lambda_{t}=\lambda_{0} \times \alpha^{t}, \quad 0<\alpha<1\tag{9} λt=λ0×αt,0<α<1(9)

几何法的优点在于其不需要指定算法的最大迭代次数。算法的终止条件可以是迭代 T T T的最大次数,也可以是其他终止条件,如运行时间。在这种情况下,T的值是未知的,SA算法将继续执行,直到满足停止条件(例如,运行时间)。

终止条件

终止条件决定何时终止SA算法。选择合适的终止准则对算法的正确收敛有重要作用。迭代次数、连续迭代之间目标函数的增量改进和运行时间是SA算法实现中常用的终止条件。

伪代码和Java实现

开始

  输入算法参数和初始数据;

  生成初始解 X X X并进行评估;

  While(终止条件未满足)

    For j j j=1 to β \beta β

      生成新解 X ( n e w ) X^{(new)} X(new),并进行评估;

      If 新解 ( X ( n e w ) ) (X^{(new)}) (X(new))优于旧解 ( X ) (X) (X)

        令 X = X ( n e w ) X=X^{(new)} X=X(new)

      Otherwise

        计算 P ( X , X ( n e w ) ) P\left( {X,{X^{(new)}}} \right) P(X,X(new)),生成[0,1]内的随机数 R a n d Rand Rand;

        If P ( X , X ( n e w ) ) P\left( {X,{X^{(new)}}} \right) P(X,X(new))> R a n d Rand Rand

          令 X = X ( n e w ) X=X^{(new)} X=X(new)

        End if

      End if

    Next j j j

    降低温度

  End while

  输出解 X X X

End

下面结合代码具体说一下算法执行流程,java源码关注公众号后回复模拟退火即可获取。

  1. 初始参数设置。主要设置最大迭代次数 maxGen,求解问题维度 dim,初始温度T0,温度下降率alpha,热平衡beta和目标函数 objectiveFun 等。
ObjectiveFun objectiveFun = new ObjectiveFun();
SANormal sa = SANormal.builder().maxGen(400).dim(2).T0(10).beta(200).objectiveFun(objectiveFun).build();
  1. 生成初始解
private Substance genInitSolution() {
	// TODO Auto-generated method stub
	Substance substance = new Substance(new Position(dim, objectiveFun.getRange()));
	substance.setEnergy(objectiveFun.getObjValue(substance.getPosition().getPositionCode()));
	return substance;
}
  1. 生成新的解。采用随机游走的方式对旧解进行扰动。
private Substance genNewSolution(Substance oldSubstance) {
	// TODO Auto-generated method stub
	Substance newSubstance = new Substance(new Position(dim, objectiveFun.getRange()));
	double[] newPositionCode = IntStream.range(0, this.dim)
			.mapToDouble(ind -> oldSubstance.getPosition().getPositionCode()[ind]
					+ 0.1 * objectiveFun.getRange().getScale()[ind] * (random.nextDouble() - 0.5))
			.toArray();
	newSubstance.getPosition().setPositionCode(newPositionCode);
	newSubstance.setEnergy(this.objectiveFun.getObjValue(newSubstance.getPosition().getPositionCode()));
	return newSubstance;
}
  1. 接受新解与否
// 针对最大化问题
if (newSubstance.getEnergy() > bestSubstance.getEnergy()) {
	substance = newSubstance;
} else {
	double deldaF = Math.abs(newSubstance.getEnergy() - bestSubstance.getEnergy());
	double p = Math.pow(Math.E, -deldaF / T);
	double rand = random.nextDouble();
	if (rand <= p) {
		substance = newSubstance;
	}
}
  1. 更新迭代器。迭代次数加1,温度降低。
public void incrementIter() {
  iterator++;
  T = T * alpha;
}
  1. 循环
while (iterator < maxGen) {
	for (int j = 0; j < beta; j++) {
		Substance newSubstance = genNewSolution(substance);
		// 针对最大化问题
		if (newSubstance.getEnergy() > bestSubstance.getEnergy()) {
			substance = newSubstance;
		} else {
			double deldaF = Math.abs(newSubstance.getEnergy() - bestSubstance.getEnergy());
			double p = Math.pow(Math.E, -deldaF / T);
			double rand = random.nextDouble();
			if (rand <= p) {
				substance = newSubstance;
			}
		}
	}
	if (substance.getEnergy() > bestSubstance.getEnergy()) {
		bestSubstance.getPosition().setPositionCode(substance.getPosition().getPositionCode());
		bestSubstance.setEnergy(substance.getEnergy());
	}
	incrementIter();
	System.out.println("**********第" + iterator + "代最优解:" + bestSubstance + "**********");
	T = T * alpha;
}

测试中使用的目标函数(最大化)方程和图像分别如下:

exp(-(x-4)^2-(y-4)^2)+exp(-(x+4)^2-(y-4)^2)+2*exp(-x^2-(y+4)^2)+2*exp(-x^2-y^2)

实验结果如下:

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
模拟退火算法Simulated AnnealingSA)是一种基于概率的全局优化算法,通常用于在大规模搜索空间中寻找全局最优解。它的基本思想是在解空间中随机漫步,接受劣解的概率随着温度的下降而减小,最终达到全局最优解。 下面是模拟退火算法的一个简单实现: 1. 初始化温度T和初始解x。 2. 重复以下操作,直到达到停止条件: - 生成一个新解x',使得x'在x的邻域中。 - 计算x'的目标函数值f(x')。 - 计算能量差ΔE=f(x')-f(x)。 - 如果ΔE<0,则接受x'作为新解。 - 如果ΔE>=0,则以概率e^(-ΔE/T)接受x'作为新解。 - 降低温度T。 3. 返回最优解。 其中,温度T的降低有多种方式,可以按照一定的函数关系进行指数下降,也可以按照一定的比例进行线性下降。 下面是一个简单的Python实现: ```python import random import math def simulated_annealing(init_solution, neighbor_func, objective_func, T, T_min, alpha): current_solution = init_solution best_solution = current_solution while T > T_min: for i in range(100): new_solution = neighbor_func(current_solution) delta_E = objective_func(new_solution) - objective_func(current_solution) if delta_E < 0: current_solution = new_solution if objective_func(current_solution) < objective_func(best_solution): best_solution = current_solution else: p = math.exp(-delta_E / T) if random.random() < p: current_solution = new_solution T *= alpha return best_solution ``` 其中,`init_solution`是初始解,`neighbor_func`是邻域函数,用于生成新解,`objective_func`是目标函数,用于计算解的价值,`T`是初始温度,`T_min`是最低温度,`alpha`是温度下降率。这里的邻域函数可以根据具体问题进行定义。 使用方法如下: ```python def neighbor_func(x): return [x[0] + random.uniform(-1, 1), x[1] + random.uniform(-1, 1)] def objective_func(x): return (x[0] - 1) ** 2 + (x[1] - 2) ** 2 init_solution = [0, 0] T = 1.0 T_min = 0.00001 alpha = 0.99 best_solution = simulated_annealing(init_solution, neighbor_func, objective_func, T, T_min, alpha) print('Best solution:', best_solution) print('Objective value:', objective_func(best_solution)) ``` 这里使用了一个简单的例子,目标函数为$(x_1-1)^2+(x_2-2)^2$,邻域函数为在当前解的基础上加上一个随机扰动。运行结果如下: ``` Best solution: [0.9864299254861487, 1.9646801078338144] Objective value: 0.0002519619956903344 ``` 可以看出,算法找到了较优的解。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

松间沙路hba

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值