news 2026/11/3 10:58:51

AI 学习第 3 课:手推线性回归与梯度下降,numpy 跑出 loss 曲线

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
AI 学习第 3 课:手推线性回归与梯度下降,numpy 跑出 loss 曲线

第 2 课我们把数据洗干净、切好了训练集和验证集。这一课在这份数据上做第一件"像机器学习"的事:拟合一条(这里是超平面)y = Xw + b。全程不装 PyTorch、不装 sklearn,只用 numpy 把梯度算出来、把 loss 曲线跑出来,再和闭式解对一遍,看手写的代码差多少。

为什么在框架已经很成熟的时候还要手推?因为求解器的收敛行为是长期主题——scikit-learn 官方站显示 1.9.1 在 2026 年 9 月发布、1.10 开发版的 changelog 一直更新到 2026 年 10 月,改动清单里仍然有线性模型求解器的线搜索优化和 Lasso/ElasticNet 路径计算提速。不懂梯度在干什么,这些调参项就只是玄学。

环境准备

只需要 numpy。本机版本:Python 3.13.14 / Windows 10 / numpy 2.5.1。

python -c "import numpy, sys, platform; print(sys.version.split()[0], platform.platform(), numpy.__version__)" pip install "numpy>=2.5"

先造一批「不好解」的数据

用随机数造数据,但故意留一手:让第二列跟第一列高度相关(相关系数接近 1)。这是现实数据里最常见的情况,也是后面所有"奇怪现象"的根源。

import numpy as np rng = np.random.default_rng(42) n = 500 x1 = rng.normal(size=n) x2 = x1 * 0.98 + rng.normal(scale=0.05, size=n) # 故意跟 x1 高度相关 x3 = rng.normal(size=n) X = np.column_stack([x1, x2, x3]) w_true = np.array([3.5, -2.0, 0.8]) b_true = 1.2 y = X @ w_true + b_true + rng.normal(scale=0.5, size=n) Xb = np.hstack([X, np.ones((n, 1))]) # 补一列 1,把截距并进权重向量 print("cond =", round(float(np.linalg.cond(Xb)), 2), Xb.shape)

输出:

cond = 37.07 (500, 4)

条件数 37 不算大,但已经足够让"不同参数、同样 loss"的现象出现了。

闭式解:lstsq 和正规方程对一遍

先算标准答案。两条路:np.linalg.lstsq(奇异值分解,数值稳)和正规方程w = (XᵀX)⁻¹Xᵀy(推导简单,但要先求逆)。

theta_star, residuals, rank, sv = np.linalg.lstsq(Xb, y, rcond=None) print("lstsq :", np.round(theta_star, 4), "residuals:", residuals, "rank:", rank) theta_ne = np.linalg.solve(Xb.T @ Xb, Xb.T @ y) print("normal:", np.round(theta_ne, 4)) print("max |diff| =", float(np.max(np.abs(theta_star - theta_ne))))

输出:

lstsq : [ 4.1367 -2.6754 0.7915 1.1187] residuals: [124.53111447] rank: 4 normal: [ 4.1367 -2.6754 0.7915 1.1187] max |diff| = 5.617728504603292e-13

两条路的差在 1e-13 量级,说明这份数据下正规方程完全可用。注意rcond=None要显式写上:NumPy 2.0 之前这个参数的默认值是-1并会发 FutureWarning,2.0 起默认值改成"机器精度 × max(M, N)",老教程里的写法在新版本上语义已经变了。

另外看一眼权重:真值是[3.5, -2.0, 0.8],闭式解给出[4.14, -2.68, 0.79]。前两维偏得挺多,这不是算错了,是 x1 和 x2 高度相关导致的参数不可识别——把 3.5·x1 − 2.0·x2 稍微改写成别的系数组合,对 y 的预测几乎一样。

手写全批量梯度下降

均方误差 loss = ‖Xw − y‖²/n,对 w 求导得 grad = 2·Xᵀ(Xw − y)/n。整个训练循环就这么三行。

