- 文档
- 教程
- 人工智能
- 深度学习
- NLP
- 计算机视觉
- 强化学习
【免费下载链接】d2l-en
Interactive deep learning book with multi-framework code, math, and discussions. Adopted at 500 universities from 70 countries including Stanford, MIT, Harvard, and Cambridge.
本文深入解析《动手学深度学习》(d2l-en)附录工具章节(:label:sec_utils)中集中收录的一批核心工具函数与工具类。这些工具承担着超参数自动保存、训练过程动画绘制、数据集下载与加载、GPU 训练评估、NLP 序列处理以及强化学习环境封装等职责,是全书各章示例代码共同依赖的基础设施。读完本文,你将能够理解这些工具的实现原理,掌握其调用方式与参数含义,并能基于 d2l 包源码 在自己的深度学习实验中复用这套高效的工具管线。
工具的定位:全书代码的基础设施
本书每一章的代码示例都大量调用形如d2l.load_array、d2l.Accumulator、d2l.Animator、d2l.train_ch6的接口。这些接口并非散布在各章重复定义,而是集中收敛在本节(:numref:sec_utils)以及对应的 d2l 包源码 中,通过#@save标记持久化到d2l包,供后续章节按需引用。完整的类与函数清单(按字母序、标注了定义章节)可参阅 d2l API 文档。
在四个深度学习框架(MXNet、PyTorch、TensorFlow、JAX)之间,这些工具保持了同名同语义的设计,仅在底层实现上有差异。例如save_hyperparameters与ProgressBoard.draw在 d2l/torch.py 与 d2l/jax.py 中的实现完全一致,体现了全书"多框架、同一套 API"的编写理念。
超参数管理:save_hyperparameters 与 add_to_class
一键保存构造参数的 save_hyperparameters
HyperParameters是所有模型与数据类(Module、DataModule、Trainer等)的公共基类。其核心方法save_hyperparameters利用 Python 的inspect模块,把调用者(通常是__init__)的局部变量自动保存为类属性:
@d2l.add_to_class(d2l.HyperParameters) #@save def save_hyperparameters(self, ignore=[]): """Save function arguments into class attributes.""" frame = inspect.currentframe().f_back _, _, _, local_vars = inspect.getargvalues(frame) self.hparams = {k:v for k, v in local_vars.items() if k not in set(ignore+['self']) and not k.startswith('_')} for k, v in self.hparams.items(): setattr(self, k, v)其工作机理可拆解为三步:
inspect.currentframe().f_back获取调用栈上一层(即__init__方法)的栈帧;inspect.getargvalues(frame)提取该方法的全部局部变量,过滤掉self、以下划线_开头的临时变量以及ignore列表中显式排除的参数;- 将剩余参数同时写入
self.hparams字典和实例属性,使self.lr、self.batch_size等可直接访问。
ignore参数用于排除不需要保存的变量(例如派生属性、依赖外部资源的对象),且过滤条件not k.startswith('_')自动丢弃_前缀的临时变量,避免污染属性命名空间。这一设计与 d2l/torch.py 中HyperParameters的实现完全一致。
扩展类的 add_to_class
save_hyperparameters通过装饰器@d2l.add_to_class(d2l.HyperParameters)注入基类,其实现(d2l/torch.py)本质上是对setattr的封装:
def add_to_class(Class): """Register functions as methods in created class.""" def wrapper(obj): setattr(Class, obj.__name__, obj) return wrapper这种"运行时向已有类追加方法"的注册机制,是全书在保持d2l包最小化的同时、按章节渐进式扩展 API 的关键手段——例如 chapter_builders-guide/oo-design.md 中提出的面向对象设计,以及 chapter_preliminaries/ndarray.md 对张量 API 的封装,都依赖这一机制。
训练可视化:ProgressBoard.draw、Animator 与 Accumulator
ProgressBoard.draw:动画式进度绘制
ProgressBoard维护训练过程的实时曲线。其draw方法(:numref:sec_utils中定义为ProgressBoard的方法)通过collections.OrderedDict按标签累积原始点,并按every_n聚合后取均值再绘制,从而在避免频繁刷新 matplotlib 的前提下保持曲线平滑:
@d2l.add_to_class(d2l.ProgressBoard) #@save def draw(self, x, y, label, every_n=1): Point = collections.namedtuple('Point', ['x', 'y']) if not hasattr(self, 'raw_points'): self.raw_points = collections.OrderedDict() self.data = collections.OrderedDict() if label not in self.raw_points: self.raw_points[label] = [] self.data[label] = [] points = self.raw_points[label] line = self.data[label] points.append(Point(x, y)) if len(points) != every_n: return mean = lambda x: sum(x) / len(x) line.append(Point(mean([p.x for p in points]), mean([p.y for p in points]))) points.clear() if not self.display: return d2l.use_svg_display() if self.fig is None: self.fig = d2l.plt.figure(figsize=self.figsize) plt_lines, labels = [], [] for (k, v), ls, color in zip(self.data.items(), self.ls, self.colors): plt_lines.append(d2l.plt.plot([p.x for p in v], [p.y for p in v], linestyle=ls, color=color)[0]) labels.append(k) axes = self.axes if self.axes else d2l.plt.gca() if self.xlim: axes.set_xlim(self.xlim) if self.ylim: axes.set_ylim(self.ylim) if not self.xlabel: self.xlabel = self.x axes.set_xlabel(self.xlabel) axes.set_ylabel(self.ylabel) axes.set_xscale(self.xscale) axes.set_yscale(self.yscale) axes.legend(plt_lines, labels) display.display(self.fig) display.clear_output(wait=True)关键设计点:
- 降频采样:
every_n控制多少原始点聚合为一个均值点,Module.plot会结合每个 epoch 内的批次数自动计算该值(见 d2l/torch.py); - 增量刷新:
display.display与display.clear_output(wait=True)配合,实现 Jupyter 中"原地更新"的动画效果; - 样式参数:线型
ls默认['-', '--', '-.', ':'],颜色colors默认['C0', 'C1', 'C2', 'C3'],坐标轴默认线性刻度(xscale/yscale='linear'),均可通过ProgressBoard构造参数覆盖(d2l/torch.py)。
Module(模型基类)内部创建self.board = ProgressBoard(),Trainer.fit在训练时通过training_step/validation_step调用board.draw分别绘制train_与val_前缀的曲线(d2l/torch.py),这正是全书各章训练曲线动画的底层来源。
Animator 与 Accumulator
Animator(仅 PyTorch / MXNet / TensorFlow 提供)是对ProgressBoard更轻量的封装:构造时接收xlabel/ylabel/legend/xlim/ylim/xscale/yscale、线型格式fmts(默认('-', 'm--', 'g-.', 'r:'))与figsize,通过add(x, y)追加数据点并配合display.clear_output(wait=True)实现动画重绘。它适合无需精细控制every_n的场景。
Accumulator用于跨批次累加统计量(损失和、正确数、样本数等):
class Accumulator: #@save """For accumulating sums over `n` variables.""" def __init__(self, n): self.data = [0.0] * n def add(self, *args): self.data = [a + float(b) for a, b in zip(self.data, args)] def reset(self): self.data = [0.0] * len(self.data) def __getitem__(self, idx): return self.data[idx]reset()将计数清零,add(*args)支持一次累加多个变量,配合索引访问,是train_ch6、train_seq2seq等训练函数统计 loss 与准确率的标准工具。
数据处理:合成数据、数据集加载与文件下载
合成数据与数据迭代器
synthetic_data(w, b, num_examples)按y = Xw + b + noise生成带噪声的线性回归数据,噪声标准差为 0.01,是 chapter_linear-regression/linear-regression-scratch.md 等章节的示例数据源。
load_array(data_arrays, batch_size, is_train=True)将数组元组包装为数据迭代器,各框架实现不同:
- PyTorch:
torch.utils.data.TensorDataset+DataLoader,is_train=True时打乱; - MXNet:
gluon.data.ArrayDataset+DataLoader; - TensorFlow:
tf.data.Dataset.from_tensor_slices,训练时shuffle(buffer_size=1000)后batch。
Fashion-MNIST 加载
load_data_fashion_mnist(batch_size, resize=None)下载并加载 Fashion-MNIST:
- 默认变换为
ToTensor(),若指定resize则在最前插入Resize(resize)缩放; - PyTorch 实现将数据缓存到
root="../data";MXNet 通过transform_first仅对数据变换、标签保持原样; - 读取线程数由
get_dataloader_workers()决定:PyTorch 恒为 4,MXNet 在 Windows 上返回 0、其余平台返回 4。
通用下载与解压:download / extract / download_extract
download(url, folder='../data', sha1_hash=None)支持两种调用形态:
- 直接传入
httpURL; - 传入
DATA_HUB中的注册名(为向后兼容而保留),此时自动解析为(url, sha1_hash)二元组。
实现要点(对应 d2l/torch.py):
- 使用
os.makedirs(folder, exist_ok=True)确保目录存在,文件名取 URL 最后一段; - SHA-1 缓存校验:若本地文件已存在且提供
sha1_hash,按 1MB 分块计算 SHA-1,一致则直接返回缓存路径、跳过下载; - 否则通过
requests.get(url, stream=True, verify=True)下载并写盘。
extract(filename, folder=None)仅支持.zip、.tar、.gz三种后缀,未指定folder时解压到文件所在目录。download_extract(name, folder=None)将二者串联:下载后自动解压,返回解压目录(folder非空时返回base_dir/folder,否则返回去掉后缀的数据目录)。DATA_HUB字典与DATA_URL(http://d2l-data.s3-accelerate.amazonaws.com/)在 d2l/torch.py 定义,全书用到的数据集(如airfoil、hotdog、glove.6b.50d、fra-eng等)均注册其中。
训练与评估:sgd、train_ch6、grad_clipping
手写小批量 SGD
sgd(params, lr, batch_size)实现无框架优化器的手写小批量随机梯度下降。注意三框架的梯度清零策略不同:PyTorch 在更新后显式调用param.grad.zero_(),MXNet 直接原地更新参数,TensorFlow 版本则签名改为sgd(params, grads, lr, batch_size)、通过param.assign_sub(lr * grad / batch_size)更新。
GPU 训练通用流程 train_ch6
train_ch6(PyTorch/MXNet 版本)与TrainCallback(TensorFlow 版本)是第 6 章(卷积神经网络)起复用的训练骨架,统一了初始化、优化器、动画与吞吐统计:
- PyTorch:
init_weights对nn.Linear/nn.Conv2d施以 Xavier 均匀初始化;net.apply(init_weights)递归应用;优化器为torch.optim.SGD(net.parameters(), lr=lr),损失为nn.CrossEntropyLoss();每轮训练后调用evaluate_accuracy_gpu计算测试准确率,并输出examples/sec吞吐; - MXNet:
net.initialize(force_reinit=True, ctx=device, init=init.Xavier())+gluon.Trainer(net.collect_params(), 'sgd', ...),autograd.record()记录计算图; - TensorFlow:通过
tf.distribute.OneDeviceStrategy将网络置于指定设备,net.fit配合自定义TrainCallback回调在每 epoch 结束绘制 train loss / train acc / test acc 三条曲线,并在最后一个 epoch 打印吞吐。
evaluate_accuracy_gpu(net, data_iter, device=None)的关键行为:
device=None时自动探测:PyTorch 取next(iter(net.parameters())).device,MXNet 取首个参数所在 context;- PyTorch 版本会先
net.eval()切换评估模式,并在torch.no_grad()下逐批前向,支持 BERT 微调所需的list输入(逐元素.to(device)); - 结果用
Accumulator(2)统计正确数与样本数,返回二者比值。
梯度裁剪 grad_clipping
grad_clipping按全参数梯度的 L2 范数进行裁剪:当范数超过阈值theta时,将所有梯度按theta/norm等比缩放。各框架参数形态不同:
- PyTorch:
params = [p for p in net.parameters() if p.requires_grad],范数经torch.sqrt(sum(torch.sum((p.grad ** 2)) ...))计算; - MXNet:对
gluon.Block取collect_params(),对普通网络取net.params; - TensorFlow:签名改为
grad_clipping(grads, theta),先统一tf.IndexedSlices为稠密张量再计算范数,返回裁剪后的梯度列表。
此外evaluate_loss(net, data_iter, loss)用Accumulator(2)统计"损失和 / 样本数"得到平均损失,供训练过程监控验证集损失使用。
NLP 工具链:分词、词表与 NMT 数据管线
通用文本工具
tokenize(lines, token='word'):按词(line.split())或按字符(list(line))切分文本行;Vocab(在 chapter_recurrent-neural-networks/text-sequence.md 中定义,实现于 d2l/torch.py):以collections.Counter统计词频,按频率降序构造idx_to_token与token_to_idx双向映射,支持min_freq过滤低频词、reserved_tokens保留<unk>等特殊记号,未登录词统一映射到self.unk;truncate_pad(line, num_steps, padding_token):序列超过num_steps截断,不足则用padding_token填充。
英法机器翻译数据管线
本节为注意力与 Seq2Seq 章节准备了完整的英法翻译数据管线,其中fra-eng数据集的 URL 与 SHA-1 校验值被注册进DATA_HUB:
d2l.DATA_HUB['fra-eng'] = (d2l.DATA_URL + 'fra-eng.zip', '94646ad1522d915e7b0f9296181140edcf86a4f5')read_data_nmt():d2l.download_extract('fra-eng')下载解压后读取fra.txt;preprocess_nmt(text):将非断行空格\u202f、\xa0替换为普通空格,全文转小写,并在标点(,.!?)前插入空格实现词与标点的分离;tokenize_nmt(text, num_examples=None):按\t分隔源语言与目标语言行,切分为词列表;num_examples限制样本数(训练默认 600);build_array_nmt(lines, vocab, num_steps):词索引化、追加<eos>、经truncate_pad填充到num_steps,同时用array != vocab['<pad>']计算每句的valid_len(有效长度),供后续掩码使用;load_data_nmt(batch_size, num_steps, num_examples=600):串联上述步骤,以min_freq=2、reserved_tokens=['<pad>', '<bos>', '<eos>']构建源/目标词表,最终返回(data_iter, src_vocab, tgt_vocab)。
Seq2Seq 训练与推理:掩码损失与自回归预测
掩码工具与 MaskedSoftmaxCELoss
sequence_mask(X, valid_len, value=0)将序列中超过valid_len的位置置为value:PyTorch 用torch.arange(maxlen)[None, :] < valid_len[:, None]构造布尔掩码;TensorFlow 版本额外处理三维张量(在最后一维前扩展掩码维度)。MXNet 直接使用npx.sequence_mask。
MaskedSoftmaxCELoss继承各框架的交叉熵损失,利用valid_len屏蔽填充位置的损失:
- PyTorch:
weights = sequence_mask(weights, valid_len)后设置reduction='none',将pred转置为(batch, vocab, steps)计算未加权损失,再乘掩码并对步长维求均值; - MXNet:
npx.sequence_mask(weights, valid_len, True, axis=1)构造权重后交给gluon.loss.SoftmaxCELoss; - TensorFlow:构造时传入
valid_len,内部以tf.one_hot将标签转为 one-hot 后计算CategoricalCrossentropy(from_logits=True),同样按掩码加权后对步长维取均值。
train_seq2seq 与 predict_seq2seq
train_seq2seq(net, data_iter, lr, num_epochs, tgt_vocab, device)封装了序列到序列模型的训练:
- 输入批
(X, X_valid_len, Y, Y_valid_len);解码器输入采用Teacher forcing:dec_input = concat([bos, Y[:, :-1]], 1),即用tgt_vocab['<bos>']作为句首标记拼接目标序列(去掉最后一个词); - PyTorch 版以
net.apply(xavier_init_weights)做 Xavier 初始化(含 GRU 权重),优化器为 Adam,损失为MaskedSoftmaxCELoss,每轮经d2l.grad_clipping(net, 1)裁剪梯度; - MXNet 版在
autograd.record()内前向并反向,trainer.step(num_tokens)按 token 数缩放梯度; - TensorFlow 版在
tf.GradientTape()中前向,d2l.grad_clipping(gradients, 1)裁剪后由 Adam 应用; - 训练损失按"损失和 / 有效 token 数"统计,并输出
tokens/sec吞吐。
predict_seq2seq(net, src_sentence, src_vocab, tgt_vocab, num_steps, device, save_attention_weights=False)实现自回归式推理:源句分词追加<eos>后截断/填充至num_steps,经编码器得到enc_outputs与dec_state;随后循环至多num_steps步,每一步取解码器输出中概率最大的 token作为下一步输入(Y.argmax),命中<eos>即停止;save_attention_weights=True时可收集每步的注意力权重用于可视化(在注意力章节使用)。
强化学习环境工具:FrozenLake 封装与价值函数可视化
本节(PyTorch tab)还收录了强化学习章节使用的 Gym 环境工具:
frozen_lake(seed):创建FrozenLake-v1(is_slippery=False,即非滑冰、确定性转移)环境并完成播种(env.seed、env.action_space.np_random.seed、env.action_space.seed),随后抽取env.desc(网格语义描述)、env.nS(状态数)、env.nA(动作数),并将env.P中的转移字典(s, a) -> [(p, s', r, done), ...]整理为env_info['mdp'],同时记录各条目的索引含义(trans_prob_idx=0、nextstate_idx=1、reward_idx=2、done_idx=3);make_env(name='', seed=0):当前仅支持'FrozenLake-v1'(值迭代章节的唯一环境),其余名称抛出ValueError;show_value_function_progress(env_desc, V, pi)与show_Q_function_progress(env_desc, V_all, pi_all):将每个迭代步的价值函数V(形状[num_iters, num_states])以 4×4 网格的热图(cmap="bone")逐一绘制为子图;H(洞)、G(目标)格子以不同颜色标注,其余格子按策略pi以红色箭头标注动作方向(动作编码:LEFT=0、DOWN=1、RIGHT=2、UP=3);Q 函数版本先对迭代步进行 10 倍稀疏采样再可视化,控制子图数量。
其余常用小工具
show_images(imgs, num_rows, num_cols, titles=None, scale=1.5):按(num_cols*scale, num_rows*scale)的画布批量绘制图片网格,隐藏坐标轴并可选添加标题;linreg(X, w, b)/squared_loss(y_hat, y):线性回归模型与平方损失((y_hat - y)^2 / 2),用于手写实现章节;get_fashion_mnist_labels(labels):将 Fashion-MNIST 类别索引映射为['t-shirt', 'trouser', 'pullover', 'dress', 'coat', 'sandal', 'shirt', 'sneaker', 'bag', 'ankle boot']文本标签;accuracy(y_hat, y):多分类时对y_hat取argmax(axis=1)并与y比较,返回正确预测的个数;- 绘图基础设施
use_svg_display()(切换 Jupyter SVG 输出)、set_figsize、set_axes、plot(见 d2l/torch.py); - 设备工具
cpu()、gpu(i)、num_gpus()、try_gpu(i)、try_all_gpus()(d2l/torch.py):try_gpu在指定 GPU 不存在时回退 CPU,是各章代码"无 GPU 也能跑"的关键保障; Timer(d2l/torch.py):记录多次运行时间,提供start/stop/avg/sum/cumsum,用于吞吐(examples/sec、tokens/sec)统计。
小结
本节工具构成了一套跨 MXNet、PyTorch、TensorFlow、JAX 四个框架高度一致的深度学习基础设施:save_hyperparameters+add_to_class奠定了全书面向对象建模的基座,ProgressBoard/Animator/Accumulator支撑起训练过程的可视化与统计,download/extract/DATA_HUB提供了带 SHA-1 校验的数据获取机制,train_ch6/train_seq2seq等则把初始化、优化、评估与动画封装为可复用的训练骨架。理解这些工具的实现细节,不仅能帮助读者读懂全书各章代码,也能直接迁移到自己的实验项目中,减少重复造轮子的成本。
- 文档
- 教程
- 人工智能
- 深度学习
- NLP
- 计算机视觉
- 强化学习
【免费下载链接】d2l-en
Interactive deep learning book with multi-framework code, math, and discussions. Adopted at 500 universities from 70 countries including Stanford, MIT, Harvard, and Cambridge.
相关推荐
YimMenu:开启GTA V游戏新体验的终极工具箱 🎮
YimMenu:开启GTA V游戏新体验的终极工具箱 🎮 你是否厌倦了GTA V中的各种限制和崩溃问题?想要在洛圣都自由探索,却总是被游戏机制束缚?今天我要向
逆向工程游戏开发如何用BooruDatasetTagManager轻松管理AI训练数据集?超实用标签编辑工具详解
如何用BooruDatasetTagManager轻松管理AI训练数据集?超实用标签编辑工具详解 在AI图像模型训练中,高质量的标签数据直接决定模型效果。今天为
数据标注桌面应用人工智能如何用AgentScope智能体框架,3步跑出一个能看到、可信任的AI Agent
如何用AgentScope智能体框架,3步跑出一个能看到、可信任的AI Agent 想让 AI 替你改代码、跑命令,你敢放手吗?问题不是它会不会,而是你看不见它
人工智能大模型AI Agent多智能体Agent 框架Agent 编排工具调用RAGMCP 服务语音
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考