详细摘要 摘要

生成:2025-05-15 22:15

摘要详情

音频文件
Stanford CS224N NLP with Deep Learning | 2023 | Lecture 8 - Self-Attention and Transformers
摘要类型
详细摘要
LLM 提供商
openai
LLM 模型
gemini-2.5-pro-exp-03-25
已创建
2025-05-15 22:15:36

概览/核心摘要 (Executive Summary)

本讲座主要介绍了从传统的循环神经网络 (RNN) 到基于自注意力机制的 Transformer 模型的演进,探讨了其核心思想、关键组件和实际应用。RNN 因其线性交互距离和难以并行化等问题,在处理长序列依赖时面临挑战。注意力机制,特别是自注意力机制,通过允许模型在序列中的任意两个位置之间直接计算依赖关系,克服了这些局限。自注意力机制将输入序列中的每个元素视为查询 (Query),并与其他元素的键 (Key) 进行匹配,然后根据匹配程度对相应的值 (Value) 进行加权求和,从而得到该元素的上下文感知表示。

为了将自注意力机制有效地应用于实际任务,讲座详细阐述了几个关键组件:首先是位置编码 (Positional Encoding),用于解决自注意力本身不包含序列顺序信息的问题,可以通过固定的正弦/余弦函数或可学习的嵌入实现;其次是前馈神经网络 (Feed-Forward Network),在自注意力层之后对每个位置的输出进行非线性变换,增强模型表达能力;以及掩码 (Masking)机制,在解码等任务中防止模型“看到”未来的信息。

Transformer 模型在此基础上引入了多头注意力 (Multi-Head Attention),允许模型在不同表示子空间中并行地关注来自不同位置的信息;缩放点积注意力 (Scaled Dot-Product Attention),通过缩放点积来稳定梯度;以及残差连接 (Residual Connections)层归一化 (Layer Normalization),以促进深度网络的训练。讲座详细介绍了 Transformer 的编码器、解码器以及编码器-解码器架构,并强调了它们在机器翻译等任务中取得的显著成果,以及推动预训练模型发展的重要作用。最后,也提及了 Transformer 的主要缺点,如二次方计算复杂度,以及相关的研究方向。

课程管理与通知

  • 新的讲义已发布: 讲义内容与本次讲座内容基本一致,但包含更多细节。
  • 作业四 (Assignment 4): 将于一周后到期。
    • Azure 的问题仍在继续。
    • 助教已测试,作业可在 Colab 上完成训练,训练量在 Colab 会话允许范围内。建议没有 GPU 的学生使用 Colab。
    • 团队正在为作业五和最终项目争取更多 GPU 资源。
  • 最终项目提案 (Final Project Proposal):
    • 将于今晚发布,届时会有 Ed Announcement 通知。
    • 团队将对提案的可行性提供反馈,并建议修改方向,以确保项目在剩余学期内有较好的成功机会。
    • 反馈将尽快给出,因为学生将在作业五完成后主要投入到最终项目中。

从循环神经网络 (RNN) 到注意力机制

Speaker 1 回顾了课程早期处理自然语言处理问题的方法,通常采用双向 LSTM (Bidirectional LSTM) 对句子进行编码,并使用单向 LSTM 逐个生成输出(如翻译或解析)。注意力机制被用于提供对记忆的灵活访问,例如在机器翻译中避免将整个源句信息压缩到单个向量中。

本次讲座的目标与之前类似,但将使用不同的构建模块。讲座指出,大约在 2014-2017 年,RNN 是主流,而之后出现了新的构建模块(即 Transformer),它们可以直接替代 LSTM,并带来了更广泛和成功的应用。

RNN 的局限性

