斯坦福/清华大佬联袂出品,这本开源「深度学习百科全书」终于出了中文版!
超越吴恩达课程的理论深度,碾压李沐课程的代码实现——这本书正在重新定义全球AI学习标准
一、为什么这个项目值得关注
1.1 项目概述
D2L(英文全称 “Dive into Deep Learning”,中文译作《动手学深度学习》)是目前全球最受欢迎的深度学习开源教材之一。该项目由 Amazon 科学家 李沐、UC Berkeley 教授 Alexander J. Smola、联合创始人 Aston Zhang 等顶尖学者共同编写和维护。
截至目前,该 GitHub 仓库已获得超过 150,000+ Stars,成为机器学习领域 Star 数量最多的教学类项目之一。
仓库地址: https://github.com/d2l-ai/d2l-en
官方主页: https://d2l.ai/
中文镜像: https://zh.d2l.ai/
1.2 项目的独特价值
为什么我要强烈推荐这个项目?让我从三个维度告诉你答案:
第一,理论与实践的完美平衡
传统教材要么只讲数学推导让人昏昏欲睡,要么只贴代码而不解释原理。D2L 做到了两者兼顾——每一个概念都有清晰的数学解释,紧接着就是可运行的代码实现。你可以边学理论边动手验证,这种学习方式效率极高。
第二,多框架支持
很多深度学习教材只聚焦于某一种框架(比如只讲 PyTorch),但在实际工作中,你需要根据项目需求选择合适的框架。D2L 提供了 PyTorch、TensorFlow、JAX、NumPy/JAX 四种框架的完整实现,让你学完一本教材就能掌握四种主流工具。
第三,循序渐进的知识体系
从最基础的线性回归开始,逐步深入到 Transformer、目标检测、语义分割等前沿领域。每一个章节都经过精心设计,前置知识交代清楚,不会出现”跳步”导致的理解断层。
1.3 谁适合学习这个项目
根据我的观察,以下几类人最适合使用 D2L:
✓ 计算机专业学生,想系统学习深度学习
✓ 转行AI的工程师,需要快速上手实战
✓ 研究人员,想深入理解模型原理
✓ 算法工程师,想夯实理论基础
✓ 对人工智能感兴趣的任何人
二、环境搭建:从零开始配置深度学习环境
2.1 基础环境要求
在开始之前,请确保你的电脑满足以下基本要求:
| 组件 | 最低配置 | 推荐配置 |
|---|---|---|
| 内存 | 8GB | 16GB+ |
| 显卡 | 无要求 | NVIDIA GPU (6GB+显存) |
| 硬盘 | 20GB可用空间 | 50GB+ SSD |
| 操作系统 | Windows/macOS/Linux | Ubuntu 20.04+ |
2.2 安装 Miniconda
我们推荐使用 conda 来管理 Python 环境,这样可以避免不同项目之间的依赖冲突。
# Linux/macOS 下载并安装 Miniconda
wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh
bash Miniconda3-latest-Linux-x86_64.sh
# Windows 用户请访问 https://docs.conda.io/en/latest/miniconda.html 下载安装包
# 安装完成后,关闭终端并重新打开,让环境变量生效
2.3 创建并激活虚拟环境
# 创建一个名为 d2l 的环境,指定 Python 版本为 3.9
conda create -n d2l python=3.9 -y
# 激活这个环境
conda activate d2l
# 验证激活成功(你应该在命令行前面看到 (d2l))
python --version
2.4 安装深度学习框架和依赖
D2L 项目的核心依赖包括深度学习框架、d2l 包以及其他科学计算库。以下是针对不同框架的安装方法:
安装 PyTorch 版本(推荐新手)
# 安装 PyTorch CPU 版本(适合没有 GPU 的用户)
pip install torch torchvision
# 安装 PyTorch GPU 版本(需要 NVIDIA 显卡和 CUDA)
pip install torch torchvision --extra-index-url https://download.pytorch.org/whl/cu118
# 安装 d2l 包和相关依赖
pip install d2l==0.17.6 matplotlib notebook jupyterlab
安装 TensorFlow 版本
# 安装 TensorFlow
pip install tensorflow
# 安装 d2l 包
pip install d2l==0.17.6 matplotlib notebook jupyterlab
2.5 安装 d2l 包的其他依赖
# 安装 scipy 用于科学计算
pip install scipy
# 安装 pandas 用于数据处理
pip install pandas
# 安装 ipykernel 用于 Jupyter Notebook
pip install ipykernel
# 将 d2l 环境添加到 Jupyter 内核
python -m ipykernel install --user --name d2l --display-name "Python (d2l)"
2.6 下载 D2L 书籍章节内容
# 方法一:克隆 GitHub 仓库(包含所有章节的源代码)
git clone https://github.com/d2l-ai/d2l-en.git
cd d2l-en
# 方法二:只下载 PDF 电子书(如果你只想阅读)
# 访问 https://github.com/d2l-ai/d2l-en/releases 下载最新版本的 PDF
# 查看仓库结构
ls -la
运行上述命令后,你应该能看到类似如下的目录结构:
d2l-en/
├── chapter_preface/ # 前言
├── chapter_optimization/ # 优化算法
├── chapter_convolutional-neural-networks/ # 卷积神经网络
├── chapter_recurrent-neural-networks/ # 循环神经网络
├── chapter_attention-mechanisms/ # 注意力机制
├── chapter_computational-performance/ # 计算性能
├── chapter_computer-vision/ # 计算机视觉
├── chapter_natural-language-processing/ # 自然语言处理
├── d2l/ # 核心工具库
├── config.ini # 配置文件
└── README.md # 项目说明
2.7 启动 Jupyter Notebook 进行验证
# 进入工作目录
cd d2l-en
# 启动 Jupyter Notebook
jupyter notebook
# 或者启动 JupyterLab(功能更强大)
jupyter lab
在浏览器中打开 Jupyter 界面后,创建一个新 Notebook,选择 d2l 内核,然后运行以下代码验证环境是否正确:
# 验证 d2l 包是否安装成功
import d2l
# 验证 PyTorch 是否可用
import torch
print(f"PyTorch 版本: {torch.__version__}")
# 验证是否可以使用 GPU(如果有的话)
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
print(f"当前设备: {device}")
# 简单的张量运算测试
x = torch.tensor([[1, 2, 3], [4, 5, 6]], device=device)
y = torch.tensor([[7, 8, 9], [10, 11, 12]], device=device)
z = x + y
print(f"张量运算测试成功: {z.shape}")
如果所有输出都正常,恭喜你!环境配置成功。
三、核心内容体系:逐章深入学习路径
D2L 的内容结构经过精心设计,形成了一个完整的深度学习知识体系。让我为你详细介绍每个主要模块。
3.1 预备知识(第1-4章)
这一部分为零基础读者提供了必要的数学和编程基础。
第1章:引言
这部分通过一个简单的房价预测问题,引出机器学习的基本概念。你将学会:
# D2L 中第一个完整的机器学习示例
# 使用人工构造的数据集来理解机器学习的工作流程
import numpy as np
import matplotlib.pyplot as plt
from d2l import torch as d2l
# 生成训练数据:假设房价与面积呈线性关系
true_w = np.array([2, -3.4]) # 真实的权重参数
true_b = 4.2 # 真实的偏置参数
num_examples = 1000
features = np.random.randn(num_examples, 2) # 生成1000个二维特征
labels = np.dot(features, true_w) + true_b # 计算标签
labels += np.random.randn(num_examples) * 0.1 # 添加噪声
# 可视化数据分布
d2l.scatter(features[:, 1].detach().numpy(),
labels.detach().numpy(),
figsize=(6, 3))
第2章:预微分
这一章教你理解深度学习框架如何自动计算梯度。理解反向传播的原理对于后续学习至关重要。
# 使用 PyTorch 的自动求导机制
import torch
x = torch.arange(4.0, requires_grad=True)
print(f"x 的值: {x}")
print(f"x 是否有梯度: {x.requires_grad}")
# 定义一个函数
y = 2 * torch.dot(x, x)
print(f"y = 2 * torch.dot(x, x) = {y}")
# 自动求导
y.backward()
print(f"dy/dx = {x.grad}")
# 验证梯度计算是否正确
# y = 2 * (x1^2 + x2^2 + x3^2 + x4^2)
# dy/dxi = 4 * xi
print(f"验证: 4 * x = {4 * x}")
第3章:线性回归
线性回归是所有深度学习的起点。通过这一章,你将掌握:
- 神经网络的通用编程模式
- 数据加载和批处理
- 损失函数的选择
- 梯度下降优化
- 模型评估指标
# 完整的线性回归实现
class LinearRegression(d2l.Module):
def __init__(self, lr):
super().__init__()
self.save_hyperparameters()
# 使用 PyTorch 简洁地定义网络
self.net = nn.LazyLinear(1) # 单层线性网络
# 权重初始化为均值为0、标准差为0.01的正态分布
self.net[0].weight.data.normal_(0, 0.01)
self.net[0].bias.data.fill_(0)
def forward(self, X):
return self.net(X)
def loss(self, y_hat, y):
fn = nn.MSELoss()
return fn(y_hat, y)
def configure_optimizers(self):
return torch.optim.SGD(self.parameters(), lr=self.lr)
# 训练模型
model = LinearRegression(lr=0.03)
data = d2l.SyntheticRegressionData(w=torch.tensor([2, -3.4]), b=4.2)
trainer = d2l.Trainer(max_epochs=3)
trainer.fit(model, data)
第4章:Softmax 回归
这是你接触分类问题的起点。Softmax 回归虽然简单,但它是理解神经网络如何处理分类任务的基础。
3.2 基础网络架构(第5-8章)
这一部分介绍深度学习的核心网络组件。
第5章:多层感知机(MLP)
这一章教你如何堆叠多层神经元,以及如何解决非线性分类问题。
# 实现带有一个隐藏层的多层感知机
class MLP(d2l.Module):
def __init__(self, num_inputs, num_outputs, num_hiddens, lr):
super().__init__()
self.save_hyperparameters()
# 定义隐藏层和输出层
self.net = nn.Sequential(
nn.Flatten(),
nn.LazyLinear(num_hiddens), # 隐藏层
nn.ReLU(), # 激活函数
nn.LazyLinear(num_outputs) # 输出层
)
def forward(self, X):
return self.net(X)
def loss(self, y_hat, y):
return F.cross_entropy(y_hat, y)
def configure_optimizers(self):
return torch.optim.SGD(self.parameters(), lr=self.lr)
# 关键概念:正则化防止过拟合
# 1. Dropout 随机丢弃部分神经元
# 2. 权重衰减(L2正则化)限制权重过大
# 3. 早停法在验证集性能下降时停止训练
第6章:深度学习计算
这一章深入探讨神经网络的构建块,包括层、块、参数管理、以及 GPU 计算。
# 使用 nn.Sequential 构建复杂的网络结构
net = nn.Sequential(
nn.Conv2d(1, 6, kernel_size=5, padding=2), nn.ReLU(),
nn.MaxPool2d(kernel_size=2, stride=2),
nn.Conv2d(6, 16, kernel_size=5), nn.ReLU(),
nn.MaxPool2d(kernel_size=2, stride=2),
nn.Flatten(),
nn.Linear(16 * 5 * 5, 120), nn.ReLU(),
nn.Dropout(0.5), # Dropout 层,防止过拟合
nn.Linear(120, 84), nn.ReLU(),
nn.Dropout(0.5),
nn.Linear(84, 10)
)
# 跨设备计算:将数据移动到 GPU
def try_gpu(i=0):
if torch.cuda.device_count() >= i + 1:
return torch.device(f'cuda:{i}')
return torch.device('cpu')
X = torch.randn(1, 1, 32, 32).to(try_gpu())
net = net.to(try_gpu())
print(f"输入设备: {X.device}")
print(f"输出形状: {net(X).shape}")
第7章:卷积神经网络(CNN)
CNN 是计算机视觉的基础。这一章详细讲解卷积、填充、步幅、通道等核心概念。
# 手动实现卷积操作,理解其原理
def corr2d(X, K):
"""二维互相关运算"""
h, w = K.shape
Y = torch.zeros((X.shape[0] - h + 1, X.shape[1] - w + 1))
for i in range(Y.shape[0]):
for j in range(Y.shape[1]):
Y[i, j] = (X[i:i+h, j:j+w] * K).sum()
return Y
# 测试卷积操作
X = torch.tensor([[0.0, 1.0, 2.0], [3.0, 4.0, 5.0], [6.0, 7.0, 8.0]])
K = torch.tensor([[0.0, 1.0], [2.0, 3.0]])
print(f"卷积结果:\n{corr2d(X, K)}")
# LeNet-5:第一个成功的卷积神经网络
class LeNet(d2l.Module):
def __init__(self, lr=0.1, num_classes=10):
super().__init__()
self.save_hyperparameters()
self.net = nn.Sequential(
nn.LazyConv2d(6, kernel_size=5, padding=2), nn.ReLU(),
nn.MaxPool2d(kernel_size=2, stride=2),
nn.LazyConv2d(16, kernel_size=5), nn.ReLU(),
nn.MaxPool2d(kernel_size=2, stride=2),
nn.Flatten(),
nn.LazyLinear(120), nn.ReLU(),
nn.LazyLinear(84), nn.ReLU(),
nn.LazyLinear(num_classes)
)
def forward(self, X):
return self.net(X)
def loss(self, y_hat, y):
return F.cross_entropy(y_hat, y)
def configure_optimizers(self):
return torch.optim.SGD(self.parameters(), lr=self.lr)
第8章:现代卷积神经网络
这一章介绍自 2012 年 AlexNet 以来的现代 CNN 架构:
# AlexNet:2012年ImageNet竞赛冠军,开启深度学习复兴
class AlexNet(d2l.Module):
def __init__(self, lr=0.01, num_classes=1000):
super().__init__()
self.save_hyperparameters()
self.net = nn.Sequential(
nn.LazyConv2d(96, kernel_size=11, stride=4, padding=1), nn.ReLU(),
nn.MaxPool2d(kernel_size=3, stride=2),
nn.LazyConv2d(256, kernel_size=5, padding=2), nn.ReLU(),
nn.MaxPool2d(kernel_size=3, stride=2),
nn.LazyConv2d(384, kernel_size=3, padding=1), nn.ReLU(),
nn.LazyConv2d(384, kernel_size=3, padding=1), nn.ReLU(),
nn.LazyConv2d(256, kernel_size=3, padding=1), nn.ReLU(),
nn.MaxPool2d(kernel_size=3, stride=2),
nn.Dropout(0.5),
nn.LazyLinear(4096), nn.ReLU(),
nn.Dropout(0.5),
nn.LazyLinear(4096), nn.ReLU(),
nn.LazyLinear(num_classes)
)
def forward(self, X):
return self.net(X)
# VGG:使用可复用的 VGG 块构建网络
def vgg_block(num_convs, out_channels):
layers = []
for _ in range(num_convs):
layers.append(nn.LazyConv2d(out_channels, kernel_size=3, padding=1))
layers.append(nn.ReLU())
layers.append(nn.MaxPool2d(kernel_size=2, stride=2))
return nn.Sequential(*layers)
class VGG(d2l.Module):
def __init__(self, arch, lr=0.01, num_classes=1000):
super().__init__()
self.save_hyperparameters()
conv_blocks = []
in_channels = 1
for (num_convs, out_channels) in arch:
conv_blocks.append(vgg_block(num_convs, out_channels))
in_channels = out_channels
self.net = nn.Sequential(
*conv_blocks,
nn.Flatten(),
nn.LazyLinear(4096), nn.ReLU(), nn.Dropout(0.5),
nn.LazyLinear(4096), nn.ReLU(), nn.Dropout(0.5),
nn.LazyLinear(num_classes)
)
def forward(self, X):
return self.net(X)
# ResNet:引入残差连接,解决深层网络训练难题
class Residual(nn.Module):
def __init__(self, num_channels, use_1x1conv=False, strides=1):
super().__init__()
self.conv1 = nn.LazyConv2d(num_channels, kernel_size=3, padding=1, stride=strides)
self.conv2 = nn.LazyConv2d(num_channels, kernel_size=3, padding=1)
if use_1x1conv:
self.conv3 = nn.LazyConv2d(num_channels, kernel_size=1, stride=strides)
else:
self.conv3 = None
self.bn1 = nn.LazyBatchNorm2d()
self.bn2 = nn.LazyBatchNorm2d()
self.relu = nn.ReLU()
def forward(self, X):
Y = self.relu(self.bn1(self.conv1(X)))
Y = self.bn2(self.conv2(Y))
if self.conv3 is not None:
X = self.conv3(X)
Y += X
return self.relu(Y)
3.3 循环神经网络(第9-10章)
第9章:序列模型
这一章处理具有时间依赖性的数据,如文本、股票价格、语音信号等。
# 文本预处理示例
import collections
import re
# 读取并预处理文本数据
def read_time_machine():
with open(d2l.download('https://raw.githubusercontent.com/d2l-ai/d2l-en/master/data/timemachine.txt'), 'r') as f:
lines = f.readlines()
# 转换为小写并移除非字母字符
lines = [re.sub('[^A-Za-z]+', ' ', line).strip().lower() for line in lines]
return lines
# 构建词汇表
def tokenize(lines, token='word'):
if token == 'word':
return [line.split() for line in lines]
elif token == 'char':
return [list(line) for line in lines]
# 加载数据集
class Vocab:
def __init__(self, tokens=None, min_freq=0, reserved_tokens=None):
if tokens is None:
tokens = []
if reserved_tokens is None:
reserved_tokens = []
counter = count_corpus(tokens)
self._token_freqs = sorted(counter.items(), key=lambda x: x[1], reverse=True)
# 构建未知词索引为0的词汇表
self.idx_to_token = ['<unk>'] + reserved_tokens
self.token_to_idx = {token: idx for idx, token in enumerate(self.idx_to_token)}
for token, freq in self._token_freqs:
if freq < min_freq:
break
if token not in self.token_to_idx:
self.idx_to_token.append(token)
self.token_to_idx[token] = len(self.idx_to_token) - 1
def __len__(self):
return len(self.idx_to_token)
def __getitem__(self, tokens):
if not isinstance(tokens, (list, tuple)):
return self.token_to_idx.get(tokens, self.token_to_idx['<unk>'])
return [self.__getitem__(token) for token in tokens]
def to_tokens(self, indices):
if not isinstance(indices, (list, tuple)):
return self.idx_to_token[indices]
return [self.idx_to_token[index] for index in indices]
第10章:现代循环神经网络
这一章实现了几种重要的 RNN 变体:LSTM(长短期记忆网络)和 GRU(门控循环单元)。
# LSTM 的核心实现
class LSTM(d2l.Module):
def __init__(self, num_inputs, num_hiddens, num_layers, dropout=0):
super().__init__()
self.save_hyperparameters()
self.rnn = nn.LSTM(num_inputs, num_hiddens, num_layers,
dropout=dropout, batch_first=True)
self.dense = nn.LazyLinear(1)
def forward(self, X, state=None):
# X shape: (batch_size, num_steps, num_inputs)
output, state = self.rnn(X, state)
# 只取最后一个时间步的输出
output = self.dense(output[:, -1, :])
return output, state
def init_state(self, batch_size):
# 初始化隐藏状态和细胞状态
return (torch.zeros((self.rnn.num_layers, batch_size,
self.rnn.hidden_size), device=X.device),
torch.zeros((self.rnn.num_layers, batch_size,
self.rnn.hidden_size), device=X.device))
3.4 注意力机制与 Transformer(第11-13章)
这是 D2L 最核心、最前沿的部分。
第11章:注意力机制
注意力机制让模型能够”关注”输入中最相关的部分。
# 缩放点积注意力机制的实现
def masked_softmax(X, valid_lens):
"""带掩码的 softmax 操作"""
if valid_lens is None:
return F.softmax(X, dim=-1)
else:
shape = X.shape
if valid_lens.dim() == 1:
valid_lens = torch.repeat_interleave(valid_lens, shape[1])
else:
valid_lens = valid_lens.reshape(-1)
# 将超出有效长度的位置填充为负无穷
X = X.reshape(-1, shape[-1])
maxlen = X.size(1)
mask = torch.arange(maxlen, dtype=torch.float32, device=X.device)[None, :] < valid_lens[:, None]
X[~mask] = -1e6
return F.softmax(X.reshape(shape), dim=-1)
class DotProductAttention(d2l.Module):
"""缩放点积注意力"""
def __init__(self, dropout):
super().__init__()
self.dropout = nn.Dropout(dropout)
def forward(self, queries, keys, values, valid_lens=None):
d = queries.shape[-1]
# 缩放因子:sqrt(d)
scores = torch.bmm(queries, keys.transpose(1, 2)) / math.sqrt(d)
self.attention_weights = masked_softmax(scores, valid_lens)
return torch.bmm(self.dropout(self.attention_weights), values)
# 多头注意力机制
class MultiHeadAttention(d2l.Module):
def __init__(self, num_inputs, num_heads, num_hiddens, dropout, bias=False):
super().__init__()
self.num_heads = num_heads
self.num_hiddens = num_hiddens
# 四个线性变换层:Query、Key、Value、输出
self.W_q = nn.LazyLinear(num_hiddens, bias=bias)
self.W_k = nn.LazyLinear(num_hiddens, bias=bias)
self.W_v = nn.LazyLinear(num_hiddens, bias=bias)
self.W_o = nn.LazyLinear(num_hiddens, bias=bias)
self.attention = DotProductAttention(dropout)
def forward(self, queries, keys, values, valid_lens):
# Linear projection + reshape for multi-head
queries = self._transform_heads(self.W_q(queries))
keys = self._transform_heads(self.W_k(keys))
values = self._transform_heads(self.W_v(values))
# Apply attention
out_concat = self.attention(queries, keys, values, valid_lens)
out = out_concat.reshape(-1, self.num_hiddens * self.num_heads)
return self.W_o(out)
def _transform_heads(self, X):
# X shape: (batch_size, num_steps, num_hiddens)
X = X.reshape(X.shape[0], X.shape[1], self.num_heads, -1)
return X.transpose(1, 2) # (batch_size, num_heads, num_steps, d_k)
第12章:Transformer 架构
Transformer 是当前 AI 领域最重要的架构,被广泛应用于自然语言处理、图像处理、语音处理等各个领域。
# Transformer 编码器块
class TransformerEncoderBlock(d2l.Module):
def __init__(self, num_inputs, num_hiddens, norm_shape, num_heads,
num_layers, dropout, use_bias=False):
super().__init__()
self.attention = MultiHeadAttention(num_inputs, num_heads,
num_hiddens, dropout)
self.addnorm1 = AddNorm(norm_shape, dropout)
self.ffn = PositionWiseFFN(num_hiddens, dropout)
self.addnorm2 = AddNorm(norm_shape, dropout)
def forward(self, X, valid_lens):
# Self-attention sublayer
Y = self.addnorm1(X, self.attention(X, X, X, valid_lens))
# Feed-forward sublayer
Y = self.addnorm2(Y, self.ffn(Y))
return Y
# Transformer 解码器块
class TransformerDecoderBlock(d2l.Module):
def __init__(self, num_inputs, num_hiddens, norm_shape, num_heads,
num_layers, dropout, size=None):
super().__init__()
self.num_hiddens = num_hiddens
self.num_layers = num_layers
self.attention = MultiHeadAttention(num_inputs, num_heads,
num_hiddens, dropout)
self.addnorm1 = AddNorm(norm_shape, dropout)
self.cross_attention = MultiHeadAttention(num_inputs, num_heads,
num_hiddens, dropout)
self.addnorm2 = AddNorm(norm_shape, dropout)
self.ffn = PositionWiseFFN(num_hiddens, dropout)
self.addnorm3 = AddNorm(norm_shape, dropout)
def forward(self, X, state):
enc_outputs, enc_valid_lens = state[0], state[1]
# 在训练阶段,输出是已知的,不需要掩码
if state[2] is None:
key_values = X
query_mask = None
else:
key_values = torch.cat((state[2], X), dim=1)
query_mask = d2l.mask(3 * X.shape[1])
# Self-attention with causal mask
X2 = self.attention(X, key_values, key_values, query_mask)
Y = self.addnorm1(X, X2)
# Cross-attention
X2 = self.cross_attention(Y, enc_outputs, enc_outputs, enc_valid_lens)
Y = self.addnorm2(Y, X2)
# Feed-forward
Y = self.addnorm3(Y, self.ffn(Y))
return Y, [enc_outputs, enc_valid_lens, key_values]
3.5 计算机视觉与 NLP 应用(第14-16章)
第14章:计算机视觉
这一章涵盖目标检测、语义分割、风格迁移等任务。
# 锚框生成(用于目标检测)
def generate_anchor_base(base_size=16, ratios=[0.5, 1, 2], anchor_scales=[8, 16, 32]):
"""生成基础锚框"""
py, px = d2l.center_to_corner_coordinates(torch.tensor([base_size / 2.0]))
py, px = py.item(), px.item()
anchor_base = torch.zeros((len(ratios) * len(anchor_scales), 4))
for i, ratio in enumerate(ratios):
for j, scale in enumerate(anchor_scales):
h = base_size * scale * np.sqrt(ratio)
w = base_size * scale / np.sqrt(ratio)
index = i * len(anchor_scales) + j
anchor_base[index, 0] = py - h / 2.0
anchor_base[index, 1] = px - w / 2.0
anchor_base[index, 2] = py + h / 2.0
anchor_base[index, 3] = px + w / 2.0
return anchor_base
# SSD(单步目标检测)简化实现
class TinySSD(d2l.Module):
def __init__(self, num_classes, num_anchors, **kwargs):
super().__init__(**kwargs)
self.num_classes = num_classes
self.num_anchors = num_anchors
self.num_ooutputs = [4, num_anchors, 4, num_anchors, 4, num_anchors]
self.net = nn.Sequential(
nn.LazyConv2d(16, kernel_size=3, padding=1),
nn.ReLU(),
nn.MaxPool2d(kernel_size=2, stride=2),
nn.LazyConv2d(32, kernel_size=3, padding=1),
nn.ReLU(),
nn.MaxPool2d(kernel_size=2, stride=2),
nn.LazyConv2d(64, kernel_size=3, padding=1),
nn.ReLU(),
nn.MaxPool2d(kernel_size=2, stride=2),
nn.LazyConv2d(64, kernel_size=3, padding=1),
nn.ReLU(),
nn.MaxPool2d(kernel_size=2, stride=2),
nn.LazyConv2d(64, kernel_size=3, padding=1),
nn.ReLU(),
)
self.output = nn.ModuleList([
nn.LazyConv2d(self.num_ooutputs[i] * num_anchors,
kernel_size=3, padding=1)
for i in range(6)
])
def forward(self, X):
anchors = []
for i, feat in enumerate(self.output):
anchors.append(d2l.multibox_detection(
self.output[i](self.net(X) if i == 0 else self.net(X)),
self.anchors, self.cls_preds, self.bbox_preds
))
return anchors
第15章:自然语言处理
这一章涵盖了 word2vec、Word2Vec、 BERT、 自然语言情感分析等前沿内容。
# Skip-gram 词嵌入模型
class SkipGram(nn.Module):
def __init__(self, num_embeddings, embedding_dim):
super().__init__()
self.token_embedding = nn.Embedding(num_embeddings, embedding_dim)
self.context_embedding = nn.Embedding(num_embeddings, embedding_dim)
def forward(self, center, contexts_and_negatives):
v = self.token_embedding(center) # (batch_size, embed_dim)
u = self.context_embedding(contexts_and_negatives[:, 0]) # 正样本
u_neg = self.context_embedding(contexts_and_negatives[:, 1:]) # 负样本
# 计算正样本的相似度
pred = torch.bmm(u, v.unsqueeze(2)).squeeze() # (batch_size,)
# 计算负样本的相似度
pred_neg = torch.bmm(u_neg, v.unsqueeze(2)).squeeze() # (batch_size, k)
# 使用 sigmoid 计算损失
loss = -torch.log(torch.sigmoid(pred) + 1e-8) - \
torch.log(1 - torch.sigmoid(pred_neg) + 1e-8).sum(-1)
return loss.mean()
四、实战教程:从数据准备到模型部署
4.1 项目实战一:图像分类器
让我们完成一个完整的图像分类项目,从数据加载到模型训练再到预测。
Step 1: 准备数据集
import torchvision
from torchvision import transforms
# 定义数据预处理流程
train_augs = transforms.Compose([
transforms.RandomResizedCrop(224), # 随机裁剪
transforms.RandomHorizontalFlip(), # 随机水平翻转
transforms.ToTensor(), # 转换为张量
transforms.Normalize([0.485, 0.456, 0.406], # ImageNet 标准化
[0.229, 0.224, 0.225])
])
test_augs = transforms.Compose([
transforms.Resize(256), # 调整大小
transforms.CenterCrop(224), # 中心裁剪
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406],
[0.229, 0.224, 0.225])
])
# 加载 CIFAR-10 数据集(如果你没有足够的计算资源)
train_iter = torch.utils.data.DataLoader(
torchvision.datasets.CIFAR10(root='./data', train=True,
download=True, transform=train_augs),
batch_size=256, shuffle=True, num_workers=4
)
test_iter = torch.utils.data.DataLoader(
torchvision.datasets.CIFAR10(root='./data', train=False,
download=True, transform=test_augs),
batch_size=256, shuffle=False, num_workers=4
)
Step 2: 构建模型
# 使用预训练的 ResNet-18 作为特征提取器
def load_pretrained_model():
# 加载预训练的 ResNet-18
resnet = torchvision.models.resnet18(pretrained=True)
# 替换最后的分类层(原始 ImageNet 有 1000 类,我们只保留特征)
# 这里保留所有层作为特征提取器
return resnet
model = load_pretrained_model()
# 如果要用于 CIFAR-10,需要调整第一层以适应 32x32 的图像
# 因为 ImageNet 预训练模型的输入是 224x224
Step 3: 定义训练函数
def train_fine_tune(model, train_iter, test_iter, num_epochs, lr, device, lr_period, lr_decay):
# 冻结大部分层,只微调最后的几层
# 或者解冻所有层进行完全微调
# 定义损失函数
loss = nn.CrossEntropyLoss()
# 定义优化器
optimizer = torch.optim.SGD(model.parameters(), lr=lr,
momentum=0.9, weight_decay=5e-4)
# 学习率调度器
scheduler = torch.optim.lr_scheduler.StepLR(optimizer,
step_size=lr_period,
gamma=lr_decay)
def evaluate_accuracy(data_iter, model, device):
model.eval()
metric = d2l.Accumulator(2)
with torch.no_grad():
for X, y in data_iter:
X, y = X.to(device), y.to(device)
y_hat = model(X)
metric.add(d2l.accuracy(y_hat, y), y.shape[0])
return metric[0] / metric[1]
# 训练循环
animator = d2l.Animator(xlabel='epoch', xlim=[1, num_epochs],
legend=['train loss', 'train acc', 'test acc'])
timer = d2l.Timer()
for epoch in range(num_epochs):
model.train()
metric = d2l.Accumulator(3)
for i, (X, y) in enumerate(train_iter):
timer.start()
X, y = X.to(device), y.to(device)
optimizer.zero_grad()
y_hat = model(X)
l = loss(y_hat, y)
l.backward()
optimizer.step()
metric.add(l * X.shape[0], d2l.accuracy(y_hat, y), X.shape[0])
timer.stop()
test_acc = evaluate_accuracy(test_iter, model, device)
scheduler.step()
animator.add(epoch + 1, (metric[0] / metric[2],
metric[1] / metric[2],
test_acc))
print(f'训练完成!')
print(f'最终测试准确率: {test_acc:.4f}')
print(f'总耗时: {timer.sum():.2f} 秒')
Step 4: 执行训练
# 将模型移动到 GPU(如果可用)
device = d2l.try_gpu()
model = model.to(device)
# 开始训练
train_fine_tune(model, train_iter, test_iter,
num_epochs=10, lr=0.001, device=device,
lr_period=3, lr_decay=0.1)
Step 5: 使用模型进行预测
# 保存模型
torch.save(model.state_dict(), 'image_classifier.pth')
# 加载模型进行预测
def predict_image(model, image_path, device):
model.eval()
# 加载并预处理图像
img = Image.open(image_path)
transform = transforms.Compose([
transforms.Resize(256),
transforms.CenterCrop(224),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406],
[0.229, 0.224, 0.225])
])
img_tensor = transform(img).unsqueeze(0).to(device)
# 预测
with torch.no_grad():
output = model(img_tensor)
probabilities = torch.nn.functional.softmax(output[0], dim=0)
predicted_class = torch.argmax(probabilities).item()
confidence = probabilities[predicted_class].item()
return predicted_class, confidence
# 使用示例
# class_id, confidence = predict_image(model, 'test_image.jpg', device)
# print(f"预测类别: {class_id}, 置信度: {confidence:.2%}")
4.2 项目实战二:情感分析
使用循环神经网络或 Transformer 进行文本情感分析。
Step 1: 数据预处理
import os
import re
import torch
from torch.utils.data import DataLoader, Dataset
# 读取 IMDb 电影评论数据集
def read_imdb(data_dir, is_train):
data, labels = [], []
folder = 'train' if is_train else 'test'
for label in ['pos', 'neg']:
folder_name = os.path.join(data_dir, folder, label)
for file in os.listdir(folder_name):
with open(os.path.join(folder_name, file), 'r', encoding='utf-8') as f:
review = f.read().replace('\n', ' ').lower()
review = re.sub(r'[^a-z ]', ' ', review)
data.append(review)
labels.append(1 if label == 'pos' else 0)
return data, labels
# 创建数据集类
class IMDBDataset(Dataset):
def __init__(self, data, labels, vocab, max_len):
self.data = data
self.labels = labels
self.vocab = vocab
self.max_len = max_len
def __len__(self):
return len(self.data)
def __getitem__(self, idx):
review = self.data[idx]
tokens = vocab(self.tokenize(review))
padded = self.pad_truncate(tokens, self.max_len)
return torch.tensor(padded, dtype=torch.long), \
torch.tensor(self.labels[idx], dtype=torch.long)
def tokenize(self, review):
return review.split()
def pad_truncate(self, tokens):
if len(tokens) < self.max_len:
tokens = tokens + [vocab['<pad>']] * (self.max_len - len(tokens))
else:
tokens = tokens[:self.max_len]
return tokens
# 加载数据
train_data, train_labels = read_imdb('./data/aclImdb', is_train=True)
test_data, test_labels = read_imdb('./data/aclImdb', is_train=False)
# 构建词汇表
all_tokens = [token for review in train_data for token in review.split()]
vocab = d2l.Vocab(all_tokens, min_freq=5, reserved_tokens=['<pad>'])
# 创建数据迭代器
train_dataset = IMDBDataset(train_data, train_labels, vocab, 500)
test_dataset = IMDBDataset(test_data, test_labels, vocab, 500)
train_iter = DataLoader(train_dataset, batch_size=64, shuffle=True)
test_iter = DataLoader(test_dataset, batch_size=64, shuffle=False)
Step 2: 构建 BiLSTM 模型
class BiLSTMClassifier(d2l.Module):
def __init__(self, vocab_size, embed_size, num_hiddens,
num_layers, dropout=0.5):
super().__init__()
self.save_hyperparameters()
self.embedding = nn.Embedding(vocab_size, embed_size)
self.encoder = nn.LSTM(embed_size, num_hiddens, num_layers,
bidirectional=True, dropout=dropout,
batch_first=True)
self.decoder = nn.LazyLinear(2)
def forward(self, X):
# X shape: (batch_size, seq_len)
embeddings = self.embedding(X) # (batch_size, seq_len, embed_size)
outputs, (hidden, cell) = self.encoder(embeddings)
# 连接前向和后向的最后一个隐藏状态
encoding = torch.cat((hidden[-2], hidden[-1]), dim=1)
return self.decoder(encoding)
def configure_optimizers(self):
return torch.optim.Adam(self.parameters(), lr=0.001)
Step 3: 训练模型
# 初始化模型
embed_size, num_hiddens, num_layers, dropout = 100, 100, 2, 0.5
model = BiLSTMClassifier(len(vocab), embed_size, num_hiddens,
num_layers, dropout)
model = model.to(device)
# 训练函数
@d2l.add_to_class(BiLSTMClassifier)
def configure_optimizers(self):
return torch.optim.Adam(self.parameters(), lr=0.001)
@d2l.add_to_class(BiLSTMClassifier)
def loss(self, y_hat, y):
return nn.CrossEntropyLoss()(y_hat, y)
# 开始训练
trainer = d2l.Trainer(max_epochs=10)
trainer.fit(model, train_iter)
4.3 项目实战三:目标检测
使用预训练的 SSD 模型进行目标检测。
# 使用预训练的 SSD 模型进行推理
import torchvision.models.detection as detection
import torchvision.transforms as T
# 加载预训练的 SSD300 模型
model = detection.ssd300_vgg16(pretrained=True)
model.eval()
# 定义图像预处理
transform = T.Compose([
T.ToTensor()
])
def detect_objects(image_path, confidence_threshold=0.5):
# 加载图像
img = Image.open(image_path).convert('RGB')
img_tensor = transform(img).unsqueeze(0)
# 检测
with torch.no_grad():
predictions = model(img_tensor)[0]
# 过滤低置信度的检测结果
keep = predictions['scores'] > confidence_threshold
boxes = predictions['boxes'][keep]
labels = predictions['labels'][keep]
scores = predictions['scores'][keep]
return boxes, labels, scores
# 可视化检测结果
def visualize_detections(image_path, boxes, labels, scores, class_names):
img = Image.open(image_path).convert('RGB')
img = img.copy()
draw = ImageDraw.Draw(img)
for box, label, score in zip(boxes, labels, scores):
# 绘制边界框
draw.rectangle(list(box), outline='red', width=3)
# 添加标签
label_text = f"{class_names[label]}: {score:.2f}"
draw.text((box[0], box[1] - 10), label_text, fill='red')
plt.figure(figsize=(12, 8))
plt.imshow(img)
plt.axis('off')
plt.savefig('detection_result.jpg', bbox_inches='tight')
# COCO 数据集的类别名称(部分)
COCO_CLASSES = [
'__background__', 'person', 'bicycle', 'car', 'motorcycle', 'airplane',
'bus', 'train', 'truck', 'boat', 'traffic light', 'fire hydrant',
'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse',
'sheep', 'cow', 'elephant', 'bear', 'zebra', 'giraffe', 'backpack',
'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', 'skis', 'snowboard',
'sports ball', 'kite', 'baseball bat', 'baseball glove', 'skateboard',
'surfboard', 'tennis racket', 'bottle', 'wine glass', 'cup', 'fork',
'knife', 'spoon', 'bowl', 'banana', 'apple', 'sandwich', 'orange',
'broccoli', 'carrot', 'hot dog', 'pizza', 'donut', 'cake', 'chair',
'couch', 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop',
'mouse', 'remote', 'keyboard', 'cell phone', 'microwave', 'oven',
'toaster', 'sink', 'refrigerator', 'book', 'clock', 'vase', 'scissors',
'teddy bear', 'hair drier', 'toothbrush'
]
# 执行检测
boxes, labels, scores = detect_objects('test_image.jpg', confidence_threshold=0.5)
visualize_detections('test_image.jpg', boxes, labels, scores, COCO_CLASSES)
五、常见应用场景
5.1 时间序列预测
使用 LSTM 预测股票价格或能源消耗:
class TimeSeriesPredictor(d2l.Module):
def __init__(self, num_inputs, num_hiddens, num_layers, dropout=0.1):
super().__init__()
self.num_hiddens = num_hiddens
self.num_layers = num_layers
self.lstm = nn.LSTM(num_inputs, num_hiddens, num_layers,
dropout=dropout, batch_first=True)
self.fc = nn.Linear(num_hiddens, 1)
def forward(self, X):
# X shape: (batch_size, seq_len, features)
lstm_out, _ = self.lstm(X)
# 只取最后一个时间步的输出
prediction = self.fc(lstm_out[:, -1, :])
return prediction
# 准备滑动窗口数据
def create_sequences(data, window_size):
X, y = [], []
for i in range(len(data) - window_size):
X.append(data[i:i+window_size])
y.append(data[i+window_size])
return np.array(X), np.array(y)
# 训练模型进行能源消耗预测
energy_data = np.random.randn(1000) # 替换为真实数据
X, y = create_sequences(energy_data, window_size=24)
# ... 后续训练代码
5.2 图像生成(GAN)
# 简单的 DCGAN 实现
class Generator(nn.Module):
def __init__(self, noise_dim, img_shape):
super().__init__()
self.img_shape = img_shape
self.net = nn.Sequential(
nn.Linear(noise_dim, 128 * 8 * 8),
nn.ReLU(),
nn.Unflatten(1, (128, 8, 8)),
nn.ConvTranspose2d(128, 128, 4, 2, 1, bias=False),
nn.BatchNorm2d(128),
nn.ReLU(),
nn.ConvTranspose2d(128, 64, 4, 2, 1, bias=False),
nn.BatchNorm2d(64),
nn.ReLU(),
nn.ConvTranspose2d(64, 64, 4, 2, 1, bias=False),
nn.BatchNorm2d(64),
nn.ReLU(),
nn.ConvTranspose2d(64, 3, 4, 2, 1, bias=False),
nn.Tanh()
)
def forward(self, z):
return self.net(z)
class Discriminator(nn.Module):
def __init__(self, img_shape):
super().__init__()
self.net = nn.Sequential(
nn.Conv2d(3, 64, 4, 2, 1),
nn.LeakyReLU(0.2),
nn.Conv2d(64, 128, 4, 2, 1),
nn.BatchNorm2d(128),
nn.LeakyReLU(0.2),
nn.Conv2d(128, 256, 4, 2, 1),
nn.BatchNorm2d(256),
nn.LeakyReLU(0.2),
nn.Flatten(),
nn.Linear(256 * 4 * 4, 1),
nn.Sigmoid()
)
def forward(self, x):
return self.net(x)
# 训练循环
def train_gan(generator, discriminator, dataloader, epochs, latent_dim, device):
criterion = nn.BCELoss()
g_optimizer = torch.optim.Adam(generator.parameters(), lr=0.0002)
d_optimizer = torch.optim.Adam(discriminator.parameters(), lr=0.0002)
for epoch in range(epochs):
for real_images, _ in dataloader:
real_images = real_images.to(device)
batch_size = real_images.size(0)
# 训练判别器
d_optimizer.zero_grad()
real_labels = torch.ones(batch_size, 1).to(device)
fake_labels = torch.zeros(batch_size, 1).to(device)
outputs = discriminator(real_images)
d_loss_real = criterion(outputs, real_labels)
noise = torch.randn(batch_size, latent_dim).to(device)
fake_images = generator(noise)
outputs = discriminator(fake_images.detach())
d_loss_fake = criterion(outputs, fake_labels)
d_loss = d_loss_real + d_loss_fake
d_loss.backward()
d_optimizer.step()
# 训练生成器
g_optimizer.zero_grad()
noise = torch.randn(batch_size, latent_dim).to(device)
fake_images = generator(noise)
outputs = discriminator(fake_images)
g_loss = criterion(outputs, real_labels)
g_loss.backward()
g_optimizer.step()
print(f"Epoch [{epoch+1}/{epochs}], "
f"d_loss: {d_loss.item():.4f}, g_loss: {g_loss.item():.4f}")
5.3 语义分割
# 使用 FCN(全卷积网络)进行图像语义分割
class FCN(d2l.Module):
def __init__(self, num_classes):
super().__init__()
# 使用 VGG16 作为编码器(预训练)
vgg = torchvision.models.vgg16(pretrained=True).features
self.encoder = nn.ModuleList(list(vgg.children()))
# 解码器(转置卷积)
self.decoder = nn.Sequential(
nn.ConvTranspose2d(512, 256, kernel_size=4, stride=2, padding=1),
nn.ReLU(),
nn.ConvTranspose2d(256, 128, kernel_size=4, stride=2, padding=1),
nn.ReLU(),
nn.ConvTranspose2d(128, 64, kernel_size=4, stride=2, padding=1),
nn.ReLU(),
nn.ConvTranspose2d(64, 32, kernel_size=4, stride=2, padding=1),
nn.ReLU(),
nn.ConvTranspose2d(32, num_classes, kernel_size=4, stride=2, padding=1)
)
def forward(self, x):
# 编码
features = []
for i, layer in enumerate(self.encoder):
x = layer(x)
if i in [4, 9, 16, 23]:
features.append(x)
# 解码
x = features[-1]
x = self.decoder(x)
# 上采样到原始图像大小
x = nn.functional.interpolate(x, size=(224, 224), mode='bilinear')
return x
六、技巧与最佳实践
6.1 代码效率优化
使用 GPU 加速训练
def try_all_gpus():
"""返回所有可用的 GPU 设备"""
devices = [torch.device(f'cuda:{i}')
for i in range(torch.cuda.device_count())]
return devices if devices else [torch.device('cpu')]
# 数据并行训练
def train_with_multiple_gpus(model, train_iter, num_epochs, lr, devices):
model = nn.DataParallel(model, device_ids=devices).to(devices[0])
optimizer = torch.optim.Adam(model.parameters(), lr=lr)
loss = nn.CrossEntropyLoss()
for epoch in range(num_epochs):
model.train()
for X, y in train_iter:
X, y = X.to(devices[0]), y.to(devices[0])
optimizer.zero_grad()
l = loss(model(X), y)
l.backward()
optimizer.step()
print(f"Epoch {epoch+1} 完成")
混合精度训练
from torch.cuda.amp import autocast, GradScaler
def train_with_amp(model, train_iter, optimizer, scheduler, num_epochs, device):
scaler = GradScaler()
for epoch in range(num_epochs):
model.train()
for i, (X, y) in enumerate(train_iter):
X, y = X.to(device), y.to(device)
optimizer.zero_grad()
# 启用自动混合精度
with autocast():
output = model(X)
loss = nn.CrossEntropyLoss()(output, y)
# 使用 scaler 处理梯度
scaler.scale(loss).backward()
scaler.step(optimizer)
scaler.update()
if i % 100 == 0:
print(f"Step {i}, Loss: {loss.item():.4f}")
scheduler.step()
print(f"Epoch {epoch+1} 完成")
6.2 模型调试技巧
检查梯度是否正常
def check_gradients(model):
"""检查模型各层梯度的统计信息"""
for name, param in model.named_parameters():
if param.grad is not None:
grad_norm = param.grad.norm().item()
print(f"{name}: grad_norm = {grad_norm:.6f}")
if grad_norm > 10 or grad_norm < 1e-6:
print(f" 警告: 梯度异常!")
使用 TensorBoard 可视化训练过程
from torch.utils.tensorboard import SummaryWriter
def train_with_tensorboard(model, train_iter, optimizer, num_epochs, log_dir):
writer = SummaryWriter(log_dir)
for epoch in range(num_epochs):
model.train()
total_loss = 0
for i, (X, y) in enumerate(train_iter):
optimizer.zero_grad()
output = model(X)
loss = nn.CrossEntropyLoss()(output, y)
loss.backward()
optimizer.step()
total_loss += loss.item()
# 记录标量
global_step = epoch * len(train_iter) + i
writer.add_scalar('Loss/train', loss.item(), global_step)
avg_loss = total_loss / len(train_iter)
writer.add_scalar('Loss/epoch', avg_loss, epoch)
# 记录模型参数分布
for name, param in model.named_parameters():
writer.add_histogram(f'Param/{name}', param.data, epoch)
writer.close()
# 使用示例
# writer = SummaryWriter('./runs/experiment_1')
# train_with_tensorboard(model, train_iter, optimizer, 10, './runs/experiment_1')
# 在终端运行: tensorboard --logdir=./runs
6.3 超参数调优
# 使用 Optuna 进行超参数搜索
import optuna
from optuna.trial import Trial
def objective(trial: Trial):
# 定义要优化的超参数
lr = trial.suggest_float('lr', 1e-5, 1e-1, log=True)
batch_size = trial.suggest_categorical('batch_size', [32, 64, 128, 256])
num_layers = trial.suggest_int('num_layers', 1, 4)
hidden_size = trial.suggest_categorical('hidden_size', [64, 128, 256, 512])
# 创建模型
model = MyModel(num_layers=num_layers, hidden_size=hidden_size)
optimizer = torch.optim.Adam(model.parameters(), lr=lr)
# 训练和评估
train_iter = DataLoader(train_dataset, batch_size=batch_size)
val_acc = train_and_evaluate(model, train_iter, val_iter, optimizer)
return val_acc
# 运行优化
study = optuna.create_study(direction='maximize')
study.optimize(objective, n_trials=100)
print(f"最佳参数: {study.best_params}")
print(f"最佳验证准确率: {study.best_value:.4f}")
6.4 模型保存与加载的最佳实践
# 保存整个模型
torch.save(model, 'full_model.pth')
# 推荐:只保存模型参数(更轻量,跨框架兼容性好)
torch.save(model.state_dict(), 'model_weights.pth')
# 保存完整检查点(包含优化器状态,便于恢复训练)
checkpoint = {
'epoch': epoch,
'model_state_dict': model.state_dict(),
'optimizer_state_dict': optimizer.state_dict(),
'loss': loss,
'best_accuracy': best_acc,
}
torch.save(checkpoint, 'checkpoint.pth')
# 加载模型
# 方法一:加载完整模型
loaded_model = torch.load('full_model.pth')
# 方法二:加载参数到模型
model = MyModel()
model.load_state_dict(torch.load('model_weights.pth'))
# 恢复训练
checkpoint = torch.load('checkpoint.pth')
model.load_state_dict(checkpoint['model_state_dict'])
optimizer.load_state_dict(checkpoint['optimizer_state_dict'])
start_epoch = checkpoint['epoch'] + 1
best_acc = checkpoint['best_accuracy']
6.5 代码组织结构建议
对于实际项目,推荐以下目录结构:
project/
├── config/ # 配置文件
│ ├── model_config.py
│ └── train_config.py
├── data/ # 数据目录
│ ├── raw/
│ ├── processed/
│ └── dataloaders.py
├── models/ # 模型定义
│ ├── __init__.py
│ ├── base.py
│ ├── classifier.py
│ └── backbone.py
├── utils/ # 工具函数
│ ├── __init__.py
│ ├── logger.py
│ └── metrics.py
├── train.py # 训练脚本
├── evaluate.py # 评估脚本
├── predict.py # 预测脚本
├── requirements.txt
└── README.md
七、进阶学习资源与项目推荐
7.1 相关优秀项目
与 D2L 配套的实践项目
| 项目名称 | GitHub 地址 | 说明 |
|---|---|---|
| d2l-zh (中文版) | github.com/d2l-ai/d2l-zh | D2L 官方中文翻译版 |
| pytorch-image-models | github.com/rwightman/pytorch-image-models | PyTorch 图像模型库 |
| transformers | github.com/huggingface/transformers | 预训练 Transformer 模型 |
| mmdetection | github.com/open-mmlab/mmdetection | 目标检测工具箱 |
| detectron2 | github.com/facebookresearch/detectron2 | Facebook 的检测框架 |
7.2 学习路径建议
入门阶段(1-2个月)
Week 1-2: 阅读第1-4章,完成线性回归和 Softmax 回归的代码实现
Week 3-4: 学习第5-8章,理解 MLP 和 CNN 的原理
Week 5-6: 完成第9-10章,实现基础的 RNN/LSTM 模型
Week 7-8: 学习第11-12章,理解注意力机制和 Transformer
进阶阶段(2-3个月)
Month 2: 完成图像分类、目标检测的实战项目
Month 3: 实现文本分类、情感分析、机器翻译等项目
高级阶段(持续学习)
深入研究 Diffusion Model、Vision Transformer、Large Language Model
参与开源项目贡献
复现顶会论文
7.3 官方资源链接
官方文档: https://d2l.ai/
中文官网: https://zh.d2l.ai/
GitHub 仓库: https://github.com/d2l-ai/d2l-en
中文仓库: https://github.com/d2l-ai/d2l-zh
讨论区: https://discuss.d2l.ai/
八、总结
D2L(动手学深度学习)不仅仅是一本书,更是一个完整的深度学习学习生态系统。从基础理论到前沿实践,从学术研究到工业应用,这本书涵盖了深度学习的方方面面。
核心价值总结:
✦ 系统性:完整的知识体系,从入门到精通
✦ 实用性:每一章都有可运行的代码示例
✦ 前沿性:涵盖 Transformer、Diffusion 等最新技术
✦ 多框架:支持 PyTorch、TensorFlow、JAX 等主流框架
✦ 开源性:完全免费,持续更新
✦ 社区活跃:有问题可以在讨论区获得解答
无论你是深度学习的新手,还是希望系统梳理知识体系的从业者,D2L 都是一个不可多得的优质资源。现在就打开 GitHub 仓库,开始你的深度学习之旅吧!
如果你觉得这篇文章对你有帮助,欢迎:
- 给 D2L 仓库点个 Star
- 收藏本文以便后续查阅
- 将文章分享给正在学习 AI 的朋友
下一步行动:
# 1. 克隆仓库
git clone https://github.com/d2l-ai/d2l-en.git
# 2. 安装依赖
pip install d2l
# 3. 启动 Jupyter Notebook
jupyter notebook
# 4. 开始学习第一章!
祝你学习愉快! 🚀
评论区