Attention Is All You Need论文解析笔记

2025-07-10

参考资料有

背景知识

Transformer属于哪一类模型,它解决了什么问题

Transformer针对的是序列转录/生成问题,即输入一个序列,输出一个序列。中译英是最典型的一种序列转录问题。例如将

我爱水课

翻译成

I love easy courses

Transformer之前都有啥

前馈神经网络

首先最原始的结构为前馈神经网络(feed-forward neural network,FNN), 通过三个步骤来实现:

分词Tokenization:
  • 将“我爱水课”拆分成“我”,“爱”, “水”,“课”
词向量表示Embedding
  • 将每一个token转变成一个向量,然后通过向量与向量在多维空间的关系来判定词与词的实际关系 向量表示视图
合并词向量
  1. 将之前的词向量进行统一处理来获得最终结果。
  2. 举例:如果想要对“我”一词进行翻译,合并向量后会产生一个大的key:value表格。每一个key对应着一个英文词,每一个value对应着一个这个英文词是否对应中文的“我”一词的几率,而“I”的value应该是最大的。
  3. 合并的具体过程就是把向量们过一遍模型结构。这个结构有:
    1. 输入层
    2. 隐藏层
    3. 输出层

前馈神经网络视图

通过用一些权重数值与输入层数值相乘获得下一层数值,在用另一部分权重乘以刚获得新数值来获得再下一层的数值,如此反复计算来获得最终数值。

这个逻辑实际上跟淘金时候用的篓子,或者用来表示正太分布的小球落体结构差不多:

小球落体结构

前馈神经网络的缺点:
  • 没法记录词语的顺序
    • 为什么“我”需要在“爱”一词的前面?FNN无法理解这一关系
  • 没法灵活更改出入词语的长度
    • 一个FNN只能对应一种输入长度,能够处理“我爱水课”的FNN处理不了“我不爱水课”。

循环神经网络

循环神经网络(Recurrent neural network, RNN)就是把FNN的一个进化版。由于参考到FNN只能有固定长度的输入,RNN决定只接受一个一个token的输入。每一个时刻对应着一个token

所以先输入“我”,算出一个隐藏层h值,再把这个h值并在下一词“爱”的输入里面,这样递归般的计算整个句子。

RNN视图

RNN的好处
  • 有时间观念,每个token的输入排序会被考虑到
  • 因为是逐个喂词,有记忆机制,有上下文观念
  • 可以处理不定长度的输入,所以句子多长多短都可以被处理
RNN的问题

输入与输出必须等长,所以如果是“哎呦喂,您吃了没?”,就没法翻译成“Hi,have you ate?”,因为句子长度不一样。

编码与解码器

编码器解码器的架构就是把之前FNN/RNN的处理输入部分,跟处理输出的部分拆开来做

只有一个上下文向量

输入放在在编码器里,随后产出一个上下文向量c

再把c编码器给的值放在解码器里,它会进行解码并产生输出

产生问题1:

仅有的一个上下文向量会在在解码过程中被重复使用,导致其变质。就跟多人传声一样。

所以这时候的一个解决办法就是在解码的每一步都重置一下输入的上下文向量:

有多个上下文向量

产生问题2:

但是不停的重置就导致了先后关系丢失。导致在解码过程中模型容易遗忘东西。

比如“水课”有可能被翻译成“water class”,因为模型有可能遗忘“课”在“水”的旁边。

产生问题3

整个过程时线性计算,没有办法并行,导致计算非常长缓慢。

卷积神经网络

卷积神经网络(CNN)运需并行计算,算是解决了之前的一部分问题,但是其对于上下文理解的缺失导致它并没有比编码解码器架构好多少。

注意力机制和Transformer

注意力机制就是为了解决以上上下文语意关系问题,它能够:

  • 帮助解决长句子的遗忘问题
  • 细化在不同步骤的上下文的对于生成的权重

本质上就是额外的一层给所有token的权重,在每一步都不一样,根据时间来变化

而Transformer则利用注意力机制来同时解决上下文理解确实和线性计算的缓慢。

Transformer

Transformer架构

编码部分

Embedding

在编码时,每个词都会生成一个向量,每个向量里同时包含语义信息和位置信息,这个编码过程会并行发生,最终生成一个矩阵,在transformer架构里每个token是512大小.

所以“我爱水课",会变为 4 x 512的矩阵。

在这个过程中,每个词会被映射到一个512维的向量空间里,这些向量的区别距离代表了词跟词之间的关系

Attention

之所以叫attention,是因为这一套计算过程帮助所有token选择该关注什么。一个token关注另一个token,就代表这两个token有联系。

而transformer所运用的self attention则代表这种关注的动作是针对同一文本中其他的token的。每个token自己决定自己应该关注哪些其他token。这与传统非自注意力的方式不同。非自注意力则是两个不同文本的互相关注,主要被运用与编码器的输出对于解码器的输出的影响。

