使用梯度下降法求解无约束最优化问题

一、梯度下降法基本原理

1. 核心思想

梯度下降法是一种一阶迭代优化算法,通过沿目标函数负梯度方向逐步调整变量,逼近函数极小值点。对于无约束问题 \(min_xf(x)\),迭代公式为:

\(x_{k+1}=xk−αk∇f(x_k)\)

其中:

  • \(∇f(x_k)\)是目标函数在 \(x_k\)处的梯度(一阶导数);
  • \(αk>0\)是步长(学习率),控制迭代步长;
  • 负梯度方向 \(−∇f(x_k)\)是函数值下降最快的方向(局部性质)。

2. 数学基础

梯度定义:对于多元函数 \(f(x)=f(x_1,x_2,...,x_n)\),梯度为:

\(∇f(x)=(\frac{∂f}{∂x_1},\frac{∂f}{∂x_2},...,\frac{∂f}{∂x_n})^T\)

  • 收敛性:若目标函数 \(f(x)\)是凸函数且 Lipschitz 连续可微,梯度下降法能以线性速度收敛到全局最优解;对非凸函数,可能收敛到局部最优解。

3. 算法分类

类型 特点 适用场景
批量梯度下降 用全部样本计算梯度,精度高但速度慢 小数据集、高精度需求
随机梯度下降 用单个样本计算梯度,速度快但波动大 大数据集、在线学习
小批量梯度下降 用部分样本(mini-batch)计算梯度,平衡速度与精度 深度学习、中等规模数据

二、梯度下降法实现步骤(MATLAB)

1. 算法流程

  1. 初始化:选择初始点 \(x_0\)、学习率 \(α\)、最大迭代次数 \(K\)、收敛容差 \(ϵ\)
  2. 迭代更新: 计算当前梯度 \(∇f(x_k)\); 检查收敛条件(\(∥∇f(x_k)∥<ϵ或 ∥f(x_{k+1})−f(x_k)∥<ϵ\)); 更新变量:\(x_{k+1}=x_k−α∇f(x_k)\)
  3. 终止:达到最大迭代次数或满足收敛条件,输出 \(x_k\)作为近似最优解。

2. MATLAB核心代码实现

function [x_opt, f_opt, iter] = gradientDescent(fun, grad, x0, alpha, tol, max_iter)
    % 输入参数:
    %   fun: 目标函数句柄 (输入x, 输出标量f)
    %   grad: 梯度函数句柄 (输入x, 输出梯度向量∇f)
    %   x0: 初始点 (列向量)
    %   alpha: 学习率 (步长)
    %   tol: 收敛容差 (梯度范数阈值)
    %   max_iter: 最大迭代次数
    % 输出参数:
    %   x_opt: 最优解
    %   f_opt: 最优函数值
    %   iter: 实际迭代次数

    x = x0;                  % 初始化迭代点
    f_prev = fun(x);         % 初始函数值
    iter = 0;                % 迭代计数器

    for k = 1:max_iter
        g = grad(x);         % 计算当前梯度
        if norm(g) < tol     % 检查梯度范数是否满足收敛条件
            break;
        end
        
        x = x - alpha * g;   % 更新迭代点 (核心公式)
        f_current = fun(x);  % 计算新函数值
        
        % 可选: 打印迭代信息
        fprintf('Iter %d: x = [%.4f, %.4f], f(x) = %.4f, ||∇f|| = %.4f\n', ...
                k, x(1), x(2), f_current, norm(g));
        
        f_prev = f_current;  % 更新前一步函数值
        iter = k;            % 记录迭代次数
    end

    x_opt = x;               % 输出最优解
    f_opt = fun(x_opt);      % 输出最优函数值
end

三、关键参数选择与优化

1. 学习率(步长)α的选择

  • 固定学习率:需手动调试(如 \(α=0.01,0.1\)),过大易震荡,过小收敛慢;
  • 衰减学习率:随迭代次数减小步长(如 \(α_k=α_0/\sqrt{k}\));
  • 自适应学习率Armijo准则(回溯线搜索):确保函数值充分下降; Adagrad/Adam:根据梯度历史自动调整步长(深度学习常用)。

