模拟退火算法(Simulated Annealing):从物理学到优化的经典方法
模拟退火算法(Simulated Annealing):从物理学到优化的经典方法
作为一名熟悉大模型的研究者,你可能对深度学习中的梯度下降、Adam 优化等方法耳熟能详。但在阅读 Noise Conditioned Score Network (NCSN,参考笔者的博客:Denoising Score Matching:去噪分数匹配的优雅与实用性) 的退火朗之万采样时,可能会遇到“模拟退火”(Simulated Annealing, SA)这一术语。这是一个源于物理学的经典优化算法,虽然在现代深度学习中较少直接使用,但在理解退火类方法(如 NCSN 的采样)及其应用场景时非常有帮助。本篇博客将介绍模拟退火的原理、用途,并提供 Python 代码示例,帮助你快速掌握这一传统方法。
什么是模拟退火?
模拟退火算法灵感来源于物理学中的退火过程。退火是冶金学中的一种技术,通过将金属加热到高温后缓慢冷却,使其内部原子从无序状态逐渐排列为低能量、有序的晶体结构。模拟退火将这一过程类比为优化问题:
- 高温阶段:系统处于高能量状态,允许探索解空间的各种可能性。
- 冷却阶段:温度逐渐降低,系统趋向于收敛到低能量状态,即最优解。
在优化问题中,模拟退火的目标是寻找目标函数的最优解(通常是最小值),尤其适用于那些具有多局部最优解的复杂、非凸问题。
模拟退火的原理
假设我们要最小化一个目标函数 ( f ( x ) f(x) f(x) ),( x x x ) 是解空间中的一个状态。模拟退火的步骤如下:
-
初始化:
- 随机选择一个初始解 ( x 0 x_0 x0 )。
- 设置初始温度 ( T 0 T_0 T0 )(通常较高)。
-
迭代更新:
- 在当前解 ( x t x_t xt ) 的邻域内随机生成一个新解 ( x ′ x' x′ )。
- 计算能量差(目标函数的变化):( Δ E = f ( x ′ ) − f ( x t ) \Delta E = f(x') - f(x_t) ΔE=f(x′)−f(xt))。
- 接受规则(Metropolis 准则):
- 如果 ( Δ E ≤ 0 \Delta E \leq 0 ΔE≤0)(新解更优),接受 ( x ′ x' x′ ) 作为新解。
- 如果 ( Δ E > 0 \Delta E > 0 ΔE>0)(新解更差),以概率 ( P = exp ( − Δ E / T ) P = \exp(-\Delta E / T) P=exp(−ΔE/T) ) 接受 ( x ′ x' x′ )。这允许算法跳出局部最优。
-
降温:
- 按照冷却策略(如 ( T t + 1 = α T t T_{t+1} = \alpha T_t Tt+1=αTt ),( α < 1 \alpha < 1 α<1))降低温度。
- 温度越低,接受次优解的概率越小。
-
终止:
- 当温度降至某个阈值或达到最大迭代次数时,停止,返回当前解作为最优解。
关键特性
- 随机性:通过随机扰动和概率接受机制,模拟退火可以探索解空间,避免陷入局部最优。
- 温度控制:高温时更具探索性,低温时更倾向于收敛。
模拟退火有什么用?
模拟退火是一种全局优化算法,特别适合以下场景:
- 非凸优化问题:
- 当目标函数有多个局部最优解时(如旅行商问题 TSP、函数优化),梯度下降容易卡在局部极值,而模拟退火能跳出这些陷阱。
- 离散问题:
- 对于组合优化问题(如调度、图划分),解空间是离散的,模拟退火通过邻域搜索有效应对。
- 初始解不敏感:
- 与依赖初始值的局部搜索不同,模拟退火对初始解的依赖较低,适合未知领域的问题。
- 生成模型中的退火采样:
- 在 NCSN 等方法中,退火思想被用于从高噪声到低噪声逐步生成样本,模拟退火提供了一个类似的逐步优化框架。
Python 代码实现
以下是一个简单的模拟退火算法实现,用于最小化一个二维函数 ( f ( x , y ) = x 2 + y 2 f(x, y) = x^2 + y^2 f(x,y)=x2+y2 )(全局最优解为 ( ( 0 , 0 ) (0, 0) (0,0) ))。
import numpy as np
# 目标函数:f(x, y) = x^2 + y^2
def objective_function(x):
return x[0]**2 + x[1]**2
# 模拟退火算法
def simulated_annealing(initial_solution, initial_temp, cooling_rate, min_temp, max_iter):
"""
Args:
initial_solution: 初始解 (np.array)
initial_temp: 初始温度
cooling_rate: 冷却系数 (0 < cooling_rate < 1)
min_temp: 最低温度
max_iter: 每温度的最大迭代次数
Returns:
best_solution: 最优解
best_value: 最优值
"""
current_solution = initial_solution.copy()
current_value = objective_function(current_solution)
best_solution = current_solution.copy()
best_value = current_value
temp = initial_temp
while temp > min_temp:
for _ in range(max_iter):
# 在邻域内随机生成新解
perturbation = np.random.normal(0, 0.1, size=current_solution.shape)
new_solution = current_solution + perturbation
new_value = objective_function(new_solution)
# 计算能量差
delta_e = new_value - current_value
# Metropolis 准则
if delta_e <= 0 or np.random.rand() < np.exp(-delta_e / temp):
current_solution = new_solution
current_value = new_value
# 更新最优解
if current_value < best_value:
best_solution = current_solution.copy()
best_value = current_value
# 降温
temp *= cooling_rate
return best_solution, best_value
# 主函数
def main():
# 参数设置
initial_solution = np.array([5.0, 5.0]) # 初始解
initial_temp = 1000.0 # 初始温度
cooling_rate = 0.95 # 冷却系数
min_temp = 0.01 # 最低温度
max_iter = 100 # 每温度迭代次数
# 运行模拟退火
best_solution, best_value = simulated_annealing(
initial_solution, initial_temp, cooling_rate, min_temp, max_iter
)
print(f"最优解: {best_solution}")
print(f"最优值: {best_value}")
if __name__ == "__main__":
main()
代码说明
- 目标函数:这里用 ( f ( x , y ) = x 2 + y 2 f(x, y) = x^2 + y^2 f(x,y)=x2+y2 ) 作为示例,真实问题中可以替换为任何复杂函数。
- 邻域扰动:通过高斯噪声生成新解,模拟邻域搜索。
- Metropolis 准则:用 ( exp ( − Δ E / T ) \exp(-\Delta E / T) exp(−ΔE/T) ) 计算接受概率。
- 冷却策略:温度按 ( T = T × 0.95 T = T \times 0.95 T=T×0.95 ) 递减。
运行结果可能为:
最优解: [0.0123, -0.0087]
最优值: 0.000226
由于随机性,每次结果略有不同,但会接近全局最优解 ( ( 0 , 0 ) (0, 0) (0,0) )。
与 NCSN 的联系
NCSN 的退火朗之万采样从高噪声水平(如 ( σ 1 \sigma_1 σ1))到低噪声水平(如 ( σ L \sigma_L σL))逐步去噪,类似于模拟退火从高温到低温的优化过程:
- 高温(大 ( σ \sigma σ)):允许大范围探索,生成粗略样本。
- 低温(小 ( σ \sigma σ)):细化细节,逼近真实分布。
模拟退火的随机接受机制与朗之万动态中的噪声项有异曲同工之妙,都是为了跳出局部陷阱。
总结
模拟退火是一种经典的全局优化算法,通过模拟物理退火过程解决复杂优化问题。它在旅行商问题、调度优化等领域有广泛应用,并在生成模型的退火采样中提供了理论启发。虽然在深度学习中,它常被梯度方法取代,但在理解多尺度优化和随机搜索时仍具价值。希望这篇博客和代码能让你对模拟退火有个直观的认识!
后记
2025年3月8日16点40分于上海,在grok 3大模型辅助下完成。