当前位置: 首页 > news >正文

用PyTorch复现线性回归:从理论到代码的保姆级拆解(附D2L数据集实战)

用PyTorch复现线性回归:从理论到代码的保姆级拆解(附D2L数据集实战)

线性回归是机器学习领域最基础也最重要的算法之一。作为深度学习的入门必备技能,它不仅帮助我们理解模型训练的核心机制,更是后续复杂神经网络的基础。本文将带你用PyTorch从零实现线性回归,结合《动手学深度学习》(D2L)教材中的案例,深入解析每个技术细节。

1. 环境准备与数据生成

在开始建模之前,我们需要准备好开发环境。推荐使用Python 3.8+和PyTorch 1.12+版本。如果你还没有安装PyTorch,可以通过以下命令快速安装:

pip install torch torchvision d2l

线性回归的目标是学习一组参数,使得预测值与真实值之间的差距最小化。为了演示这个过程,我们首先生成一个模拟数据集:

import torch def synthetic_data(w, b, num_examples): """生成y=Xw+b+噪声""" X = torch.normal(0, 1, (num_examples, len(w))) y = torch.matmul(X, w) + b y += torch.normal(0, 0.01, y.shape) # 添加噪声 return X, y.reshape((-1, 1)) true_w = torch.tensor([2, -3.4]) true_b = 4.2 features, labels = synthetic_data(true_w, true_b, 1000)

这段代码生成了1000个样本,每个样本有两个特征。我们设置了真实权重true_w=[2, -3.4]和偏置true_b=4.2,并在输出中添加了少量噪声模拟真实场景。

提示:在机器学习中,我们通常会人为生成这样的数据集来验证算法,因为这样可以精确知道模型应该学习到什么参数。

2. 数据加载与批处理

在实际项目中,数据往往无法一次性全部加载到内存中。PyTorch提供了高效的数据加载机制,但为了理解底层原理,我们先手动实现一个简单的数据迭代器:

import random def data_iter(batch_size, features, labels): num_examples = len(features) indices = list(range(num_examples)) random.shuffle(indices) # 随机打乱顺序 for i in range(0, num_examples, batch_size): batch_indices = torch.tensor( indices[i: min(i + batch_size, num_examples)]) yield features[batch_indices], labels[batch_indices]

这个迭代器每次返回一个批次的数据,主要做了三件事:

  1. 随机打乱数据顺序
  2. 按照指定批量大小划分数据
  3. 返回特征和标签的批量张量

我们可以测试一下这个迭代器:

batch_size = 10 for X, y in data_iter(batch_size, features, labels): print(X.shape, y.shape) # 输出: torch.Size([10, 2]) torch.Size([10, 1]) break

3. 模型定义与参数初始化

线性回归模型的数学表达式非常简单:

$$ \hat{y} = Xw + b $$

其中$X$是输入特征,$w$是权重,$b$是偏置项。在PyTorch中,我们可以这样实现:

def linreg(X, w, b): """线性回归模型""" return torch.matmul(X, w) + b

模型参数需要初始化后才能开始训练。通常我们会:

  • 权重$w$:从均值为0,标准差较小的正态分布中随机初始化
  • 偏置$b$:初始化为0
w = torch.normal(0, 0.01, size=(2,1), requires_grad=True) b = torch.zeros(1, requires_grad=True)

这里的关键是设置了requires_grad=True,这告诉PyTorch需要计算这些参数的梯度,这是自动微分的基础。

4. 损失函数与优化算法

线性回归常用的损失函数是平方误差损失(MSE):

$$ L = \frac{1}{2n}\sum_{i=1}^n (\hat{y}_i - y_i)^2 $$

对应的PyTorch实现:

def squared_loss(y_hat, y): """均方损失""" return (y_hat - y.reshape(y_hat.shape)) ** 2 / 2