def loss_fn(th): r = Xb @ th - y return float((r @ r) / n) print("lstsq loss:", round(loss_fn(theta_star), 6)) th = np.zeros(4) lr = 0.1 for i in range(1, 301): grad = (Xb.T @ (Xb @ th - y)) * 2.0 / n th -= lr * grad if i in (1, 2, 5, 10, 20, 50, 100, 200, 300): print(f"iter {i:4d} loss {loss_fn(th):.6f}") print("GD theta:", np.round(th, 4)) print("gap to lstsq:", round(float(np.max(np.abs(th - theta_star))), 4))

实测输出:

lstsq loss: 0.249062 iter 1 loss 2.369513 iter 2 loss 1.399652 iter 5 loss 0.498003 iter 10 loss 0.300016 iter 20 loss 0.279378 iter 50 loss 0.278677 iter 100 loss 0.277907 iter 200 loss 0.276426 iter 300 loss 0.275021 GD theta: [1.0282 0.4931 0.7976 1.1258] gap to lstsq: 3.1685

loss 曲线是对的:2.37 → 0.50 → 0.28 → 0.275,前 10 轮掉得最快,之后是一条很长的尾巴。但权重差得离谱——梯度下降收敛到[1.03, 0.49, 0.80, 1.13],和闭式解的[4.14, -2.68, ...]差了 3.17,而两边的 loss 只差 0.026。原因就是前面那条:x1 与 x2 相关,参数在这个方向上可以随便滑,梯度下降停在哪个点取决于起点和学习率,loss 却几乎不变。

换成 mini-batch

全批量每次都算 500 条样本。改成每 32 条更新一次,epoch 内先打乱顺序:

th_mb = np.zeros(4) for epoch in range(1, 31): perm = rng.permutation(n) for s in range(0, n, 32): idx = perm[s:s + 32] grad = (Xb[idx].T @ (Xb[idx] @ th_mb - y[idx])) * 2.0 / len(idx) th_mb -= 0.1 * grad if epoch in (1, 2, 5, 10, 30): print(f"epoch {epoch:3d} loss {loss_fn(th_mb):.6f}") print("MB theta:", np.round(th_mb, 4))

输出:

epoch 1 loss 0.290387 epoch 2 loss 0.283768 epoch 5 loss 0.281025 epoch 10 loss 0.278352 epoch 30 loss 0.274106 MB theta: [1.1607 0.3286 0.8248 1.1219]

一个 epoch 就到 0.29,比全批量 300 轮的 0.275 差一点点,但更新次数只有它的 1/10 左右。这就是 mini-batch 的全部秘密:单步质量差,步数多,总账更划算。

三个真实的坑

学习率太大,直接发散。把 lr 从 0.1 换成 2.0,同一份数据:

iter 1 loss 131.1284 iter 2 loss 5804.7643 iter 3 loss 279925.2999 iter 4 loss 13722612.0304 iter 20 loss 1.6185783571901943e+34

20 轮之后权重已经是 -6.3e16 量级。判断标准很简单:如果前几轮 loss 不降反升,直接把 lr 除以 10 重来,不要等它自己"跳出来"。

学习率太小,看着像收敛其实没到。lr = 0.001 时,3000 轮 loss 是 0.279001,还不如 lr = 0.1 跑 50 轮的 0.278677。

特征量纲差太多,loss 会炸。把第一列乘 1000(模拟"金额"和"年龄"混在一起),条件数从 37 跳到 18867,同样的 lr = 0.1:

iter 1 loss 3.8088696757870656e+17 iter 2 loss 1.2889668030118792e+28 iter 3 loss 4.362016977972201e+38 iter 19 loss 1.2906760751510606e+207

再跑下去 numpy 会抛RuntimeWarning: overflow encountered in matmul,接着是invalid value encountered in matmul,loss 变成 nan。修法只有一句话:训练前先做标准化(X - X.mean(0)) / X.std(0),别指望调学习率救回来。

看 loss 还是看参数

