线性最小二乘拟合通过梯度下降法实现参数优化,目标是寻找最优的斜率与截距,使得拟合直线 y = ax + b 尽可能贴近所有数据点 (xi, yi)。
1. 损失函数定义(均方误差)
为评估拟合效果,采用均方误差作为损失函数:
L(a, b) = (1 / 2n) ∑i=1n (a xi + b yi)
该值越小,表示模型拟合程度越高。其中引入因子 1/2 是为了在后续求导过程中简化表达式,不影响优化方向。
2. 梯度计算
梯度反映损失函数对各参数的变化率,用于指导参数更新方向:
- 对斜率 a 的偏导数:
L/a = (1/n) ∑i=1n (a xi + b yi) xi - 对截距 b 的偏导数:
L/b = (1/n) ∑i=1n (a xi + b yi)
梯度指向误差上升最快的方向,因此参数应沿其反方向调整以降低损失。
3. 参数迭代更新(梯度下降)
每一轮迭代中,按如下规则更新参数:
a ← a η (L/a)
b ← b η (L/b)
其中 η > 0 表示学习率(例如 0.02),控制每次更新的步长大小,直接影响收敛速度与稳定性。
4. 迭代直至收敛
重复执行以下流程直到达到最大迭代次数或损失趋于稳定:
- 计算当前预测值:i = a xi + b
- 计算梯度
- 更新斜率 a 和截距 b
随着迭代进行,损失函数 L(a, b) 逐步减小,拟合直线逐渐逼近最优解。
关键要点总结
- 梯度下降是一种迭代优化方法,不依赖于解析解,适用于更广泛的问题场景;
- 除以样本数 n 可得到平均误差,使结果不受数据量影响;
- 即使数据严格位于一条直线上,仍需多次迭代才能接近真实参数值;
- 学习率 η 需谨慎选择:过大可能导致震荡甚至发散,过小则收敛缓慢。
Matlab 实现代码
%% 梯度下降动画:最小二乘直线拟合(修复起点显示问题)
clear; close all; clc;
% 生成带噪声的线性数据
rng(0); % 可复现
n = 30;
x = linspace(0, 10, n)';
y_true = -2.5 * x + 1.0; % 真实直线
y = y_true + randn(n,1) * 1; % 添加高斯噪声
% 初始化参数
a = 1; % 初始斜率
b = -20; % 初始截距
lr = 0.02; % 学习率(可调)
max_iter = 500;
% 存储历史用于绘制轨迹
a_hist = zeros(max_iter+1, 1);
b_hist = zeros(max_iter+1, 1);
loss_hist = zeros(max_iter+1, 1);
a_hist(1) = a;
b_hist(1) = b;
loss_hist(1) = sum((a*x + b - y).^2) / (2*n);
% 创建图形窗口
figure('Position', [100, 100, 1000, 400]);
% === 左图:数据与拟合直线 ===
subplot(1,2,1); hold on; box on;
scatter(x, y, 'filled', 'MarkerFaceColor', [0.2 0.6 0.8]);
title('梯度下降拟合过程', 'FontSize', 12);
xlabel('x'); ylabel('y');
xlim([min(x)-1, max(x)+1]); ylim([min(y)-2, max(y)+2]);
h_line = plot(x, a*x + b, 'r-', 'LineWidth', 2);
h_text = text(0.05, 0.95, '', 'Units','normalized', 'FontSize',12,...
'VerticalAlignment','top', 'BackgroundColor',[1 1 1 0.7]);
% === 右图:参数空间轨迹(初始化坐标轴)===
subplot(1,2,2); hold on; box on;
title('参数更新轨迹 (a vs b)', 'FontSize', 12);
xlabel('斜率 a'); ylabel('截距 b');
% 在右图中标注初始点(使用红色大圆点突出显示起点)
subplot(1,2,2);
plot(a_hist(1), b_hist(1), 'ro', 'MarkerSize', 10, 'MarkerFaceColor', 'r');
drawnow;
pause(1.0); % 暂停1秒,便于观察初始状态
% === 更新左图:拟合直线与信息文本 ===
set(h_line, 'YData', a*x + b);
set(h_text, 'String', sprintf('Iter: %d\na=%.3f, b=%.3f\nLoss=%.3f', ...
0, a, b, loss_hist(1)));
% === 开始迭代优化过程 ===
for k = 1:max_iter
% 前向传播:计算当前预测值
y_pred = a * x + b;
% 计算损失函数对参数的梯度
da = sum((y_pred - y) .* x) / n; % ?L/?a
db = sum(y_pred - y) / n; % ?L/?b
% 使用梯度下降法更新参数
a = a - lr * da;
b = b - lr * db;
% 记录每一步的参数与损失值
a_hist(k+1) = a;
b_hist(k+1) = b;
loss_hist(k+1) = sum((a*x + b - y).^2) / (2*n);
% 实时更新左侧图像中的拟合直线和文字说明
set(h_line, 'YData', a*x + b);
set(h_text, 'String', sprintf('Iter: %d\na=%.3f, b=%.3f\nLoss=%.3f', ...
k, a, b, loss_hist(k+1)));
% 更新右侧参数轨迹图
subplot(1,2,2);
cla; % 清除当前坐标轴内容,避免图形叠加变粗
hold on; box on;
title('参数更新轨迹 (a vs b)', 'FontSize', 12);
xlabel('斜率 a'); ylabel('截距 b');
% 绘制从开始到当前迭代的完整参数路径
plot(a_hist(1:k+1), b_hist(1:k+1), 'go-', ...
'MarkerFaceColor', 'g', 'MarkerSize', 5);
% 重新绘制起点高亮标记(保持红色醒目)
plot(a_hist(1), b_hist(1), 'ro', 'MarkerSize', 10, 'MarkerFaceColor', 'r');
drawnow;
pause(0.05); % 控制动画播放速度
end
% 输出最终优化结果并与真实值对比
fprintf('最终结果: a = %.4f, b = %.4f (真实值: a=-2.5, b=1.0)\n', a, b);


雷达卡


京公网安备 11010802022788号