Speaker 1 指出了 RNN 的两个主要问题:

  1. 线性交互距离 (Linear Interaction Distance):

    • RNN 按顺序(从左到右或从右到左)处理信息,这使得相邻词语易于交互。
    • 然而,对于长距离依赖关系(例如句子 "The chef who ... was..." 中 "chef" 和 "was" 的关系),信息需要在 RNN 中逐步传递,距离越远,学习这种依赖关系就越困难。
    • 尽管 LSTM 比简单 RNN 在处理长距离梯度问题上有所改进,但并非完美。
    • "very long distance dependencies can take a very long time to interact."

    • 理想情况下,希望相关的词语能更容易地在神经网络的计算图中交互,而不受线性距离的限制。
  2. 缺乏并行性 (Lack of Parallelizability / Dependence on Time):

    • RNN 的前向和后向传播包含 O(序列长度) 数量的不可并行操作。
    • 要计算时间步 t 的隐藏状态,必须先计算时间步 t-1 的隐藏状态。
    • "you can't actually compute the rnn hidden state for time step five before you compute the rnn hidden state for time step four or time step three."

    • 这限制了 GPU 等并行计算硬件的有效利用,因为序列越长,无法并行的操作链就越长。

针对 Speaker 2 的提问 (关于注意力是否已解决线性交互问题):Speaker 1 回应,注意力确实有助于解决线性交互问题,并且本讲座后续内容将完全基于注意力,并会摒弃循环结构。

深入理解注意力机制 (Attention)

Speaker 1 提出,如果 RNN 不是最佳选择,那么注意力机制是可行的替代方案。注意力机制的核心思想是:

  • 将每个词的表示视为一个查询 (Query)
  • 该查询用于访问并整合来自一组值 (Values) 的信息。
  • 注意力机制允许模型直接关注序列中任意远距离的词语,解决了线性交互问题。
  • 由于可以同时处理整个序列,它也解决了并行性问题。

注意力机制:类比于模糊查找

Speaker 1 将注意力机制比作在键值存储 (Key-Value Store) 中的一种“模糊查找”:

  • 标准查找表 (Lookup Table): 如 Python 字典,查询精确匹配一个键,然后返回对应的值。
  • 注意力机制:
    • 查询 (Query) 与所有键 (Keys) 进行“软性”匹配,计算相似度。
    • 通过 softmax 函数将相似度转换为权重 (0到1之间)。
    • 最终输出是所有值 (Values) 基于这些权重的加权平均。
    • "it really is quite a bit like a lookup table, but in this sort of soft vector space, you mushy sort of sense."

示例: 在句子 "I went to Stanford cs224n and learned" 中,为了构建 "learned" 的表示,"learned" 作为查询,会与句子中所有词(作为键)计算相似度,并对这些词对应的值进行加权求和。

自注意力 (Self-Attention) 详解

自注意力是指在单个序列内部,元素之间相互关注。其计算步骤如下:

  1. 输入: 词序列 W_1, ..., W_n
  2. 词嵌入: 每个词 W_i 通过嵌入矩阵 E 转换为词向量 x_i (维度为 d)。这些是无上下文的词嵌入。
  3. 生成查询 (Query)、键 (Key)、值 (Value) 向量:

    • 对每个词向量 x_i,使用三个不同的可学习权重矩阵 W_q, W_k, W_v (均为 d x d 维度) 进行线性变换,得到该词的查询向量 q_i、键向量 k_i 和值向量 v_i
      • q_i = W_q * x_i
      • k_i = W_k * x_i
      • v_i = W_v * x_i
    • 因此,序列中的每个词都同时扮演这三种角色。
  4. 计算注意力得分 (Attention Scores):

    • 对于任意一对词 ij (词 i 作为查询,词 j 作为键),计算它们之间的点积相似度 e_ij
      • e_ij = q_i^T * k_j
    • 这个得分表示词 i 应该多大程度上关注词 j
  5. 计算注意力权重 (Attention Weights):

    • 对每个词 i,将其与序列中所有其他词 j 的得分 e_ij 进行 softmax 归一化,得到注意力权重 alpha_ij
      • alpha_ij = softmax_j(e_ij) = exp(e_ij) / sum_k(exp(e_ik))
    • 权重 alpha_ij 表示词 i 的表示中,来自词 j 的信息的贡献程度。
  6. 计算输出向量 (Output Vectors):

    • i 的最终输出向量 o_i 是序列中所有词的值向量 v_j 的加权和,权重为 alpha_ij
      • o_i = sum_j (alpha_ij * v_j)