这一课最容易产生误解的地方:loss 已经降到 0.275 了,参数却和真值、和闭式解都不一样。判断训练是否成功,应该看验证集上的指标,而不是逐个权重去对答案。

pred = Xb @ th ss_res = float(((y - pred) ** 2).sum()) ss_tot = float(((y - y.mean()) ** 2).sum()) print("R2 =", round(1 - ss_res / ss_tot, 4), " RMSE =", round((ss_res / n) ** 0.5, 4)) print("lstsq R2 =", round(1 - float(((y - Xb @ theta_star) ** 2).sum()) / ss_tot, 4))

输出:

R2 = 0.913 RMSE = 0.5244 lstsq R2 = 0.9213

两者 R² 差 0.008,参数却差 3.17。噪声标准差我设的是 0.5,RMSE 0.5244 基本就贴着这个下限——说明模型已经把能学的都学到了,剩下的就是噪声。特征共线时想要"正确的权重",得靠第 4 课要讲的特征处理,或者加正则化,硬调梯度下降是调不出来的。

小结

闭式解给的是标准答案,手写梯度下降给的是同一条路的不同走法,两边对不上时先查特征共线和量纲,再怀疑代码。把上面三段代码存成一个脚本跑一遍,改改 lr 和 batch size 看 loss 曲线怎么变,比读十遍公式管用。下一课在这个基础上加 L2 正则、讲清楚训练集和验证集上的 loss 什么时候该开始分岔。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/11/3 10:58:44

DeepSeek-R1实战指南:零基础搞定办公、数据与代码三大痛点

简介:本资源是清华大学新闻与传播学院新媒体研究中心元宇宙文化实验室出品的104页深度学习实践指南,面向AI初学者、NLP开发者及大模型应用从业者,系统解决DeepSeek模型认知、场景落地与人机协同能力构建三大核心问题。内容覆盖DeepSeek公司定…

作者头像 李华
网站建设 2026/11/3 10:58:01

SolidWorks二次开发:VBA宏改造与特征装配自动化

简介:这份面向SolidWorks二次开发学习者与工程师的教程文档,围绕API、VBA与宏自动化展开,适合希望简化建模流程、提升设计效率并建立二次开发基础的初、中级读者。压缩包内共1个doc文件,大小约276KB,以系列教程形式串联…

作者头像 李华
网站建设 2026/11/3 10:56:01

神经网络画图PPT模版:从图形语义到结构复用的设计指南

简介:这份神经网络画图PPT模版面向机器学习学习者、论文撰写者与高校教师,用于在学术报告、课堂教学和论文配图中直观呈现神经网络结构与工作原理,解决手绘示意图耗时、结构不统一的问题。压缩包内共1个pptx文件,约28.87MB&#x…

作者头像 李华
网站建设 2026/11/3 10:55:31

WMI详解:Windows系统管理的统一接口与实战指南

简介:本资源是微软官方发布的Windows Management Instrumentation(WMI)英文开发文档PDF合集,面向Windows系统开发人员、IT运维工程师及自动化脚本编写者,用于深入理解WMI架构、类模型与远程管理实践。文档覆盖WMI核心概…

作者头像 李华
网站建设 2026/11/3 10:55:25

IEC 61508-1 功能安全标准:生命周期、SIL 与证据链机制解析

简介:IEC 61508-1:2010 第 1 部分《一般要求》高清可复制版,面向从事功能安全设计、评估与认证的工程师、系统架构师及安全管理人员,也适合需要理解 E/E/PE 安全相关系统通用框架的研发与测试人员。标准围绕风险评估、安全生命周期管理、系统…

作者头像 李华
网站建设 2026/11/3 10:55:03

用 AI 能做哪些视频?按想交付的作品选做法

本文回答有剧情短片、连载短剧与产品广告分别怎样起步,用作品愿望到开始动作的分流表说明三条制作路径,并区分动画画风、人物讲解和真实现场的不同需求。 用 AI 能做哪些视频?有剧情的单条短片、连载短剧、产品外观广告,都有对应的…

作者头像 李华