对于优化算法,我们使用小批量随机梯度下降(SGD)。其核心思想是:

  1. 计算当前参数下损失函数关于参数的梯度
  2. 沿着梯度反方向更新参数
  3. 重复这个过程直到收敛
def sgd(params, lr, batch_size): """小批量随机梯度下降""" with torch.no_grad(): # 不计算梯度 for param in params: param -= lr * param.grad / batch_size # 参数更新 param.grad.zero_() # 梯度清零

注意:每次更新参数后必须手动清零梯度,否则PyTorch会累积梯度,导致错误的结果。

5. 训练循环与模型评估

现在我们可以将各个组件组合起来,构建完整的训练流程:

lr = 0.03 # 学习率 num_epochs = 3 # 迭代周期数 net = linreg # 模型 loss = squared_loss # 损失函数 for epoch in range(num_epochs): for X, y in data_iter(batch_size, features, labels): l = loss(net(X, w, b), y) # 计算小批量损失 l.sum().backward() # 反向传播计算梯度 sgd([w, b], lr, batch_size) # 更新参数 # 每个epoch后评估整体损失 with torch.no_grad(): train_l = loss(net(features, w, b), labels) print(f'epoch {epoch + 1}, loss {float(train_l.mean()):f}')

训练完成后,我们可以比较学习到的参数与真实参数:

print(f'w的估计误差: {true_w - w.reshape(true_w.shape)}') print(f'b的估计误差: {true_b - b}')

理想情况下,这些误差应该非常小,说明模型成功学习到了数据的生成规律。

6. 与解析解的比较

线性回归有一个独特的性质:它存在解析解(闭式解)。也就是说,我们可以通过数学公式直接计算出最优参数,而不需要迭代优化:

$$ w^* = (X^TX)^{-1}X^Ty $$

X = features y = labels w_analytic = torch.matmul(torch.matmul(torch.inverse(torch.matmul(X.T, X)), X.T), y) print(f'解析解得到的w: {w_analytic.reshape(true_w.shape)}')

虽然解析解看起来更直接,但在实际中有几个限制:

  1. 需要计算矩阵的逆,当特征维度很高时计算代价大
  2. 要求数据集能全部放入内存
  3. 对于更复杂的模型(如神经网络)通常不存在解析解

相比之下,梯度下降法:

  • 可以处理超大规模数据集
  • 适用于各种模型结构
  • 可以灵活调整学习率等超参数

7. 使用PyTorch高级API简化实现

前面的实现帮助我们理解了底层原理,但在实际项目中,我们可以使用PyTorch提供的高级API来简化代码:

import torch.nn as nn # 定义模型 model = nn.Sequential(nn.Linear(2, 1)) # 定义损失函数和优化器 criterion = nn.MSELoss() optimizer = torch.optim.SGD(model.parameters(), lr=0.03) # 训练循环 for epoch in range(num_epochs): for X, y in data_iter(batch_size, features, labels): optimizer.zero_grad() output = model(X) loss = criterion(output, y) loss.backward() optimizer.step() print(f'epoch {epoch+1}, loss {loss.item():f}')

这种实现方式更加简洁,而且利用了PyTorch的许多优化,如:

  • 自动参数初始化
  • 更高效的优化器实现
  • 内置的损失函数
  • 更灵活的网络结构定义

8. 实际应用中的注意事项

在将线性回归应用到真实项目时,有几个关键点需要考虑:

  1. 特征缩放:当特征量纲差异大时,应该进行标准化处理

    from sklearn.preprocessing import StandardScaler scaler = StandardScaler() features_scaled = scaler.fit_transform(features)
  2. 正则化:为防止过拟合,可以添加L1/L2正则化

    # L2正则化(岭回归) optimizer = torch.optim.SGD([ {'params': model[0].weight, 'weight_decay': 0.1}, {'params': model[0].bias}], lr=0.03)
  3. 学习率调整:合适的学习率对收敛至关重要

    scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=30, gamma=0.1)
  4. 评估指标:除了损失函数,还应该关注R²分数等指标

    from sklearn.metrics import r2_score r2 = r2_score(labels.numpy(), model(features).detach().numpy())
  5. GPU加速:对于大规模数据,可以使用GPU加速计算

    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') model = model.to(device) features, labels = features.to(device), labels.to(device)

