目录
老饼讲解:一步一步上手学习

【代码】模拟退火(SA)-优化函数

作者 : 老饼 发表日期 : 2025-12-08 16:47:25 更新日期 : 2026-05-15 11:51:28
老饼讲解-简单易懂,干货满满,爽过嗦螺!


好了,上节我们已经用模拟退火来优化TSP问题了,这节我们来看看模拟退火怎么用来优化函数。

一、模拟退火-用于函数优化

好了,就让我们开始玩玩模拟退火,看它怎么优化函数吧。

1.1. 目标优化函数

作为学习我们就以下面的简单函数来作为问题:

求 为何值时, 取得最小值。

容易知道,y的最小值在处取得最小值0,下面我们使用模拟退火算法来进行求解,看看它能不能找到这个最优值。

1.2. 模拟退火-优化函数-方案

用模拟退火解决该问题时,主要需要确定以下两点:

1. 能量函数是什么

在这里我们将目标函数作为能量函数就可以 

2. 邻域中获得新解的方式

这里我们在解的邻域随机选择就可以 

使用模拟退火解决问题时,都需要确定以上两点,不同的方案就会有不同的结果,所以模拟退火是一种半开放式的算法,需要自己定义能量函数和新解的获得方式。

二、模拟退火-函数优化-代码实现

好了,就按上面的方案,用模拟退火算法来优化目标函数,闲话少说,直接上代码,如下:

% 本代码展示模拟退火算法求解函数极小值问题,目标函数为:y = (x1-2)^2+(x2-3)^2
% 本代码来自《老饼讲解神经网络》www.bbblearn.com ,matlab版本:2018a   
setdemorandstream(888);                                                     % 为方便复现结果,设定随机种子
x     = [0,0];                                                              % 初始化x 
E     = calE(x);                                                            % 初始化能量
teamp = 100;                                                                % 设置初始温度
											                               
% 初始化温度(取N次邻域能量差均值的10倍)                                    
try_cn = 20;                                                                % 尝试20次
En   = zeros(1,try_cn);                                                     % 初始化邻域能量
for i = 1:try_cn                                                            % 逐次尝试
    new_x = x+ 0.1*(rand(size(x))-0.5);                                     % 在邻域中随机取一个解作为新解
    En(i)= calE(new_x);                                                     % 记录本次邻域解的能量
end                                                                         
teamp = mean(abs(En-E))*10 ;                                                % 初始化温度
											                               
% ----------外循环------                                                   
for t = 1:10000                                                             % 迭代10000次
    minE = E;                                                               % 初始化本次温度下的最小能量
    maxE = E;                                                               % 初始化本次温度下的最大能量
    % ------内循环------                                                   
    for i=1:100                                                            
        new_x = x+ 0.05*(rand(size(x))-0.5);                                % 在邻域中随机取一个解作为新解
        new_E = calE(new_x);                                                % 计算新解的能量
		
        % 按概率接受新解                                                   
        if(exp((E-new_E)/teamp)>rand())                                     % 如果接受新解
            x    = new_x;                                                   % 更新解
            E    = new_E;                                                   % 更新当前能量
            minE = min(E,minE);                                             % 更新本次温度下的最小能量
            maxE = max(E,maxE);                                             % 更新本次温度下的最大能量
        end
    end
	fprintf('第%d轮:x=[%.4f,%.4f],E=%.5f,teamp:%.5f\n',t,x(1),x(2),E,teamp) % 打印结果
    % --降温,并检查是否退出循环--    
    teamp = teamp*0.5;                                                      % 降温
    if( (maxE-minE)/maxE<0.01 )                                             % 如果最大最小能量没什么区别
        break                                                               % 则终止迭代
    end                                                                     
end                                                                         
											                                
%定义能量计算函数(目标函数)                                                 
function y = calE(x)                                                        % 能量计算函数
    y = (x(1)-2).^2+(x(2)-3).^2;                                            % 计算目标函数值
end

代码运行结果如下:

模拟退火-优化函数的结果

最终的解为x = [2.004,2.9999],与我们预期的[2,3]的差异极小,可见,模拟退火算法已经取得了较好的效果。

总结

模拟退火用于函数优化是很简单的,在获取新解时,只需随便在领域取一个值就行了,实现起来非常方便!而且即使是不同的目标函数,也可以换汤不换药,照抄过去就行了,这就是为什么我最喜欢这个算法了,简单有效易实现。



图标 评论
添加评论