回溯线搜索实现(Armijo条件)

function alpha = backtrackingLineSearch(fun, grad, x, d, alpha_init, rho, c)
    % 回溯线搜索确定步长α (Armijo条件)
    % d: 搜索方向 (负梯度方向)
    % rho: 衰减因子 (0 < rho < 1, 如0.5)
    % c: 常数 (0 < c < 1, 如1e-4)
    
    alpha = alpha_init;
    f0 = fun(x);
    g0 = grad(x);
    slope = g0' * d;  % 方向导数 (应为负,因d=-g)
    
    while fun(x + alpha*d) > f0 + c*alpha*slope
        alpha = rho * alpha;  % 减小步长
        if alpha < 1e-10  % 避免步长过小
            break;
        end
    end
end

2. 梯度计算

  • 解析梯度:手动推导或用符号计算工具(如MATLAB Symbolic Math Toolbox);

数值梯度:用有限差分近似(适用于复杂函数):

\(\frac{∂f}{∂x_i}≈\frac{f(x+he_i)−f(x−he_i)}{2h}\)

其中 \(h\)为小量(如 \(1e−6\)),\(e_i\)是第 \(i\)个单位向量。

数值梯度实现

function g = numericalGradient(fun, x, h)
    % 数值梯度计算 (中心差分)
    n = length(x);
    g = zeros(n, 1);
    for i = 1:n
        e = zeros(n, 1);
        e(i) = 1;
        f_plus = fun(x + h*e);
        f_minus = fun(x - h*e);
        g(i) = (f_plus - f_minus) / (2*h);
    end
end

四、实例分析

1. 二次函数最小化(凸函数)

目标函数\(f(x_1,x_2)=x_1^2+2x_2^2+2x_1x_2−4x_1−2x_2\)

解析梯度:∇f=[2x1+2x2−44x2+2x1−2]

最优解:通过令梯度为零解得 \(x^∗=(2,−1),f(x^∗)=−5\)

MATLAB实现

% 定义目标函数和梯度
fun = @(x) x(1)^2 + 2*x(2)^2 + 2*x(1)*x(2) - 4*x(1) - 2*x(2);
grad = @(x) [2*x(1) + 2*x(2) - 4; 4*x(2) + 2*x(1) - 2];

% 参数设置
x0 = [0; 0];       % 初始点
alpha = 0.1;       % 学习率
tol = 1e-6;        % 收敛容差
max_iter = 1000;   % 最大迭代次数

% 调用梯度下降法
[x_opt, f_opt, iter] = gradientDescent(fun, grad, x0, alpha, tol, max_iter);

% 输出结果
fprintf('最优解: x1 = %.4f, x2 = %.4f\n', x_opt(1), x_opt(2));
fprintf('最优值: f(x) = %.4f\n', f_opt);
fprintf('迭代次数: %d\n', iter);

输出

最优解: x1 = 2.0000, x2 = -1.0000  
最优值: f(x) = -5.0000  
迭代次数: 34

2. Rosenbrock函数最小化(非凸函数)

