本项目包含三个 MATLAB 脚本/函数文件,主要用于演示和实现最速下降法(Steepest Descent Method)在不同目标函数上的优化过程。适合用于数值优化、无约束优化方法的学习与实验。
文件列表
- Steepest_descent_method.m
- Rosenbrock_function.m
- Scaled_quadratic_function.m
一、Steepest_descent_method.m
功能简介:
该脚本实现了最速下降法(带 Armijo 回溯线搜索),用于求解无约束优化问题。可选择优化 Rosenbrock 函数或缩放二次函数,并可视化优化过程。
主要内容:
- 支持两种目标函数(Rosenbrock 和缩放二次函数),可通过修改
if 0
语句块切换。 - 采用 Armijo 条件的回溯线搜索自动调整步长。
- 记录并输出每次迭代的函数值、梯度范数、到最优点的距离等信息。
- 迭代结束后,绘制优化轨迹、目标函数收敛曲线、梯度范数收敛曲线和到最优点距离的收敛曲线。
- 可用于分析最速下降法的收敛速度和理论收敛率。
主要变量说明:
x
:当前迭代点objfun
:目标函数句柄xs
、fs
、norm_gs
:分别记录每次迭代的点、函数值和梯度范数alpha0
、tau
、beta
:线搜索相关参数kappa
:Hessian 条件数,用于理论收敛率分析
% Run steepest descent (% Solver settings % 求解器设置max_iterations = 800; % 设置最大迭代次数为800tol_g = 1e-5; % termination condition ||gradient|| <= tol % 终止条件:梯度范数小于等于容差alpha0 = 1; % initial step length % 初始步长为1tau = 0.5; % backtracking parameter % 回溯参数为0.5beta = 0.001; % for Armijo condition % Armijo条件参数为0.001
% Useful data to see progress of solver % 用于观察求解器进展的有用数据n = numel(x); % 获取变量向量x的元素个数xs = zeros(max_iterations+1, n); % iterate % 初始化存储所有迭代点的矩阵fs = zeros(max_iterations+1,1); % objective value at each iteration % 初始化存储每次迭代函数值的向量norm_gs = zeros(max_iterations+1,1); % ||gradient|| at each iteration % 初始化存储每次迭代梯度范数的向量
% Set initial data % 设置初始数据xs(1,:) = x; % 将初始点存储到迭代点矩阵的第一行[f, g] = objfun(x); % 计算初始点的函数值和梯度fs(1,:) = f; % 将初始函数值存储到函数值向量的第一个元素norm_gs(1,:) = norm(g); % 将初始梯度范数存储到梯度范数向量的第一个元素% 运行最速下降法(带线搜索)% Lindon Roberts, 2019 % 作者:Lindon Roberts,2019年
clear, close all % 清除工作空间变量,关闭所有图形窗口
% Problem and x0 % 问题设置和初始点x0if 0 % 如果条件为0(即false,不执行此分支) a = 10; % 设置参数a为10 objfun = @(x)Scaled_quadratic_function(x,a); % 创建缩放二次函数句柄 x = [1; a]; % 设置初始点为[1; a] xmin = [0;0]; % true minimiser % 设置真实最小值点为[0;0]else % 否则执行此分支 objfun = @(x)Rosenbrock_function(x); % 创建Rosenbrock函数句柄 x = [1.5; 1.5]; % 设置初始点为[1.5; 1.5] %x = [-1.2; 1]; % 另一个可选初始点[-1.2; 1] %x = [0.4; 0.2]; % start close to the solution % 接近解的起始点[0.4; 0.2] xmin = [1;1]; % true minimiser % 设置真实最小值点为[1;1]endnhistory = 10; % use last N iterates to check asymptotic rate % 使用最后N次迭代来检查渐近收敛率
% True info % 真实信息[fmin, gmin, Hmin] = objfun(xmin); % true minimum % 计算真实最小值点处的函数值、梯度和Hessian矩阵kappa = cond(Hmin); % 计算Hessian矩阵的条件数
% Solver settings % 求解器设置max_iterations = 800;tol_g = 1e-5; % termination condition ||gradient|| <= tolalpha0 = 1; % initial step lengthtau = 0.5; % backtracking parameterbeta = 0.001; % for Armijo condition
% Useful data to see progress of solvern = numel(x);xs = zeros(max_iterations+1, n); % iteratefs = zeros(max_iterations+1,1); % objective value at each iterationnorm_gs = zeros(max_iterations+1,1); % ||gradient|| at each iteration
% Set initial dataxs(1,:) = x;[f, g] = objfun(x);fs(1,:) = f;norm_gs(1,:) = norm(g);
k = 1; % 初始化迭代计数器为1fprintf(' k | f(xk) | ||grad|| \n'); % 打印表头:迭代次数、函数值、梯度范数fprintf('--------------------------------\n'); % 打印分隔线fprintf(' %i | %.4e | %.4e \n', k-1, f, norm(g)); % 打印初始状态信息while k <= max_iterations && norm(g) >= tol_g % 当迭代次数未超过最大值且梯度范数大于容差时继续迭代 s = -g; % steepest descent direction % 设置最速下降方向为负梯度方向 % Backtracking Armijo linesearch % 回溯Armijo线搜索 alpha = alpha0; % 设置初始步长 xtest = x + alpha*s; % 计算测试点 while objfun(xtest) > f + beta*alpha*(g'*s) % 当不满足Armijo条件时 alpha = tau*alpha; % 缩小步长 xtest = x + alpha*s; % 重新计算测试点 end x = xtest; % 更新当前点为测试点 [f, g] = objfun(x); % 计算新点的函数值和梯度 if mod(k, 10) == 0 % 如果迭代次数是10的倍数 fprintf(' %i | %.4e | %.4e \n', k, f, norm(g)); % 打印当前状态信息 end % Save info % 保存信息 xs(k+1,:) = x; % 将当前点存储到迭代点矩阵 fs(k+1,:) = f; % 将当前函数值存储到函数值向量 norm_gs(k+1,:) = norm(g); % 将当前梯度范数存储到梯度范数向量 k = k + 1; % 迭代计数器加1endfprintf(' %i | %.4e | %.4e <- finished\n', k-1, f, norm(g)); % 打印最终状态信息并标记结束fprintf('Finished after %g iterations\n', k-1) % 打印总迭代次数xs = xs(1:k, :); % 截取实际使用的迭代点数据fs = fs(1:k, :); % 截取实际使用的函数值数据norm_gs = norm_gs(1:k, :); % 截取实际使用的梯度范数数据xdists = zeros(k,1); % 初始化存储到最优点距离的向量for i=1:k % 对每个迭代点 xdists(i) = norm(xs(i,:) - xmin); % 计算当前点到最优点的距离end
% Check asymptotic order of convergence % 检查渐近收敛阶if numel(fs) < nhistory % 如果函数值个数少于历史记录数 asym_fs = fs; % 使用所有函数值else % 否则 asym_fs = fs(end-nhistory:end); % 使用最后nhistory个函数值endfit_fs = polyfit(log(asym_fs(1:end-1)), log(asym_fs(2:end)), 1); % 对对数函数值进行一次多项式拟合fprintf('Objective values converge with order %1.2f\n', fit_fs(1)); % 打印目标函数值的收敛阶
%=====================================================% Plot iterates, objective decrease, gradient decrease % 绘制迭代点、目标函数下降、梯度下降%=====================================================
subplot(2,2,1); % 创建2×2子图的第1个子图npts = 30; % 设置网格点数为30xplt = linspace(min(min(xs)), max(max(xs)), npts); % 在迭代点范围内创建x轴网格yplt = xplt; % y轴网格与x轴相同[X,Y] = meshgrid(xplt,yplt); % 创建二维网格Z = zeros(npts,npts); % 初始化函数值网格for i=1:npts % 对每个网格点i for j=1:npts % 对每个网格点j Z(i,j) = log(objfun([X(i,j); Y(i,j)])); % 计算网格点处的对数函数值 endendcontour(X,Y,Z,20) % 绘制20条等高线hold on % 保持当前图形axis equal % 设置坐标轴等比例plot(xs(:,1), xs(:,2), 'r.-', 'MarkerSize', 15); % 绘制迭代轨迹,红色点线,标记大小15xlabel('x1'); % 设置x轴标签ylabel('x2'); % 设置y轴标签hold off % 释放图形保持
subplot(2,2,2); % 创建2×2子图的第2个子图semilogy(fs-fmin, 'b-', 'Linewidth', 2); % 绘制目标函数值与最小值差的半对数图,蓝色实线,线宽2hold on % 保持当前图形xlabel('Iteration'); % 设置x轴标签为"迭代次数"ylabel('Objective value - fmin'); % 设置y轴标签为"目标函数值 - 最小值"rho = ((kappa-1)/(kappa+1))^2; % 计算最速下降法的理论收敛率fprintf('rho_{SD} convergence rate <= %g (from kappa = %g)\n', rho, kappa); % 打印理论收敛率和条件数semilogy(1:numel(fs), (fs(1)-fmin) * rho.^(0:1:numel(fs)-1), 'r--', 'Linewidth', 2); % 绘制理论收敛曲线,红色虚线,线宽2grid on % 显示网格hold off % 释放图形保持
subplot(2,2,3); % 创建2×2子图的第3个子图semilogy(norm_gs, 'b-', 'Linewidth', 2); % 绘制梯度范数的半对数图,蓝色实线,线宽2xlabel('Iteration'); % 设置x轴标签为"迭代次数"ylabel('Norm of gradient'); % 设置y轴标签为"梯度范数"grid on % 显示网格
subplot(2,2,4); % 创建2×2子图的第4个子图semilogy(xdists, 'b-', 'Linewidth', 2); % 绘制到最优点距离的半对数图,蓝色实线,线宽2hold on % 保持当前图形xlabel('Iteration'); % 设置x轴标签为"迭代次数"ylabel('||x-x*||'); % 设置y轴标签为"到最优点的距离"if exist('a') % 如果变量a存在 xs_rate = zeros(numel(xdists),1); % 初始化理论距离收敛率向量 xs_rate(1) = xdists(1); % 设置初始距离 for i=2:numel(fs) % 对每个后续迭代 xs_rate(i) = (a-1)/(a+1) * xs_rate(i-1); % 计算理论距离收敛率 end semilogy(xs_rate, 'r--', 'Linewidth', 2); % 绘制理论距离收敛曲线,红色虚线,线宽2endgrid on % 显示网格hold off % 释放图形保持
二、Rosenbrock_function.m
功能简介:
实现了著名的 Rosenbrock 函数及其梯度和 Hessian 的计算。Rosenbrock 函数常用于测试优化算法的性能。
函数接口:
[f, g, H] = Rosenbrock_function(x)
x
:输入变量(二维向量)f
:函数值g
:梯度H
:Hessian 矩阵
函数形式:
function varargout = Rosenbrock_function(x) % 定义Rosenbrock函数,输入x为变量向量,varargout为可变输出参数 % Rosenbrock test function % Rosenbrock测试函数 % An interesting start point is x = [-1; 0.8] % 一个有趣的起始点是x = [-1; 0.8] % Unique local/global minimum is f=0 at [1;1] % 唯一的局部/全局最小值点是[1;1]处的f=0 % Lindon Roberts, 2019 % 作者:Lindon Roberts,2019年
% Call test functions as: % 调用测试函数的方式: % f = rosenbrock(x); % function value only % 仅获取函数值 % [f, g] = rosenbrock(x); % function value and gradient % 获取函数值和梯度 % [f, g, H] = rosenbrock(x); % function value, gradient and Hessian % 获取函数值、梯度和Hessian矩阵
if nargout > 3 % 如果输出参数个数大于3 error('Invalid number of output arguments'); % 抛出错误:输出参数个数无效 end
% Function value % 计算函数值 a = 10; % 设置参数a为10 f = a*(x(2)-x(1).^2).^2 + (x(1)-1).^2; % 计算Rosenbrock函数值:a*(x2-x1^2)^2 + (x1-1)^2 varargout{1} = f; % 将函数值存储为第一个输出参数
if nargout > 1 % 如果需要输出梯度 % Gradient % 计算梯度 g = [2*(x(1)-1)-4*a*x(1).*(x(2)-x(1).^2); 2*a*(-x(1).^2 + x(2))]; % 计算梯度向量,包含对x1和x2的偏导数 varargout{2} = g; % 将梯度存储为第二个输出参数 end
if nargout > 2 % 如果需要输出Hessian矩阵 % Hessian % 计算Hessian矩阵 H = [2 + 12*a*x(1).^2 - 4*a*x(2), -4*a*x(1); -4*a*x(1), 2*a]; % 计算2×2的Hessian矩阵(二阶偏导数矩阵) varargout{3} = H; % 将Hessian矩阵存储为第三个输出参数 endend
三、Scaled_quadratic_function.m
功能简介:
实现了一个带缩放参数的二次型函数及其梯度和 Hessian 的计算。可用于分析不同条件数下最速下降法的表现。
函数接口:
[f, g, H] = Scaled_quadratic_function(x, a)
x
:输入变量(二维向量)a
:缩放参数(决定二次型的条件数)f
:函数值g
:梯度H
:Hessian 矩阵
函数形式:
function varargout = Scaled_quadratic_function(x,a) % 定义缩放二次函数,输入x为变量向量,a为缩放参数 % Scaled quadratic, parametrised by a > 0 % 缩放二次函数,由参数a > 0控制 % Large a -> poorly scaled % 较大的a值会导致函数缩放不良 % An interesting start point is x = [1; a] % 一个有趣的起始点是x = [1; a] % Unique local/global minimum is f=0 at [0;0] % 唯一的局部/全局最小值点是[0;0]处的f=0 % Lindon Roberts, 2019 % 作者:Lindon Roberts,2019年
% Call test functions as: % 调用测试函数的方式: % a = 10; % 设置参数a为10 % objective = @(x)scaled_quadratic(x,a); % 创建目标函数句柄 % f = objective(x); % function value only % 仅获取函数值 % [f, g] = objective(x); % function value and gradient % 获取函数值和梯度 % [f, g, H] = objective(x); % function value, gradient and Hessian % 获取函数值、梯度和Hessian矩阵
if a <= 0 % 如果参数a小于等于0 error('Parameter a must be strictly positive'); % 抛出错误:参数a必须严格为正数 end
if nargout > 3 % 如果输出参数个数大于3 error('Invalid number of output arguments'); % 抛出错误:输出参数个数无效 end
% Function value % 计算函数值 f = (a*x(1).^2 + x(2).^2) / 2; % 计算缩放二次函数值:(a*x1^2 + x2^2) / 2 varargout{1} = f; % 将函数值存储为第一个输出参数
if nargout > 1 % 如果需要输出梯度 % Gradient % 计算梯度 g = [a*x(1); x(2)]; % 计算梯度向量:[a*x1; x2] varargout{2} = g; % 将梯度存储为第二个输出参数 end
if nargout > 2 % 如果需要输出Hessian矩阵 % Hessian % 计算Hessian矩阵 H = [a, 0; 0, 1]; % 计算2×2的Hessian矩阵:对角矩阵[a, 0; 0, 1] varargout{3} = H; % 将Hessian矩阵存储为第三个输出参数 endend