针对 Speaker 2 的提问 (为何需要独立的 Q 和 K 矩阵,而不是一个组合矩阵): Speaker 1 解释这与计算效率有关,最终会形成 QK^T 的低秩近似。
针对 Speaker 2 的提问 (词自身对其自身表示的注意力,即 q_ik_i 的关系): Speaker 1 指出,这取决于学习到的 W_qW_k 矩阵。模型可以通过学习来决定一个词是否应该关注自身。

构建自注意力模块的关键组件

Speaker 1 指出,直接使用上述定义的自注意力机制替代 RNN 还存在一些问题,需要引入额外组件来构建一个“最小可行”的自注意力模块。

问题1:缺乏序列顺序信息 (No Notion of Sequence Order)

  • 问题描述: 自注意力机制本身是对集合的操作,它不关心词语在序列中的原始顺序。例如,"Zuko made his uncle" 和 "His uncle made Zuko" 在经过自注意力处理后可能会得到相同的表示,因为词的嵌入和注意力计算不依赖于词的位置索引。
  • 解决方案: 位置编码 (Positional Encoding)。将代表词语位置信息的向量 p_i 加到对应的词嵌入 x_i 上。
    • 正弦/余弦位置编码 (Sinusoidal Positional Encoding):
      • 使用不同频率的正弦和余弦函数为每个位置生成一个固定维度的向量。
      • P_i 的每个维度 k 的计算方式类似于 sin(pos / 10000^(2k/d_model))cos(pos / 10000^(2k/d_model))
      • 优点:可以处理比训练时更长的序列(理论上),但实践中外推效果不佳。
      • 这是一种早期的、有时仍在使用的方法。
    • 可学习的位置编码 (Learned Positional Encoding):
      • 创建一个可学习的嵌入矩阵,维度为 (最大序列长度 N_max, 词嵌入维度 d)
      • 在输入时,将对应位置的向量加到词嵌入上。
      • 优点:模型可以学习到最适合数据的位置表示。
      • 缺点:无法处理超过 N_max 长度的序列。模型在遇到更长序列时会出错。
      • "in practice, you'll get a model error if you pass a self attention model, something longer than length n, it will just sort of crash and say, I can't do this."

      • 目前大多数系统采用这种方式。实际中 N_max 可能为 4000 左右,对于小说或长篇维基百科页面仍显不足。
    • 其他方法:相对位置编码、依赖树结构感知的位置编码等(讲义中有更多细节)。

针对 Speaker 2 的提问 (实践中是否将 N 设置得足够大以避免超长序列问题): Speaker 1 回应,这在实践中仍然是一个问题,即使是大型语言模型。自注意力操作的复杂度是序列长度的二次方,这限制了 N_max 的大小。
针对 Speaker 2 的提问 (如何确保学习到的 P 矩阵代表位置信息): Speaker 1 解释,因为 P 矩阵在每个位置上是固定的,而词是变化的,所以 P 矩阵唯一关联的就是位置信息。

问题2:缺乏非线性 (No Non-linearities for Deep Learning Magic)

  • 问题描述: 如果仅仅堆叠自注意力层,本质上只是在反复对值向量进行加权平均,缺乏深度学习模型通常需要的非线性变换来增强表达能力。
  • 解决方案: 逐位置前馈神经网络 (Position-wise Feed-Forward Network, FFN)
    • 在自注意力层的输出之后,对每个位置的输出向量独立地应用一个小型的前馈网络(通常是一个两层的 MLP,包含一个非线性激活函数,如 ReLU)。
    • FFN(x) = max(0, xW_1 + b_1)W_2 + b_2
    • 这为模型引入了非线性,并且可以高效并行计算。

问题3:解码时“预知未来” (Looking at the Future)

  • 问题描述: 在某些任务中(如语言建模、机器翻译解码),模型在预测当前词时不应获取未来词的信息。标准的自注意力会允许一个词关注序列中所有其他词,包括未来的词。
  • 解决方案: 掩码 (Masking)
    • 在计算注意力权重之前,修改注意力得分矩阵 e_ij
    • 对于词 i,如果词 j 在其之后 (即 j > i),则将 e_ij 设置为一个非常小的负数 (如负无穷大)。
    • 这样,在 softmax 计算后,这些未来位置的注意力权重 alpha_ij 会趋近于零。
    • "when you softmax the eij, negative infinity gets mapped to zero. So now my attention is weighted zero... on the future."

    • 这使得模型在并行计算整个序列的注意力的同时,能够确保每个位置的表示仅依赖于当前和之前的位置。
    • 通常在解码器中使用,编码器中通常不需要(允许双向信息流)。

