用 PyTorch 手动实现线性回归
在深度学习的世界里,线性回归常被视为“Hello World”级别的入门算法。虽然它看起来很简单,但它包含了深度学习的核心思想:参数化模型、损失函数、优化算法。
今天,我将带领大家使用 PyTorch,不依赖高级 API,从零开始手动实现线性回归。
1. 生成人造数据
为了验证我们的代码是否正确,我们需要一个已知答案的数据集。我们将根据公式 $y = Xw + b + \text{noise}$ 生成数据。
我们设定真实的参数为:
- 权重 (w):
[2, -3.4] - 偏置 (b):
4.2
1 | import random |
运行代码后,我们可以看到数据集的形状为 (1000, 2),标签形状为 (1000, 1)。通过绘制散点图,我们可以直观地看到特征与标签之间存在的线性关系(此处放你的图)。
2. 数据迭代器
在训练时,我们不会一次性把所有数据喂给模型,而是分批(Batch)进行。这不仅能节省内存,还能让模型收敛得更好。
1 | def data_iter(batch_size, features, labels): |
这里我们使用了 Python 的生成器 (yield),它可以在需要时才生成数据,非常高效。
3. 初始化参数
接下来,我们需要初始化模型的参数。我们将权重 w 初始化为均值为 0、标准差为 0.01 的正态分布随机数,偏置 b 初始化为 0。
注意:因为我们希望 PyTorch 记录这些参数的梯度以便后续更新,所以必须设置 requires_grad=True。
1 | w = torch.normal(0, 0.01, size=(2,1), requires_grad=True) |
4. 定义模型与损失
模型的定义非常简单,就是矩阵乘法:
1 | def linreg(X, w, b): |
损失函数我们选择均方损失 (MSE):
1 | def squared_loss(y_hat, y): |
5. 定义优化算法
我们实现最基础的小批量随机梯度下降 (SGD)。对于每个参数,我们将其沿着梯度的反方向移动一小步(学习率)。
1 | def sgd(params, lr, batch_size): |
6. 训练过程
现在,我们将所有组件组装起来,开始训练!
1 | lr = 0.03 |
训练结果:
经过 3 轮训练,我们的损失已经降到了一个很小的值。让我们来看看学到的参数与真实参数的对比:
1 | print(f'真实 w: {true_w}, 学习到的 w: {w.reshape(true_w.shape)}') |
输出结果应该类似于:
w的估计误差: tensor([ 0.0003, -0.0008])
b的估计误差: tensor([0.0011])
可以看到,学习到的参数与真实参数非常接近!这证明我们的模型训练成功了。
结语
通过这篇文章,我们手动实现了线性回归的所有核心组件。虽然 PyTorch 之后提供了更高级的 nn.Module 和 torch.optim,但理解底层原理对于成为一名优秀的算法工程师至关重要。
本文部分内容参考动手学深度学习,遵循 Apache 2.0 协议。