如上图所示,在Embedding之后有三个箭头输进第一个muti-head attention模块,这三个箭头分别代表q(query), k(key), v(value)

这个qkv的三套组合主要是为了描述一个词在不同语境/文本下意思的区别,一个词的向量映射不能一直都一样,因为它的含义会根据文本而改变,所以qkv能够更准确的描述一个词在一个文本下的具体含义。

就比如“水课”的水与“水果”的水有语义上的区别。

QCK

  • Q代表“我想知道什么”
  • K代表“我能被问到什么”
  • V代表“我能提供什么信息”

假设每一个token是一个人, 然后他们都在一个屋子里。每一个人都有

  • 一个想提的问题(Q)
  • 能被问题的列表(K)
  • 他手上的知识 (V)

然后其中一个token环顾四周,开始决定多关注谁,他就会

  • 拿着自己的Q,问个问题,比如:我在这里是啥作用?
  • 他扫视所有其他人的K,看谁能回答这个问题 (这个过程就是矩阵相乘的运算)
  • 根据运算出的对于所有其他人匹配分数,他会分别去采集等量的V值。
  • 最终产出的矩阵为这个token对所有其他token在“我是啥作用”一题下的关系度。

用“我是水课”来举例:

这句话的kv表

TokenKey 向量(简写)Value 向量(简写)
表示“主语”信息“我”的语义
表示“动词”信息“爱”的语义
表示“名词属性(未定)”“水”的初始语义
表示“名词/学习相关”“课”的语义

我们Q可以是:我是什么水?是喝水的水,还是水课的水。

利用这个Q我们获得权重

Token向量匹配得分 权重 (softmax)
0.20.1
1.50.4
1.0(和自己)0.3
1.20.2

最后得出,token水更关注”爱“,和”课“,所以它不是喝水的水,而是跟课程相关。

在一个词在经历了语义向量和位置向量的编码后,会再乘以qkv三个向量,从而得出一个最终向量结果。这个结果就是所有其他token对当前该token语意的影响程度

Attention头

每一个attention的头,就是将一开始的input矩阵分别乘以qkv三个矩阵, 再用attention的softmax公式来获得最终矩阵。

所谓多头,本质就是通过拆分原本只有三个的qck权重矩阵,来更细化每一个“头”对于语义关系理解,通过一种拆分-> 分头理解 ->再重新组合得到最全面的理解的形式来更好的map token的语义。所以就可以在不变计算量的情况下扩大之前单头能够理解的语义范围

在单头attention中,qck三个矩阵的维度与input矩阵类似。

例如,一个四词的input矩阵维度可以是 4512。在单头中,qck三个权重矩阵的维度就会是 512512 。而在多头中,qck三个权重矩阵的维度就可以被分成8个 64*4 的矩阵。这样的话,attention的过程能做八次:

(4x512) x (512 x 64) = (4 x 64)

然后就能得出8个 (4 x 64)的矩阵。

我们最后再通过一个线性层把这8个矩阵再重新映射到一个最终的一个(4 × 512)的最终矩阵上。这个最终矩阵就会包含更广阔的语义信息。

在编码器的多头注意力模块产生结果后,transformer会把结果放进残差连接(add)和归一化(norm)过一遍。

残差链接的主要作用为防止前面的模块产出太差的结果。所以它把原始输入与前面模块产出的结果相加,来起到一定的结果质量的中和。

归一化则会将结果标准化

之后变进入编码器的第二板块,利用一个普通的前馈神经网络来增加整体模型对于非线性的一个更精确的表达,最终获得编码器的最后输出

解码部分

在解码器一侧,解码器会接受向右位位移一位的ground truth(答案)

比如如果是针对句子 "i love easy course", 它可能会是"I love _ _",

这个输入会经过一个masked多头自注意力模块。这个模块跟其他自注意力模块基本一样,但是这里的矩阵里包含的把每一个可能产生的填空组合,而这些的"填空题", 就可以让解码器更能预测下一个词

在经过masked多头自注意力模块的输出后,该输出会被作为query输入放进下一个注意力模块中,而这个新的注意力模块会同时接受刚从编码器输出的结果作为key和value的输入

在此之后transformer模型会继续套用残差连接+归一+前馈,最终产出一个(num of token x 512)的矩阵

这个矩阵再最后通过线性层来进行打分:把512的向量映射在一个拥有所有英文词的向量(可能有三万维里,根据该token对每一个英文词的关系打分。比如如果该token是water,那在英文词向量里的water一词的分数就会最大

在最后通过softmax进行标准化,把分数变成几率,所以token是water的话,那最后water一词的几率会最大

总结,Why Attention

这个自注意力模块主要解决了三个问题

  • 第一个是计算复杂的降低
  • 第二个是允许了并行处理的能力
  • 第三个是保留了长距离文本语义的理解能力,不管句子有多长,上下文含义的理解都还可以有