文档教程人工智能深度学习NLP计算机视觉强化学习【免费下载链接】d2l-enInteractive deep learning book with multi-framework code, math, and discussions. Adopted at 500 universities from 70 countries including Stanford, MIT, Harvard, and Cambridge.项目地址https://gitcode.com/gh_mirrors/d2/d2l-en点击查看免费下载在上一章 chapter_recurrent-neural-networks/index.md 中我们掌握了循环神经网络RNN的基础思想但经典 RNN 深受梯度消失与梯度爆炸之苦——上一章只能通过梯度裁剪这一粗暴手段缓解爆炸梯度而消失梯度问题始终悬而未决。本章chapter_recurrent-modern/index.md正是围绕这一痛点展开先后介绍以 LSTM 记忆单元与门控机制为核心的现代 RNN 架构以及双向 RNN、深层 RNN并一路延伸到机器翻译数据集、编码器-解码器架构、seq2seq 模型与束搜索解码。读完本章你将掌握四套主流深度学习框架MXNet/PyTorch/TensorFlow/JAX下这些模型的从零实现与高层 API 简洁实现并能独立完成基于 RNN 的序列到序列任务实验。一、为什么需要现代RNN数值不稳定性的困局上一章已经明确指出RNN 在训练中面临的核心障碍是梯度消失与梯度爆炸。梯度爆炸可以通过梯度裁剪启发式地缓解但消失梯度问题依旧悬而未决——当序列很长时误差信号在反向传播中逐时间步连乘梯度会指数级衰减使得网络几乎无法学习长期依赖关系。现代 RNN 架构的创新正是围绕如何在保留长期记忆的同时保持梯度通畅这一命题展开。本章涉及的里程碑式工作主要源于两篇论文LSTM长短期记忆:cite:Hochreiter.Schmidhuber.1997引入记忆单元memory cell以替代传统网络隐藏层中的普通节点。直观上记忆单元通过一条权重恒为 1 的自连接循环边让内部状态值在连续多个时间步上级联传递从而规避梯度消失问题一组乘法门则帮助网络决定哪些输入允许进入记忆状态、以及记忆状态的内容何时应该影响模型输出。双向 RNN:cite:Schuster.Paliwal.1997引入一种同时利用未来后续时间步与过去先前时间步信息的架构与之前仅由过去输入影响输出的单向网络形成对比。双向 RNN 已成为自然语言处理中序列标注等任务的主流组件。这两项创新并不互斥早在 2005 年前后就被成功结合用于音素分类与手写识别Graves 与 Schmidhuber 的工作本章也会展示它们如何在现代框架中自由组合。本章各节的阅读路径如下即原文档的章节目录章节主题lstm长短期记忆网络LSTMgru门控循环单元GRUdeep-rnn深层循环神经网络bi-rnn双向循环神经网络machine-translation-and-dataset机器翻译与数据集encoder-decoder编码器-解码器架构seq2seq基于 RNN 的序列到序列学习beam-search束搜索二、LSTM带门控的记忆单元2.1 从长期记忆与短期记忆到记忆单元长短期记忆一词的由来颇具直觉性。简单 RNN 具有以权重形式存在的长期记忆权重在训练中缓慢变化编码关于数据的通用知识以及以瞬时激活值形式存在的短期记忆激活值在节点间逐级传递。LSTM 则通过记忆单元引入一种居中的存储类型记忆单元是一个复合单元由更简单的节点按特定连接模式构成其新颖之处在于引入了乘法节点。每个记忆单元配备一个内部状态internal state与若干乘法门用来决定三件事给定输入是否应影响内部状态输入门input gate内部状态是否应被清零遗忘门forget gate内部状态是否允许影响该单元的输出输出门output gate。LSTM 与普通 RNN 的关键区别在于支持对隐藏状态的门控我们有了专门的机制来决定隐藏状态何时更新、何时重置这些机制是学到的。例如如果第一个 token 至关重要网络会学会在第一个观测之后不再更新隐藏状态也可以学会跳过无关紧要的临时观测还可以在需要时重置潜在状态。2.2 三门一节点数学形式设当前时间步输入为 $\mathbf{X}t \in \mathbb{R}^{n \times d}$样本数 $n$输入维度 $d$上一时间步隐藏状态为 $\mathbf{H}{t-1} \in \mathbb{R}^{n \times h}$隐藏单元数 $h$。三个门分别计算如下$$\begin{aligned} \mathbf{I}t \sigma(\mathbf{X}t \mathbf{W}{\textrm{xi}} \mathbf{H}{t-1} \mathbf{W}{\textrm{hi}} \mathbf{b}\textrm{i}),\ \mathbf{F}t \sigma(\mathbf{X}t \mathbf{W}{\textrm{xf}} \mathbf{H}{t-1} \mathbf{W}{\textrm{hf}} \mathbf{b}\textrm{f}),\ \mathbf{O}t \sigma(\mathbf{X}t \mathbf{W}{\textrm{xo}} \mathbf{H}{t-1} \mathbf{W}{\textrm{ho}} \mathbf{b}\textrm{o}), \end{aligned}$$其中 $\mathbf{W}{\textrm{xi}}, \mathbf{W}{\textrm{xf}}, \mathbf{W}{\textrm{xo}} \in \mathbb{R}^{d \times h}$、$\mathbf{W}{\textrm{hi}}, \mathbf{W}{\textrm{hf}}, \mathbf{W}{\textrm{ho}} \in \mathbb{R}^{h \times h}$ 为权重参数$\mathbf{b}\textrm{i}, \mathbf{b}\textrm{f}, \mathbf{b}_\textrm{o} \in \mathbb{R}^{1 \times h}$ 为偏置参数求和时触发广播机制。三个门均使用sigmoid激活因此取值落在 $(0, 1)$ 区间天然适合做开关。此外还需要一个输入节点$\tilde{\mathbf{C}}_t$candidate memory cell其计算与三门类似但激活函数改用值域为 $(-1, 1)$ 的 $\tanh$$$\tilde{\mathbf{C}}t \textrm{tanh}(\mathbf{X}t \mathbf{W}{\textrm{xc}} \mathbf{H}{t-1} \mathbf{W}{\textrm{hc}} \mathbf{b}\textrm{c}).$$2.3 记忆单元内部状态与隐藏状态使用 Hadamard逐元素乘积算子 $\odot$记忆单元内部状态按如下方式更新$$\mathbf{C}_t \mathbf{F}t \odot \mathbf{C}{t-1} \mathbf{I}_t \odot \tilde{\mathbf{C}}_t.$$输入门 $\mathbf{I}_t$ 控制有多少新数据 $\tilde{\mathbf{C}}_t$ 进入单元遗忘门 $\mathbf{F}t$ 控制保留多少旧状态 $\mathbf{C}{t-1}$。如果遗忘门恒为 1、输入门恒为 0内部状态将永远保持不变并原样传递到后续每个时间步——这正是 LSTM 缓解梯度消失的关键设计梯度可以沿着这条权重为 1 的路径畅通地反向传播。在实际中两个门给了模型学习的灵活性何时保持该值不变、何时响应后续输入而扰动它这使得模型在长序列数据集上更容易训练。最后输出门决定记忆单元内容如何影响网络其他层$$\mathbf{H}_t \mathbf{O}_t \odot \tanh(\mathbf{C}_t).$$对内部状态先施加 $\tanh$ 再与输出门逐元素相乘可确保 $\mathbf{H}_t$ 的值始终落在 $(-1, 1)$。当输出门接近 1 时内部状态几乎无阻碍地影响后续层接近 0 时则阻止当前记忆影响网络其他层。因此一个记忆单元可以跨多个时间步累积信息而不对外暴露只要输出门接近 0然后在某个后续时间步输出门翻转为接近 1 时突然影响网络——这是 LSTM 表达长期依赖的典型方式。2.4 从零实现在 lstm.md 中作者给出了跨 MXNet/PyTorch/TensorFlow/JAX 的从零实现。核心要点参数初始化LSTMScratch(num_inputs, num_hiddens, sigma0.01)权重按标准差 0.01 的高斯分布初始化偏置置 0每组输入门、遗忘门、输出门、输入节点各需一组W_x*输入到隐藏形状num_inputs × num_hiddens、W_h*隐藏到隐藏形状num_hiddens × num_hiddens与偏置b_*。前向传播以 PyTorch 等为例对输入序列逐时间步执行I d2l.sigmoid(d2l.matmul(X, self.W_xi) d2l.matmul(H, self.W_hi) self.b_i) F d2l.sigmoid(d2l.matmul(X, self.W_xf) d2l.matmul(H, self.W_hf) self.b_f) O d2l.sigmoid(d2l.matmul(X, self.W_xo) d2l.matmul(H, self.W_ho) self.b_o) C_tilde d2l.tanh(d2l.matmul(X, self.W_xc) d2l.matmul(H, self.W_hc) self.b_c) C F * C I * C_tilde H O * d2l.tanh(C)JAX 的特殊处理由于 JIT 编译长时间步的 Python for 循环会导致首次编译极其漫长因此 JAX 实现改用jax.lax.scan工具变换它接收初始状态carry与沿首轴扫描的inputs数组最终返回末状态与堆叠的输出。这种用 scan 替代循环的写法是 Flax/JAX 下 RNN 实现的标准实践。训练与预测使用d2l.TimeMachine(batch_size1024, num_steps32)数据集《时间机器》字符级语言模型通过d2l.RNNLMScratch(lstm, vocab_sizelen(data.vocab), lr4)与d2l.Trainer(max_epochs50, gradient_clip_val1, num_gpus1)训练最终调用model.predict(it has, 20, data.vocab, d2l.try_gpu())生成给定前缀后的 20 个字符。2.5 高层 API 简洁实现高层的简洁实现将上述细节全部封装进框架自带算子训练速度显著提升使用编译算子而非逐时间步 Python 循环# PyTorch class LSTM(d2l.RNN): def __init__(self, num_inputs, num_hiddens): d2l.Module.__init__(self) self.save_hyperparameters() self.rnn nn.LSTM(num_inputs, num_hiddens)TensorFlow 使用tf.keras.layers.LSTM(num_hiddens, return_sequencesTrue, return_stateTrue, time_majorTrue)JAX 使用nn.scan(nn.OptimizedLSTMCell, ...)。注意 LSTM 的隐藏层输出包含隐藏状态与记忆单元内部状态两部分只有隐藏状态被送入输出层记忆单元内部状态完全内部化。LSTM 是带非平凡状态控制的潜在变量自回归模型的典型代表后续诸多变体多层、残差连接、各类正则化皆源于此其训练因长程依赖而代价高昂这也为后文 Transformer 等替代模型埋下伏笔。三、GRU更轻量的门控循环单元2010 年代 LSTM 迅速流行后研究者开始尝试简化架构——保留内部状态 乘法门控的核心思想同时追求更快的计算。门控循环单元GRU:cite:Cho.Van-Merrienboer.Bahdanau.ea.2014就是 LSTM 记忆单元的精简版常能达到相近性能但计算更快。3.1 重置门与更新门GRU 将 LSTM 的三个门缩减为两个均使用 sigmoid 激活、取值在 $(0, 1)$重置门$\mathbf{R}_t$控制对前一个状态的记忆程度更新门$\mathbf{Z}_t$控制新状态在多大程度上只是旧状态的拷贝。数学形式输入 $\mathbf{X}t \in \mathbb{R}^{n \times d}$上一步隐藏状态 $\mathbf{H}{t-1} \in \mathbb{R}^{n \times h}$$$\begin{aligned} \mathbf{R}t \sigma(\mathbf{X}t \mathbf{W}{\textrm{xr}} \mathbf{H}{t-1} \mathbf{W}{\textrm{hr}} \mathbf{b}\textrm{r}),\ \mathbf{Z}t \sigma(\mathbf{X}t \mathbf{W}{\textrm{xz}} \mathbf{H}{t-1} \mathbf{W}{\textrm{hz}} \mathbf{b}\textrm{z}). \end{aligned}$$3.2 候选隐藏状态将重置门与常规更新机制结合得到候选隐藏状态$$\tilde{\mathbf{H}}t \tanh(\mathbf{X}t \mathbf{W}{\textrm{xh}} \left(\mathbf{R}t \odot \mathbf{H}{t-1}\right) \mathbf{W}{\textrm{hh}} \mathbf{b}_\textrm{h}),$$其中 $\odot$ 为 Hadamard 乘积。当重置门元素接近 1 时退化为普通 RNN 的隐藏状态更新相当于 :eqref:rnn_h_with_state当重置门元素接近 0 时候选隐藏状态退化为以 $\mathbf{X}_t$ 为输入的 MLP 结果先前的隐藏状态被重置为默认值。3.3 隐藏状态的凸组合最后用更新门对旧状态与候选状态做逐元素凸组合$$\mathbf{H}_t \mathbf{Z}t \odot \mathbf{H}{t-1} (1 - \mathbf{Z}_t) \odot \tilde{\mathbf{H}}_t.$$当更新门接近 1 时直接保留旧状态、忽略 $\mathbf{X}_t$ 的信息相当于在依赖链中跳过时间步 $t$当更新门接近 0 时新状态趋近于候选状态。因此 GRU 具备两个显著特性重置门帮助捕捉序列中的短期依赖更新门帮助捕捉序列中的长期依赖。3.4 实现与训练从零实现时GRUScratch用triple()一次性创建更新门、重置门、候选隐藏状态三组参数W_x*、W_h*、b_*权重标准差sigma0.01。前向传播核心为Z d2l.sigmoid(d2l.matmul(X, self.W_xz) d2l.matmul(H, self.W_hz) self.b_z) R d2l.sigmoid(d2l.matmul(X, self.W_xr) d2l.matmul(H, self.W_hr) self.b_r) H_tilde d2l.tanh(d2l.matmul(X, self.W_xh) d2l.matmul(R * H, self.W_hh) self.b_h) H Z * H (1 - Z) * H_tilde训练配置与 LSTM 相同d2l.TimeMachine(batch_size1024, num_steps32)、num_hiddens32、lr4、max_epochs50、gradient_clip_val1。简洁实现中PyTorch 直接使用nn.GRU(num_inputs, num_hiddens)TensorFlow 使用tf.keras.layers.GRU(num_hiddens, return_sequencesTrue, return_stateTrue)JAX 使用nn.scan(nn.GRUCell, ...)。训练后打印训练集困惑度perplexity与给定前缀 it has 后的 20 字符预测序列。总结对比GRU 与 LSTM 性能相近但计算更轻与普通 RNN 相比门控 RNNLSTM/GRU能更好地捕捉大步长距离的依赖关系。GRU 在重置门开启时包含普通 RNN 作为其极端情形也可通过开启更新门跳过子序列。四、深层 RNN在输入-输出方向上叠加深度前面讨论的 RNN 都只有一层隐藏层但它们在时间方向上是深的第一个时间步的输入要经过 $T$ 次循环层应用$T$ 常达数百甚至上千才能影响最终输出。然而我们常常还需要同一时间步内输入到输出的复杂映射关系即沿输入-输出方向也加深——这正是 MLP 与深度 CNN 中已经遇到的深度概念。4.1 堆叠 RNN 的数学定义构建深度 RNN 的标准方法出奇地简单把 RNN 逐层堆叠。给定长度为 $T$ 的序列第一层 RNN 产生等长的输出序列这些输出又构成下一层 RNN 的输入。设第 $l$ 层$l1,\ldots,L$在时间步 $t$ 的隐藏状态为 $\mathbf{H}_t^{(l)}$令 $\mathbf{H}_t^{(0)} \mathbf{X}_t$则$$\mathbf{H}t^{(l)} \phi_l(\mathbf{H}t^{(l-1)} \mathbf{W}{\textrm{xh}}^{(l)} \mathbf{H}{t-1}^{(l)} \mathbf{W}{\textrm{hh}}^{(l)} \mathbf{b}\textrm{h}^{(l)}),$$输出层只基于最后一层 $L$ 的隐藏状态$$\mathbf{O}t \mathbf{H}t^{(L)} \mathbf{W}{\textrm{hq}} \mathbf{b}\textrm{q}.$$与 MLP 相同层数 $L$ 与隐藏单元数 $h$ 都是可调超参数常见的 RNN 层宽$h$在 $(64, 2056)$ 范围常见深度$L$在 $(1, 8)$ 范围。只要把公式中的隐藏状态计算替换为 LSTM 或 GRU 的更新式就能轻松得到深度门控 RNN。4.2 从零实现与简洁实现从零实现中StackedRNNScratch将每一层视为一个独立的RNNScratch实例第一层输入维度为num_inputs后续各层输入维度为上一层隐藏单元数num_hiddens。前向传播逐层执行outputs inputs for i in range(self.num_layers): outputs, Hs[i] self.rnnsi outputs d2l.stack(outputs, 0)示例训练采用 2 层 GRU 语言模型StackedRNNScratch(num_inputslen(data.vocab), num_hiddens32, num_layers2)lr2、max_epochs100。简洁实现中PyTorch 直接写nn.GRU(num_inputs, num_hiddens, num_layers, dropoutdropout)TensorFlow 通过[tf.keras.layers.GRUCell(num_hiddens, dropoutdropout) for _ in range(num_layers)]构造多层RNNJAXFlax采取极简主义需自行用nn.scan(nn.GRUCell, ...)叠加层数并显式在非最后一层之后插入nn.Dropout。MXNet 版的多层 GRU 训练耗时超过 1 小时待修复问题其余框架可正常训练。注意深度 RNN 中隐藏状态信息同时传给当前层的下一时间步与下一层的当前时间步。模型初始化需谨慎总体而言深度 RNN 需要相当多的调参工作学习率、梯度裁剪等才能保证收敛。五、双向 RNN同时利用过去与未来语言建模只依赖左侧上下文前文因此单向 RNN 链条是合适的。但很多序列任务允许在每个时间步同时利用左右两侧上下文——例如词性标注判断某个词的词性时为何不参考它前后的词另一个常见场景是掩码 token 预测常作为正式任务微调前的预训练随机遮蔽文档中的 token 并训练序列模型预测缺失值。同一处空白其后续内容不同答案会剧烈变化I am___.happy很可能是答案I am___hungry.not或very似乎合理I am___hungry, and I can eat half a pig.not则与第三句矛盾5.1 架构与数学形式将任意单向 RNN 变成双向 RNN 的技术十分简单 :cite:Schuster.Paliwal.1997实现两个方向相反、作用于同一输入的单向 RNN 层并拼接输出。第一个 RNN 层按 $\mathbf{x}_1$ 到 $\mathbf{x}_T$ 顺序读取第二个按 $\mathbf{x}_T$ 到 $\mathbf{x}_1$ 逆序读取。形式化地前向与后向隐藏状态分别为$$\begin{aligned} \overrightarrow{\mathbf{H}}t \phi(\mathbf{X}t \mathbf{W}{\textrm{xh}}^{(f)} \overrightarrow{\mathbf{H}}{t-1} \mathbf{W}{\textrm{hh}}^{(f)} \mathbf{b}\textrm{h}^{(f)}),\ \overleftarrow{\mathbf{H}}t \phi(\mathbf{X}t \mathbf{W}{\textrm{xh}}^{(b)} \overleftarrow{\mathbf{H}}{t1} \mathbf{W}{\textrm{hh}}^{(b)} \mathbf{b}\textrm{h}^{(b)}), \end{aligned}$$将两者拼接得到 $\mathbf{H}t \in \mathbb{R}^{n \times 2h}$ 再送入输出层$\mathbf{O}t \mathbf{H}t \mathbf{W}{\textrm{hq}} \mathbf{b}\textrm{q}$注意此时 $\mathbf{W}{\textrm{hq}} \in \mathbb{R}^{2h \times q}$。在多层的深度双向 RNN 中拼接后的信息作为下一双向层的输入继续传递。虽然技术上两个方向可有不同隐藏单元数实践中极少这样设计。5.2 实现要点从零实现中BiRNNScratch内部包含两个独立参数的RNNScratch实例f_rnn与b_rnn并将num_hiddens * 2以反映输出维度翻倍f_outputs, f_H self.f_rnn(inputs, f_H) b_outputs, b_H self.b_rnn(reversed(inputs), b_H) outputs [d2l.concat((f, b), -1) for f, b in zip(f_outputs, reversed(b_outputs))]简洁实现中PyTorch 使用nn.GRU(num_inputs, num_hiddens, bidirectionalTrue)MXNet 为rnn.GRU(num_hiddens, bidirectionalTrue)而Flax API 不提供 RNN 层、也没有bidirectional参数需要像从零实现那样手动反转输入。总结双向 RNN 中每个时间步的隐藏状态同时由该时间步之前和之后的数据决定主要用于序列编码与给定双向上下文估计观测这类任务由于梯度链很长双向 RNN 训练代价高昂。六、机器翻译与英法数据集机器翻译是现代 RNN 引发广泛关注的重要应用突破之一模型输入一种语言的句子预测另一种语言的对应句子。注意两种语言的句子长度可能不同且对应词序因语法结构差异而不同——这类未对齐序列之间的映射对话→回复、问题→答案等统称为序列到序列seq2seq问题是本章剩余部分乃至注意力与 Transformer 章节的焦点。6.1 下载与预处理chapter_recurrent-modern/machine-translation-and-dataset.md 使用 Tatoeba 项目的英法双语平行句对数据集。MTFraEng(d2l.DataModule)的_download通过d2l.download(d2l.DATA_URL fra-eng.zip, self.root, 94646ad1522d915e7b0f9296181140edcf86a4f5)下载并解压读取fra-eng/fra.txt每行是一个制表符分隔的英文源句\t法文目标句对。预处理_preprocess依次执行把不间断空格\u202f、\xa0替换为普通空格、统一转小写、在单词与标点之间插入空格no_space lambda char, prev_char: char in ,.!? and prev_char ! 。6.2 词级 tokenization 与词表与语言建模中的字符级 tokenization 不同机器翻译这里更偏好词级 tokenization今日 SOTA 模型使用更复杂的 tokenization 技术。_tokenize(text, max_examplesNone)将前max_examples个句对切分为 token 列表每个 token 是一个词或标点每个序列末尾追加特殊 tokeneos表示序列结束——模型逐 token 生成时生成eos即表明输出序列完成。该方法返回两个 token 列表的列表src英文源与tgt法文目标。随后可绘制源/目标序列 token 数直方图该简单数据集大多数序列少于 20 个 token。后续步骤详见原文档包括基于词频构建源/目标词表src_vocab、tgt_vocab将低频 token 视为未知词为组成 minibatch用截断与填充使序列等长并用_build_arrays构造源序列、目标序列、标签与源有效长度build方法便于将自定义句对快速转为训练数组。现代实现常用长度分桶bucketing减少填充带来的计算浪费。七、编码器-解码器架构在一般的 seq2seq 问题如机器翻译中输入与输出是长度可变且不对齐的。处理这类数据的标准做法是编码器-解码器架构encoder-decoder.md由两大组件构成编码器Encoder接收变长序列作为输入解码器Decoder扮演条件语言模型角色接收编码后的输入与目标序列的左侧上下文预测目标序列的下一个 token。以英译法为例输入英文序列 They, are, watching, .编码器先把变长输入编码为状态解码器再逐 token 生成译文 Ils, regardent, .。原文档将这一架构抽象为可被后续模型继承的接口interface而非具体实现。7.1 Encoder / Decoder / EncoderDecoder 三个接口四个框架下的接口定义完全同构MXNet 为nn.Block、PyTorch 为nn.Module、TensorFlow 为tf.keras.layers.Layer、JAX 为nn.ModuleEncoderforward(X, *args)TF 为callJAX 为__call__接收变长序列X具体实现留给子类Decoder额外提供init_state(enc_all_outputs, *args)方法把编码器输出enc_all_outputs转换为编码状态可能需要额外输入如输入的有效长度每次解码时把上一步生成的 token与编码状态映射为当前时间步的输出 token从而逐 token 生成变长序列EncoderDecoder(d2l.Classifier)串联两者——前向传播中先用encoder(enc_X, *args)得到全部编码器输出再decoder.init_state(enc_all_outputs, *args)得到解码状态最后decoder(dec_X, dec_state)[0]仅返回解码器输出。该架构能处理输入与输出皆为变长序列的问题因此适合机器翻译等 seq2seq 任务。下一节seq2seq.md将展示如何用 RNN 基于此架构具体实现 seq2seq 模型。八、束搜索序列解码的折中策略在 seq2seq.md 中测试时的预测只提到贪心策略每个时间步选择条件概率最高的 token直至预测出特殊结束符eos。而 beam-search.md 系统比较了三种解码策略其复杂度横跨一个谱系。8.1 贪心搜索便宜但不一定最优设输出词表为 $\mathcal{Y}$含eos最大输出长度为 $T$。贪心搜索在每个时间步选择$$y_{t} \operatorname*{argmax}{y \in \mathcal{Y}} P(y \mid y_1, \ldots, y{t-1}, \mathbf{c}),$$计算代价为 $\mathcal{O}(|\mathcal{Y}|T)$十分廉价。但最可能的 token 序列 ≠ 最可能序列——后者最大化 $\prod_{t1}^{T} P(y_{t} \mid y_1, \ldots, y_{t-1}, \mathbf{c})$。原文档用四 tokenA/B/C/eos的示例证明贪心得到的序列 A,B,C,eos 概率为 $0.5\times0.4\times0.4\times0.60.048$而若在时间步 2 选择次高概率的 C序列 A,C,B,eos 概率为 $0.5\times0.3\times0.6\times0.60.054$反而更优——因为后续各时间步的条件分布随前缀改变而改变。8.2 穷举搜索最优但不可行枚举所有 $|\mathcal{Y}|^{T}$ 个可能输出序列并取概率最高者代价为 $\mathcal{O}(|\mathcal{Y}|^{T})$随序列长度指数爆炸。例$|\mathcal{Y}|10000$、$T10$ 时需评估 $10000^{10}10^{40}$ 个序列远超任何可预见计算机的能力。8.3 束搜索用束宽平衡效率与最优性束搜索由唯一超参数束宽 $k$刻画时间步 1 选取概率最高的 $k$ 个 token 作为 $k$ 个候选序列的首 token此后每个时间步基于上一时间步的 $k$ 个候选从 $k|\mathcal{Y}|$ 个候选中继续挑出概率最高的 $k$ 个。计算代价为 $\mathcal{O}(k|\mathcal{Y}|T)$介于贪心与穷举之间贪心搜索正是束宽 $k1$ 的特例。图示过程词表 $\mathcal{Y}{A,B,C,D,E}$其一为eos束宽 2。时间步 1 选 $A$、$C$时间步 2 对二者分别展开全部 $y_2$ 计算 $P(A,y_2\mid\mathbf{c})$ 与 $P(C,y_2\mid\mathbf{c})$在 10 个值中取最大的两个如 $AB$ 与 $CE$时间步 3 同理得到 $ABD$ 与 $CED$。最终候选集合为 ${A, C, AB, CE, ABD, CED}$去掉含eos的部分后按如下得分选择最终输出$$ \frac{1}{L^\alpha} \log P(y_1, \ldots, y_{L}\mid \mathbf{c}) \frac{1}{L^\alpha} \sum_{t1}^L \log P(y_{t} \mid y_1, \ldots, y_{t-1}, \mathbf{c});$$其中 $L$ 为最终候选序列长度$\alpha$ 通常取 0.75。由于长序列在对数和中项数更多分母中的 $L^\alpha$ 起到惩罚长序列的作用。九、章节总结与延伸阅读本章以 RNN 的梯度消失/爆炸问题为起点完整覆盖了现代 RNN 家族的核心成员及其在 seq2seq 场景下的应用LSTM通过带三条门输入/遗忘/输出门与权重为 1 的自连接内部状态让梯度跨越多时间步畅通传播是 2011 年至 Transformer 兴起2017 年期间序列学习的主导模型Transformer 的部分关键设计思路也源于 LSTM 的架构创新GRU以更轻量的重置门/更新门组合达到相近性能计算更快深层 RNN通过逐层堆叠在输入-输出方向加深网络L/GRU/LSTM 皆可作其单元双向 RNN拼接正反两个方向的隐藏状态成为序列标注等任务的主流组件机器翻译数据集英法平行语料提供词级 tokenization、词表构建与填充/分桶的完整数据管线编码器-解码器架构将变长序列映射到固定形状状态、再解码回变长序列是 seq2seq 模型seq2seq.md的通用基座束搜索以束宽 $k$ 在贪心$k1$与穷举之间折中配合长度惩罚 $\alpha$ 选择最终输出序列。后续可继续阅读 chapter_attention-mechanisms-and-transformers/index.md注意力机制正是为了解决 seq2seq 中编码器须将全部信息压缩进固定长度状态的瓶颈而提出而 Transformer 则彻底改写了本章各模型所依赖的递归结构。output文章赞分享文档教程人工智能深度学习NLP计算机视觉强化学习【免费下载链接】d2l-enInteractive deep learning book with multi-framework code, math, and discussions. Adopted at 500 universities from 70 countries including Stanford, MIT, Harvard, and Cambridge.项目地址https://gitcode.com/gh_mirrors/d2/d2l-en点击查看免费下载相关推荐《动手学深度学习》现代循环神经网络全解GRU、LSTM、深层/双向架构与 seq2seq 序列生成《动手学深度学习》现代循环神经网络全解GRU、LSTM、深层/双向架构与 seq2seq 序列生成 导读 本篇技术指南以开源仓库 d2l zh 中 现代循环神人工智能深度学习机器学习教程《动手学深度学习》循环神经网络RNN实战指南序列模型、语言建模与 BPTT 全解析《动手学深度学习》循环神经网络RNN实战指南序列模型、语言建模与 BPTT 全解析 导读 本文以《动手学深度学习》d2l zh仓库中 chapter_人工智能深度学习机器学习教程Dive into Deep Learningd2l-en循环神经网络章节指南从序列建模到 BPTT 的完整学习路线Dive into Deep Learningd2l en循环神经网络章节指南从序列建模到 BPTT 的完整学习路线 循环神经网络RNN是深度学习处理文档教程人工智能深度学习NLP计算机视觉强化学习上一篇无需安装也能畅玩三国杀开源无名杀网页版让你随时随地开战下一篇5个关键点揭秘yysScript如何实现阴阳师24小时无人值守挂机的完整指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考