AI

d2l 学习笔记:深度学习的工程化方法

·11 分钟阅读·4330 字

整理 d2l 学习笔记:深度学习的工程化方法 的核心概念、关键流程与实践要点

📋 目录

d2l 学习笔记:深度学习的工程化方法

你现在学习到 D2L 的线性回归和 Softmax 回归,其实已经接触到了现代深度学习训练流程中最核心的骨架。后续无论是 CNN、RNN、Transformer,甚至大语言模型训练,本质上都没有脱离这个流程,只是模型结构、损失函数和优化方法变得更加复杂。

因此这一节我会把 D2L 3.2(线性回归手动实现)、3.3(线性回归框架实现)、3.4(Softmax回归)、3.6/3.7(Softmax工程实现)中的代码抽象出来,形成一个完整的深度学习模型训练工程流程。

整体来看,一个训练系统可以抽象成:

数据→数据加载→模型定义→前向传播→损失计算→反向传播→参数更新→模型评估→循环优化数据 \rightarrow 数据加载 \rightarrow 模型定义 \rightarrow 前向传播 \rightarrow 损失计算 \rightarrow 反向传播 \rightarrow 参数更新 \rightarrow 模型评估 \rightarrow 循环优化

这就是现在几乎所有深度学习框架(PyTorch、TensorFlow、Paddle)的核心训练范式。


1. 数据准备阶段:把现实问题转换为数学问题

任何机器学习任务第一步都是:

将现实世界中的信息转换成计算机可以处理的数据表示。

例如线性回归:

现实:

房屋面积预测价格。

转换:

输入:

XX

表示房屋特征:

X=[x1 x2 ...]X= \begin{bmatrix} x_1\ x_2\ ... \end{bmatrix}

输出:

yy

表示价格。

最终形成训练数据:

D=(x(1),y(1)),(x(2),y(2)),...,(x(n),y(n))D={(x^{(1)},y^{(1)}),(x^{(2)},y^{(2)}),...,(x^{(n)},y^{(n)})}

在 D2L 中:

features, labels = synthetic_data(true_w,true_b,1000)

对应:

生成训练数据。


2. synthetic_data 做了什么?

代码:

X = torch.normal(0,1,(num_examples,len(w)))

y = torch.matmul(X,w)+b

y += torch.normal(0,0.01,y.shape)

数学对应:

首先生成输入:

X∼N(0,1)X\sim N(0,1)

然后假设真实世界规律:

y=Xw+b+ϵy=Xw+b+\epsilon

其中:

ϵ∼N(0,σ2)\epsilon\sim N(0,\sigma^2)

这里实际上是在模拟:

现实世界存在噪声。

例如:

真实规律:

价格=面积×5000+地段价格=面积\times5000+地段

但是现实:

还有:

  • 装修

  • 楼层

  • 随机因素

所以:

真实值=规律+噪声真实值=规律+噪声

3. 数据加载阶段:为什么需要 DataLoader

现实训练中:

数据可能:

  • 几万张图片

  • 几TB文本

  • 百亿token

不可能一次全部放入GPU。

所以需要:

mini-batch训练。

D2L手写:

data_iter(batch_size,features,labels)

框架:

DataLoader(dataset,batch_size)

本质一样。


例如:

100万个样本。

batch_size=100。

一次训练:

只取:

100100

个样本。

计算:

∇Lbatch\nabla L_{batch}

然后更新。

为什么?

因为:

完整梯度:

∇L=1N∑i=1N∇li\nabla L= \frac1N \sum_{i=1}^{N} \nabla l_i

计算成本太高。

所以使用:

∇Lbatch\nabla L_{batch}

近似:

∇L\nabla L

这就是小批量随机梯度下降。


4. 模型定义阶段:建立数学映射关系

模型本质:

就是一个函数。

例如线性回归:

y^=XW+b\hat y=XW+b

代码:

手动:

def net(X,w,b):
    return torch.matmul(X,w)+b

框架:

net=nn.Linear(2,1)

区别:

手写:

你管理参数。

框架:

PyTorch管理参数。

但是数学完全一样。


Softmax:

模型:

o=XW+bo=XW+b

输出:

logits。

代码:

net=nn.Linear(784,10)

表示:

输入:

784个像素。

输出:

10个类别分数。


5. 前向传播阶段:计算预测结果

训练循环:

首先:

输入数据:

XX

进入模型:

y^=fθ(X)\hat y=f_\theta(X)

这个过程叫:

forward。


线性回归:

y^=XW+b\hat y=XW+b

Softmax:

先:

o=XW+bo=XW+b

然后:

y^j=eoj∑keok\hat y_j= \frac{e^{o_j}} {\sum_ke^{o_k}}

得到类别概率。

代码:

y_hat=net(X)

6. 损失函数:评价预测错误程度

模型预测之后,需要回答:

这个结果好不好?

所以定义:

损失函数。


7. 线性回归

预测:

y^\hat y

真实:

yy

误差:

y^−y\hat y-y

平方:

(y^−y)2(\hat y-y)^2

得到:

均方误差:

L=1n∑i(y^i−yi)2L= \frac1n \sum_i (\hat y_i-y_i)^2

代码:

