使用梯度下降法求解无约束最优化问题
一、梯度下降法基本原理
1. 核心思想
梯度下降法是一种一阶迭代优化算法,通过沿目标函数负梯度方向逐步调整变量,逼近函数极小值点。对于无约束问题
$x_{k+1}=xk−αk∇f(x_k)$
其中:
是目标函数在 处的梯度(一阶导数); 是步长(学习率),控制迭代步长; - 负梯度方向
是函数值下降最快的方向(局部性质)。
2. 数学基础
-
梯度定义:对于多元函数
,梯度为: -
收敛性:若目标函数
是凸函数且 Lipschitz 连续可微,梯度下降法能以线性速度收敛到全局最优解;对非凸函数,可能收敛到局部最优解。
3. 算法分类
| 类型 | 特点 | 适用场景 |
|---|---|---|
| 批量梯度下降 | 用全部样本计算梯度,精度高但速度慢 | 小数据集、高精度需求 |
| 随机梯度下降 | 用单个样本计算梯度,速度快但波动大 | 大数据集、在线学习 |
| 小批量梯度下降 | 用部分样本(mini-batch)计算梯度,平衡速度与精度 | 深度学习、中等规模数据 |
二、梯度下降法实现步骤(MATLAB)
1. 算法流程
- 初始化:选择初始点
、学习率 、最大迭代次数 、收敛容差 ; - 迭代更新: 计算当前梯度
; 检查收敛条件( ); 更新变量: ; - 终止:达到最大迭代次数或满足收敛条件,输出
作为近似最优解。
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. 学习率(步长)α的选择
- 固定学习率:需手动调试(如
),过大易震荡,过小收敛慢; - 衰减学习率:随迭代次数减小步长(如
); - 自适应学习率: 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);
-
数值梯度:用有限差分近似(适用于复杂函数):
其中
为小量(如 ), 是第 个单位向量。
数值梯度实现
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=[2x1+2x2−44x2+2x1−2]
最优解:通过令梯度为零解得
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=[\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) |
动量法改进(加速收敛)
引入动量项累积历史梯度方向,减少震荡:
其中
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. 停止准则
- 梯度范数:
(常用 ϵ=1e−6); - 函数值变化:
; - 迭代次数:设置最大迭代次数避免无限循环。
3. 与其他算法对比
| 算法 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 梯度下降 | 简单、内存需求低 | 收敛慢、易陷局部最优 | 大规模数据、非凸优化 |
| 牛顿法 | 二次收敛速度 | 需计算Hessian矩阵(O(n²)存储) | 中小规模凸优化 |
| 拟牛顿法 | 超线性收敛、无需Hessian | 实现复杂、内存需求较高 | 中等规模优化 |
参考代码 使用梯度下降法求无约束问题最优解 www.youwenfan.com/contentcsn/83675.html
七、总结
梯度下降法是求解无约束最优化问题的基础算法,其核心是沿负梯度方向迭代更新。在MATLAB中实现时需注意:
- 准确计算梯度(解析梯度优先,数值梯度备用);
- 合理选择学习率(固定/自适应/回溯线搜索);
- 设置收敛条件(梯度范数、函数值变化);
- 针对非凸函数或病态问题,可引入动量法、预处理等技术改进。
通过实例验证(如二次函数、Rosenbrock函数),梯度下降法能有效逼近最优解,是机器学习(如线性回归、神经网络训练)和科学计算中的核心工具。