9. 线性回归的局限性及扩展

虽然线性回归简单有效,但它有一些固有局限:

  1. 线性假设:只能建模线性关系,无法处理非线性模式

    • 解决方案:可以通过特征工程引入多项式特征
    # 添加二次项特征 X_poly = torch.cat([features, features**2], dim=1)
  2. 对异常值敏感:平方损失会放大异常点的影响

    • 解决方案:使用Huber损失等鲁棒损失函数
    criterion = nn.HuberLoss()
  3. 多重共线性问题:当特征高度相关时,参数估计不稳定

    • 解决方案:使用主成分分析(PCA)降维或增加正则化

尽管有这些局限,线性回归仍然是理解更复杂模型的基础。许多先进的深度学习架构,如残差网络(ResNet)中的跳跃连接,本质上可以看作是对线性关系的扩展。

http://www.jsqmd.com/news/596807/

相关文章:

  • 文件路径操作
  • 5分钟搭建AI语音助手:小白也能轻松上手的py-xiaozhi实战指南
  • 3大核心价值+5种应用场景:番茄小说下载器开源工具全解析
  • RMBG-2.0入门必看:暗黑动漫UI交互+透明背景输出完整操作手册
  • 目录操作管理
  • Mermaid:代码驱动的图表绘制工具效率革命
  • 别只搭场景了!深入Prescan动力学模型:从“3D Simple”配置到Simulink信号联调避坑指南
  • OpenClaw学术利器:千问3.5-27B自动校对LaTeX公式与引用
  • AI不是“抢工作”这么简单:过去7天,岗位正在被重组
  • 如何为Unity游戏实现自动翻译:XUnity.AutoTranslator完整使用指南
  • OFA视觉语义蕴含(iic/ofa_visual-entailment_snli-ve_large_en)零基础入门指南
  • 5个实用技巧让你高效使用bypass-paywalls-chrome-clean突破付费内容限制
  • 文件搜索效率低下?FSearch让Linux文件定位速度提升10倍的技术实现与应用指南
  • RTC-8564NB实时时钟芯片驱动开发与低功耗设计指南
  • 工业场景实战:如何用OpenCV搞定无重叠视域的双相机标定与拼接
  • 戴森球计划FactoryBluePrints蓝图库:从新手到高手的终极工厂建设指南
  • 开箱即用体验:AI股票分析师镜像快速生成多维度分析报告
  • 音乐文件解密与跨平台播放完全指南:解锁你的数字音乐自由
  • 百度网盘秒传链接的3个高效解决方案:告别漫长等待的文件传输新时代
  • WiFi CSI感知技术实战指南:从原理到部署的完整解决方案
  • Unity UI布局核心:RectTransform属性实战解析与避坑指南
  • 放大图片轻松到4K ,把你的旧照片快拿出来修复-realesrgan-gui
  • 01 前端 Web 开发 HTML5 + CSS3 + 移动 web 视频教程,前端web入门首选黑马程序员
  • AI辅助开发:协同Claude Code与Kimi,高效实现天气组件智能编码
  • OpenClaw学习助手搭建:Qwen3.5-9B自动整理课程截图笔记
  • mPLUG-Owl3-2B图文问答工具:5分钟本地部署,零基础搭建专属AI看图助手
  • DOE实战指南:从析因设计到响应面优化的全流程解析
  • 突破Windows触控瓶颈:mac-precision-touchpad实现苹果触控板无缝体验
  • 智能电池充电:使用PID控制器优化SOC(Matlab代码实现)
  • 5分钟上手!用Real-ESRGAN-ncnn-vulkan让模糊图像秒变高清,3大场景实测