squared_loss(y_hat,y)

8. Softmax分类

预测:

y^\hat y

例如:

[0.1,0.8,0.1][0.1,0.8,0.1]

真实:

[1,0,0][1,0,0]

我们关心:

真实类别概率。

交叉熵:

L=−∑iyilog⁡y^iL=-\sum_i y_i\log\hat y_i

如果:

真实类别概率低:

损失大。

如果:

真实类别概率高:

损失小。

代码:

cross_entropy(y_hat,y)

9. 反向传播:计算参数应该如何变化

这是训练最核心步骤。

损失:

LL

是参数:

W,bW,b

的函数。

所以:

求:

∂L∂W\frac{\partial L}{\partial W}

表示:

如果改变参数:

损失如何变化。

代码:

l.backward()

PyTorch自动计算:

计算图:

W→o→lossW \rightarrow o \rightarrow loss

然后链式求导:

∂L∂W∂L∂o∂o∂W\frac{\partial L}{\partial W} \frac{\partial L}{\partial o} \frac{\partial o}{\partial W}

10. 参数更新阶段:优化模型

得到梯度:

∇W\nabla W

更新:

W=W−η∇WW=W-\eta\nabla W

其中:

η\eta

叫学习率。


D2L手写:

param -= lr*param.grad/batch_size

PyTorch:

optimizer.step()

例如:

optimizer=torch.optim.SGD(
    net.parameters(),
    lr=0.03
)

11. 训练循环:重复优化

完整训练:

for epoch:

    for X,y in data_iter:

        y_hat=net(X)

        loss=loss_fn(y_hat,y)

        optimizer.zero_grad()

        loss.backward()

        optimizer.step()

对应数学:

不断重复:

θt+1θt−η∇θL(θt)\theta_{t+1} \theta_t-\eta\nabla_\theta L(\theta_t)

直到:

损失下降。


12. 模型评估阶段

训练损失下降不代表模型真的好。

因为可能:

过拟合。

所以需要测试集。

代码:

evaluate_accuracy(net,test_iter)

计算:

预测正确数量:

correctcorrect

总数量:

totaltotal

准确率:

Accuracy=correcttotalAccuracy= \frac{correct}{total}

13. 完整工程流程图

把D2L代码抽象:

                数据集
                  |
                  ↓
          Dataset / DataLoader
                  |
                  ↓
              Batch数据
                  |
                  ↓
              Model
                  |
                  ↓
            Forward传播
                  |
                  ↓
              Prediction
                  |
                  ↓
            Loss Function
                  |
                  ↓
          Autograd计算梯度
                  |
                  ↓
            Optimizer更新
                  |
                  ↓
              新参数
                  |
                  ↓
             下一批数据
                  |
                  ↓
              Epoch循环
                  |
                  ↓
             Evaluation

14. 手写实现和框架实现最大的区别

15. D2L手写线性回归

你负责:

  • 参数初始化

  • 前向计算

  • 损失函数

  • 梯度更新

  • 数据迭代

目的:

理解数学。


16. PyTorch实现

框架负责:

  • 参数管理

  • 自动求导

  • 优化器

  • GPU计算

  • 数据加载

你负责:

  • 定义模型结构

  • 定义loss

  • 定义optimizer

  • 写训练循环


17. 从工程角度理解一个模型

实际上一个生产级训练系统就是下面几个模块:

18. 数据模块

负责:

  • 数据读取

  • 清洗

  • 增强

  • batch

例如:

PyTorch:

Dataset
DataLoader

19. 模型模块

负责:

定义:

fθ(x)f_\theta(x)

例如:

nn.Module

20. 损失模块

负责:

定义:

L(y,y^)L(y,\hat y)

例如:

MSELoss
CrossEntropyLoss

21. 优化模块

负责:

θ←θ−η∇L\theta\leftarrow\theta-\eta\nabla L

例如:

SGD
Adam

22. 训练管理模块

负责:

  • epoch

  • checkpoint

  • logging

  • evaluation

工业中:

还有:

  • TensorBoard

  • WandB

  • MLFlow

  • Kubernetes训练任务管理


23. 最后总结

你目前学习的线性回归和Softmax回归,本质上是在学习现代AI系统最基础的训练闭环:

数据→模型→预测→损失→梯度→参数更新\boxed{ 数据 \rightarrow 模型 \rightarrow 预测 \rightarrow 损失 \rightarrow 梯度 \rightarrow 参数更新 }

线性回归让你理解:

模型如何通过误差调整参数。

Softmax回归让你理解:

模型如何输出概率并通过交叉熵优化分类。

而PyTorch框架让你理解:

如何把数学模型工程化为一个可重复运行的大规模训练系统。

后面 CNN、Transformer、大模型训练,变化主要集中在:

  • 模型函数 fθf_\theta 更复杂;

  • 参数量更大;

  • 数据更多;

  • 优化策略更高级;

但是训练闭环本质仍然是这一套。你现在D2L第三章实际上是在建立整个深度学习工程体系的底层抽象。


关联文档

Yanche Blog

记录云原生、Linux、数据库等技术领域的学习心得,以及日常生活的思考与感悟。

© 2026 Yanche Blog. All rights reserved.

Powered by Astro