一、前言
最速下降法 ,又称为梯度法,是一种无约束求解多元函数极小值的方法。最速下降法的起源可以追溯到19世纪,最早由数学家Cauchy在1847年提出。随着计算机技术的发展,最速下降法在20世纪50年代逐渐应用于各种优化问题,尤其是在机器学习领域得到了广泛的采用。
最速下降法的核心思想是利用函数的梯度信息来指导搜索方向。在当前点计算函数的梯度,确定下降方向,即当前点的负梯度方向。
二、定义
基于梯度信息来寻找函数的局部最小值。它从当前点出发,取函数在该点下降最快的方向(即负梯度方向)作为搜索方向,然后沿此方向进行一维搜索,找到使函数值最小的步长,从而更新当前点。
- 选取初始点x(0),并给定终止误差ε>0。
- 计算当前点的梯度∇f(x),若∇f(x)≤ε,则停止迭代,输出当前点作为近似最优解;否则,进行下一步。
- 取搜索方向d(k)=-∇f(x(k)).
- 进行一维搜索,求步长αk,这里提供公式.使得f(x(k)+αkp(k))=minf(x(k)+αp(k))
- 更新当前点x(k+1)=x(k)+αkd(k)并令k=k+1,转步骤2。
三、代码实现
% 梯度下降法求解二次函数最小值
f = @(x1,x2) 3/2 * x1.^2 + 1/2*x2.^2 - x1*x2 - 2*x1;
% 初始化参数
x0 = -2; % 初始x值
y0 = 4; % 初始y值
alpha = 1; % 初始步长(学习率)
tol = 1e-3; % 容差,用于判断梯度是否足够小
max_iter = 1000; % 最大迭代次数
% 初始化变量并预分配内存(如果需要存储每次迭代的结果)
x = zeros(1, max_iter);
y = zeros(1, max_iter);
f_val = zeros(1, max_iter);
iter = 0;
x(iter+1) = x0;
y(iter+1) = y0;
f_val(iter+1) = f(x0,y0);
hesse = [3,-1;-1,1];
% 梯度计算函数(向量化形式,尽管在这个例子中向量化并没有带来性能提升)
grad_f = @(x_vec) [3*x_vec(1)-x_vec(2)-2; x_vec(2)-x_vec(1)];
% 迭代过程
while iter < max_iter-1
% 计算当前点的梯度(使用向量化输入,但输出仍然是分开的x和y梯度)
grad = grad_f([x(iter+1), y(iter+1)]);
% 检查梯度是否足够小,以判断是否达到停止条件
if norm(grad) < tol
fprintf('达到停止条件,迭代结束。\n');
break;
end
alpha = (grad.' * grad) / (grad.' * hesse * grad);
% 更新x和y的值
x(iter+2) = x(iter+1) - alpha * grad(1);
y(iter+2) = y(iter+1) - alpha * grad(2);
% 计算新的函数值(可选,用于监控收敛过程)
f_val(iter+2) = f(x(iter+2),y(iter+2));
% 增加迭代次数
iter = iter + 1;
end
% 输出最终结果
if iter == max_iter-1
fprintf('达到最大迭代次数,迭代结束。\n');
end
fprintf('最终结果: x = %.6f, y = %.6f, f(x, y) = %.6f\n', x(iter+1), y(iter+1), f_val(iter+1));
% 如果需要,可以绘制收敛过程
figure;
plot(1:iter+1, f_val(1:iter+1), '-o');
xlabel('迭代次数');
ylabel('f(x, y)');
title('梯度下降法收敛过程');
需要输入函数表达式和梯度表达式,然后 设置初始点,步长默认为1,如果想要减少迭代次数可以设置的小一点。
这里基于课本习题第一题为例,用最速下降法极小化,默认步长为1,通过线性搜索法算出最佳步长,这里的公式为
alpha = (grad.' * grad) / (grad.' * hesse * grad);
hesse为海色(Hesse)矩阵,grad为梯度,可以直接算出下次迭代的步长。
结果:
以及曲线图
然后在右侧查看每次迭代的函数值
这里迭代6次就结束了。
四、总结
通过之后的学习,了解到最速下降法效率较低,收敛慢等问题,下一篇将介绍牛顿法达到一步迭代出结果。
如有问题还请评论区指正,感谢观看!