现在位置: 首页 > AI 数学基础 > 正文

手写梯度下降拟合一条直线

不用 sklearn,用梯度下降从零拟合 \(y = wx + b\),一步步观察损失如何下降。

学完本案例你将理解:不需要闭式解,只要会求梯度,参数就能自动收敛到最优值。


生活引入

投篮练习——每次调整一点角度

你站在三分线外投篮。第一次偏左了——下次往右调一点。第二次偏右了——再往左调一点。每次投完,你看一眼偏差,朝减小偏差的方向调整姿势。

机器学习训练完全一样:每次算完预测值,看一眼和真实值的差距(损失),然后朝减小差距的方向调整参数(梯度下降)。重复几百次,姿势就定型了。


直观理解

我们的目标是找到一条直线 \(y = wx + b\),让它尽可能穿过所有数据点。\(w\) 是斜率,\(b\) 是截距,损失 = 所有点到直线的竖直距离平方的平均值(MSE)。

如果从 \(w=0, b=0\) 开始,直线是平的,损失很大。梯度下降会告诉我们:「w 该往大调,b 也该往大调」,然后我们照做。反复 100 次,直线就会穿过数据点。


数学定义

\[ L(w, b) = \frac{1}{n}\sum_{i=1}^{n}(wx_i + b - y_i)^2 \] \[ \frac{\partial L}{\partial w} = \frac{2}{n}\sum_{i=1}^{n}(wx_i + b - y_i) \cdot x_i, \quad \frac{\partial L}{\partial b} = \frac{2}{n}\sum_{i=1}^{n}(wx_i + b - y_i) \] \[ w \leftarrow w - \eta \cdot \frac{\partial L}{\partial w}, \quad b \leftarrow b - \eta \cdot \frac{\partial L}{\partial b} \]

Python 动手实践

实例

import numpy as np
np.random.seed(0)

# 生成带噪声的线性数据:真实 y = 2x + 1
n = 60
x = np.random.uniform(-3, 3, n)
y = 2 * x + 1 + np.random.randn(60) * 0.8

# 手推梯度函数(对 w 和 b 分别求偏导)
def compute_gradients(w, b, x, y):
    y_pred = w * x + b
    error = y_pred - y          # 预测值 - 真实值
    dw = np.mean(2 * error * x) # dL/dw
    db = np.mean(2 * error)     # dL/db
    return dw, db

# 梯度下降主循环
w, b = 0.0, 0.0     # 初始参数故意设成 0
lr = 0.05
epochs = 100

print("RUNOOB 梯度下降过程 (真实值 w=2, b=1):")
for epoch in range(epochs):
    y_pred = w * x + b
    loss = np.mean((y_pred - y) ** 2)
    dw, db = compute_gradients(w, b, x, y)
    w -= lr * dw
    b -= lr * db
    if epoch % 20 == 0:
        print(f"  epoch {epoch:3d}  loss={loss:.4f}  w={w:.3f}  b={b:.3f}")

print(f"\nRUNOOB 最终: w={w:.3f}, b={b:.3f}  (真实 w=2, b=1)")
print(f"拟合直线: y = {w:.2f}x + {b:.2f}")
RUNOOB 梯度下降过程 (真实值 w=2, b=1):
  epoch   0  loss=13.4515  w=0.790  b=0.057
  epoch  20  loss=0.9165  w=1.868  b=0.785
  epoch  40  loss=0.7316  w=1.949  b=0.918
  epoch  60  loss=0.7083  w=1.971  b=0.956
  epoch  80  loss=0.7055  w=1.977  b=0.967
  epoch 100  loss=0.7052  w=1.979  b=0.970

RUNOOB 最终: w=1.979, b=0.970  (真实 w=2, b=1)
拟合直线: y = 1.98x + 0.97

AI 中的应用场景

这个案例的代码骨架就是所有深度学习训练的模板:前向计算预测值 → 计算损失 → 反向传播求梯度 → 更新参数 → 重复。PyTorch 中的 optimizer.step() 和 loss.backward() 就是自动化了这个过程。