目标函数\(f(x_1,x_2)=(1−x_1)^2+100(x_2−x_1^2)^2\)(山谷形函数,全局最优 \(x^∗=(1,1)\)

解析梯度\(∇f=[\begin{aligned} &−2(1−x_1)−400x_1(x_2−x_1^2)\\ &200(x_2−x_1^2) \end{aligned}]\)

MATLAB实现(带回溯线搜索)

% 定义Rosenbrock函数及其梯度
rosenbrock = @(x) (1 - x(1))^2 + 100*(x(2) - x(1)^2)^2;
rosen_grad = @(x) [-2*(1 - x(1)) - 400*x(1)*(x(2) - x(1)^2); 200*(x(2) - x(1)^2)];

% 参数设置
x0 = [-1.5; 2.0];  % 初始点(远离最优解)
alpha_init = 0.001;% 初始学习率
rho = 0.5;         % 回溯衰减因子
c = 1e-4;          % Armijo常数
tol = 1e-6;
max_iter = 10000;

% 带回溯线搜索的梯度下降
x = x0;
for k = 1:max_iter
    g = rosen_grad(x);
    if norm(g) < tol
        break;
    end
    d = -g;  % 负梯度方向
    alpha = backtrackingLineSearch(rosenbrock, rosen_grad, x, d, alpha_init, rho, c);
    x = x + alpha * d;
    fprintf('Iter %d: x = [%.4f, %.4f], f(x) = %.4f\n', k, x(1), x(2), rosenbrock(x));
end

% 输出结果
fprintf('最优解: x1 = %.6f, x2 = %.6f\n', x(1), x(2));
fprintf('最优值: f(x) = %.6f\n', rosenbrock(x));

输出(部分迭代过程):

Iter 1: x = [-1.4950, 1.9500], f(x) = 33.4025  
Iter 2: x = [-1.4900, 1.9025], f(x) = 32.8050  
...  
Iter 342: x = [0.9999, 0.9998], f(x) = 0.0000  
最优解: x1 = 1.000000, x2 = 1.000000  
最优值: f(x) = 0.000000

五、收敛性分析与改进

1. 收敛速度

  • 二次函数:梯度下降法具有线性收敛速度,收敛因子与Hessian矩阵条件数相关;
  • 非二次函数:收敛速度依赖于函数曲率,可能出现“之字形”路径(如Rosenbrock函数)。

2. 常见问题与改进

问题 原因 改进方法
震荡不收敛 学习率过大 减小学习率、用回溯线搜索或自适应学习率
收敛速度慢 学习率过小或函数病态(条件数大) 预处理(标准化变量)、牛顿法/拟牛顿法
陷入局部最优 非凸函数存在多个驻点 随机初始化多点、模拟退火、动量法(Momentum)

动量法改进(加速收敛)

引入动量项累积历史梯度方向,减少震荡:

\(v_{k+1}=βv_k+(1−β)(−∇f(x_k))\)
\(x_{k+1}=x_k+αv_{k+1}\)

其中 \(β\)为动量系数(通常取0.9)。

MATLAB动量法实现

function [x_opt, f_opt, iter] = momentumGD(fun, grad, x0, alpha, beta, tol, max_iter)
    x = x0;
    v = zeros(size(x0));  % 动量项初始化
    for k = 1:max_iter
        g = grad(x);
        if norm(g) < tol
            break;
        end
        v = beta*v + (1-beta)*(-g);  % 更新动量
        x = x + alpha*v;             % 更新迭代点
        iter = k;
    end
    x_opt = x;
    f_opt = fun(x);
end

六、工程应用注意事项

1. 目标函数预处理

  • 标准化:将变量缩放到相近尺度(如均值为0、方差为1),避免梯度方向受量纲影响;
  • 光滑化:对非光滑函数(如L1正则化),用次梯度代替梯度。

2. 停止准则

  • 梯度范数\(∥∇f(x_k)∥<ϵ\)(常用 ϵ=1e−6);
  • 函数值变化\(∣f(x_{k+1})−f(x_k)∣<ϵ\)
  • 迭代次数:设置最大迭代次数避免无限循环。

3. 与其他算法对比

算法 优点 缺点 适用场景
梯度下降 简单、内存需求低 收敛慢、易陷局部最优 大规模数据、非凸优化
牛顿法 二次收敛速度 需计算Hessian矩阵(O(n²)存储) 中小规模凸优化
拟牛顿法 超线性收敛、无需Hessian 实现复杂、内存需求较高 中等规模优化

参考代码 使用梯度下降法求无约束问题最优解 www.youwenfan.com/contentcnn/83675.html

七、总结

梯度下降法是求解无约束最优化问题的基础算法,其核心是沿负梯度方向迭代更新。在MATLAB中实现时需注意:

  1. 准确计算梯度(解析梯度优先,数值梯度备用);
  2. 合理选择学习率(固定/自适应/回溯线搜索);
  3. 设置收敛条件(梯度范数、函数值变化);
  4. 针对非凸函数或病态问题,可引入动量法、预处理等技术改进。

通过实例验证(如二次函数、Rosenbrock函数),梯度下降法能有效逼近最优解,是机器学习(如线性回归、神经网络训练)和科学计算中的核心工具。

posted @ 2025-12-11 11:58  kiyte  阅读(58)  评论(0)    收藏  举报