最小自注意力构建模块总结:
1. 输入嵌入 + 位置编码
2. 自注意力机制 (计算 Q, K, V, 得分, 权重, 输出)
3. (可选) 掩码机制 (用于解码等任务)
4. 逐位置前馈神经网络

这个模块可以堆叠多次,形成深度网络。

Transformer 模型详解

Speaker 1 指出,之前介绍的“最小自注意力模块”并非实际中性能最佳的方案。Transformer 模型在此基础上引入了更多关键细节。

Transformer 解码器 (Decoder)

Transformer 解码器用于语言模型等任务,其核心组件包括:

  1. 掩码多头自注意力 (Masked Multi-Head Self-Attention):

    • 动机: 单个自注意力机制可能难以同时捕捉多种不同类型的依赖关系。例如,一个词可能需要基于语义相似性关注某些词,同时基于句法结构关注另一些词。
    • 多头机制:
      • 将原始的查询、键、值向量分别投影到 H 个不同的、更低维度的子空间中(每个子空间的维度是 d_model / H)。
      • 在每个子空间(即每个“头”)内独立地执行自注意力计算。
      • H 个头的输出拼接起来。
      • 通过一个最终的线性变换层 (W_o) 将拼接后的结果融合。
    • "each head gets to look at different things and construct their value vectors differently."

    • 实现: 通过对 Q, K, V 矩阵进行变形 (reshape) 来高效实现,计算成本并不会显著高于单头注意力。
    • 效果: 允许模型从不同角度、不同表示子空间关注信息。实践中,不同的头倾向于学习关注不同的模式。
    • 针对 Speaker 2 的提问 (如何确保不同的头学习不同的东西): Speaker 1 表示这并没有显式保证,但实践中它们倾向于自发地专业化。
  2. 缩放点积注意力 (Scaled Dot-Product Attention):

    • 问题: 当词向量维度 d_k (键向量的维度,通常是 d_model / H) 较大时,点积 q^T * k 的结果可能会变得很大,导致 softmax 函数进入梯度饱和区,使得梯度非常小,不利于学习。
    • 解决方案: 在计算 softmax 之前,将点积结果除以 sqrt(d_k)
      • Attention(Q, K, V) = softmax( (QK^T) / sqrt(d_k) ) * V
    • 这有助于在初始化时保持注意力权重的平滑分布。
  3. 残差连接 (Residual Connections) 与层归一化 (Layer Normalization) (合称 "Add & Norm"):

    • 在每个子层(如多头注意力层、前馈网络层)的输出端应用。
    • 残差连接: 将子层的输入 x 加到其输出 SubLayer(x) 上,即 x + SubLayer(x)
      • 极大地帮助了深度网络的训练,缓解梯度消失问题,使网络更容易学习恒等映射。
      • "the gradient is just really great through the residual connection... the gradient is one because it's the identity."

    • 层归一化: 对每个样本的每个词的表示向量(在 d_model 维度上)进行归一化,使其均值为0,标准差为1。然后通过可学习的缩放参数 gamma 和偏移参数 beta 进行调整。
      • LayerNorm(x) = gamma * ( (x - mean(x)) / sqrt(std(x)^2 + epsilon) ) + beta
      • 有助于稳定训练过程,减少层间协方差偏移。
      • 注意: 层归一化是针对单个词向量的维度进行的,不跨序列中的词,也不跨批次中的样本。

Transformer 解码器模块 (Block) 结构:
一个解码器模块通常包含以下顺序操作:
1. 掩码多头自注意力 (Masked Multi-Head Self-Attention)
2. Add & Norm (残差连接 + 层归一化)
3. 逐位置前馈神经网络 (FFN)
4. Add & Norm (残差连接 + 层归一化)
这样的模块会重复堆叠 N 次。

针对 Speaker 2 的提问 (模型如何处理可变长度输入): Speaker 1 解释,输入通常会被填充 (pad) 到一个固定的最大长度。在注意力计算中,可以通过掩码机制忽略这些填充标记的贡献。

Transformer 编码器 (Encoder)

  • 结构与解码器模块非常相似。
  • 主要区别: 编码器中的多头自注意力层是非掩码的 (unmasked),允许每个位置关注序列中的所有其他位置(双向上下文)。

Transformer 编码器-解码器 (Encoder-Decoder) 架构

这是原始 "Attention Is All You Need" 论文中提出的完整 Transformer 架构,常用于机器翻译等序列到序列任务。

  • 编码器 (Encoder):

    • N 个编码器模块堆叠而成。
    • 处理输入源序列(例如,待翻译的句子)。
    • 其最终输出是一系列上下文感知的词表示。
  • 解码器 (Decoder):

    • N 个解码器模块堆叠而成。
    • 生成目标序列(例如,翻译后的句子)。
    • 解码器模块与之前描述的略有不同,它包含两个多头注意力子层:
      1. 掩码多头自注意力层 (Masked Multi-Head Self-Attention): 对解码器自身已生成的部分序列进行自注意力计算(与独立解码器中的一样)。
      2. 编码器-解码器注意力层 (Encoder-Decoder Attention / Cross-Attention):
        • 查询 (Queries) 来自前一个解码器子层(即掩码自注意力层)的输出。
        • 键 (Keys) 和 值 (Values) 来自编码器的最终输出
        • 这一层允许解码器在生成每个目标词时,关注源序列中的相关部分。
        • 这一层是非掩码的,因为解码器可以关注源序列的任何部分。
      3. 逐位置前馈神经网络 (FFN)。
    • 每个子层(两个注意力层和 FFN)之后都跟着一个 "Add & Norm" 操作。

Transformer 的卓越成果

  • 机器翻译: 原始 Transformer 论文在机器翻译任务上取得了优异成绩,虽然不一定比当时最好的系统有惊人的提升,但其训练效率显著更高,因为它能更好地利用并行计算。
  • 预训练模型的基石: Transformer 的并行性和效率使其能够处理海量数据进行预训练,催生了 BERT、GPT 等一系列强大的预训练语言模型。
  • 广泛应用: 在各种自然语言处理基准测试中,基于 Transformer 的模型迅速成为主流,并在文档生成、摘要、问答等多种任务上取得了 SOTA (State-of-the-Art) 结果。
    • "This ability to make use of lots and lots of data, lots and lots of compute, just put transformers head and shoulders above lstms in, let's say, almost every sort of modern advancement in natural language processing."

Transformer 的不足与变体

  1. 二次方计算复杂度 (Quadratic Compute Problem):

    • 自注意力机制需要计算序列中所有词对之间的交互,导致计算量和内存消耗随序列长度 NO(N^2 * d) 增长。
    • 这限制了 Transformer 处理非常长序列(如整本书或长篇文档)的能力。相比之下,RNN 的复杂度是线性的 O(N * d^2)
    • "if you had something like you know, 50000, then n squared becomes huge and sort of totally infeasible."

    • 许多研究工作致力于降低这种复杂度(例如,稀疏注意力、线性化注意力),但 Speaker 1 提到,对于像 GPT-3 这样的大模型,自注意力部分可能已不是主要的计算瓶颈。
  2. 位置表示: 绝对位置编码可能不是最优的,相对位置编码等变体被提出。

  3. 模型变体: 过去几年中出现了大量 Transformer 的变体,但 Speaker 1 认为,原始 Transformer 加上一些小的修改(如改变 FFN 中的非线性激活函数)仍然非常强大且具有持久力。

结论与展望

  • Transformer 架构,特别是其自注意力机制,已经成为现代自然语言处理领域的基础。
  • 尽管存在计算复杂度等问题,但其并行性和强大的表示能力使其在各种任务中取得了巨大成功。
  • 未来的讲座将讨论预训练技术。
  • 提醒学生关注作业四的截止日期和最终项目提案的发布。