首页 / 第二部分 · 注意力和 Transformer / 第 04 篇

第 04 篇 · 第二部分 · 注意力和 Transformer

从 RNN 到注意力机制:为什么非要换一套架构

RNN 并非能力不足,它受困于"必须一个词一个词地读"这一限制。它一度是最擅长处理语言的网络,可用得越多,越会发现两个明显局限:前面的话传到后面就淡化得几乎消失,而且它几乎无法并行计算。注意力机制正是为了绕开这两道障碍才出现的。这篇顺着时间线,把 RNN 的困境、它做过的补救,以及注意力如何兴起,逐条梳理一遍。

一、语言是序列:一个词的意思取决于上下文

图像是一整块,从哪看起都可以。语言则不同,它是一条线,词和词依次排列,顺序稍加改变,意思就会变化。

拿"苹果"来说。单看这两个字,你没法判断它是水果还是那家公司,得看前后文——"苹果很甜"和"苹果发布了新手机",同一个词,含义完全不同。再比如"打":打人、打水、打车、打酱油,四个搭配四种意思。更能说明问题的是词序,"我打你"和"你打我"用了同样的三个字,动作的主客完全反过来。

所以处理语言的第一道难关就是:不能把句子当成一个无序的袋子。词的位置、词与词之间的距离,全都带着信息。而这恰恰是前面讲的那些网络最不擅长的地方——它们接收的是定长输入,无法体现先后顺序。

二、RNN 的思路:把历史压进一个状态

循环神经网络(RNN)就是为解决序列问题而设计的。它的做法是"读一个,记一点,再读一个"。

网络里有一个隐藏状态,可以看成一个向量,常见的有 256、512、1024 维。每读入一个词,它就拿着"当前这个词"和"上一步的状态",算出一个新状态:

ht = tanh( W·ht−1 + U·xt + b )

然后再读下一个词,继续更新这个状态。一句话读完了,这个状态就代表整句话的"记忆";换一个任务,直接使用这个状态即可。参数量是固定的——不管句子是十个词还是一千个词,W、U、b 始终是那几套,反复使用。

打个比方,它像一个被允许做笔记的读者。每读一句,就把心得添到那页笔记上,读到后面时翻着笔记回忆前面。这个设计天然适应任意长度,看起来相当理想。

但那个笔记页,是固定大小的。这是它的根本限制:所有读过的内容,都必须装入同一个定长的向量里。读过的东西越多,压缩得越厉害,早先的细节被后来的覆盖掉——这个向量一旦被填满,就只能舍弃更早的信息。

三、传话游戏:梯度消失与长期依赖

训练 RNN 要用沿时间反向传播,也就是把上一篇讲的反向传播,沿着时间轴逐层回溯。每往回退一个时间步,就要按链式法则乘上一个因子。

问题就出在这连乘上。假设每一步的因子平均是 0.9——已经不小了。走过 50 步,是 0.9 的 50 次方,约等于 0.005;走过 100 步,就掉到约 0.00003。前面第 2 个词携带的那份信号,传到第 100 步时已经稀薄得几乎为零。误差无法回传,前面的那些权重收不到有效的训练信号,等于没有学到。

这个现象叫梯度消失。它的直接后果是长期依赖学不会——句子里隔得远的两个词之间的牵绊,模型抓不住。

想象一句长句:"我上个月在旧书店淘到的那本讲量子力学的书,它……"你要预测"它"后面接什么,得知道"它"指的是那本书,可"书"这个字与"它"中间隔了二十来个词,RNN 读到"它"的时候,那份记忆早被中间的许多词冲淡了。就像传话游戏,一句话从头传到尾,第一个人说的是"明天下午三点开会",传到第十个人变成了"明天下午有雨"——不是传话的人出错,而是这条链条太长,每一环都打了折扣。

梯度也可能反向发展:因子普遍大于 1,逐层相乘就会发散,这称为梯度爆炸。爆炸相对容易处理,设置一个上限把梯度截断,基本就能控制住;消失则更难处理,因为它是逐渐损耗殆尽,而不是一次性发散。

四、LSTM/GRU:加几道闸门加以缓解

1997 年,Hochreiter 和 Schmidhuber 提出长短期记忆网络(LSTM),专门冲着梯度消失去的。

它的核心改动是给状态配了一条传送带(论文里叫细胞状态),再加三道闸门来管流量:一道决定新信息要不要记进去,一道决定旧的记忆要不要扔掉,一道决定这个状态此刻要不要往外交付。闸门不是开关,而是 0 到 1 之间的软阀门,值由网络自己学出来。

为什么能缓解梯度消失?关键在于那条传送带上,信息主要是靠加法一路往前送的,而不是每步都被一整套权重矩阵反复乘。梯度顺着加法这条通路往回走,衰减就慢得多,能传得更远。打个生活化的比方:普通 RNN 像每读一页就把整本书重新抄一遍,越抄偏差越大;LSTM 像在一条传送带上放置内容,该保留的保留、该丢弃的丢弃,内容不必每页重抄。

后来 GRU 把三道门简化成两道,参数更少、训练更快,效果常常差不多。这类结构让 RNN 的长期记忆能力上了一个台阶,也确实在一段时间内被广泛使用。但要说彻底根治,其实并未实现。传送带也只是把衰减拖慢,句子上千个词时依然吃力。它只是权宜之计,不是根本解法。

五、但串行这件事始终没解决

更麻烦的还在后面,而且这次不是数学上的问题,而是结构上的限制。

RNN 必须按时间步一个一个算:要算第 t 步的状态,得先有第 t−1 步的结果。一环扣一环,谁也不能提前。可 GPU 最擅长的是什么?是把成千上万个彼此独立的运算一次性铺开、同时算。RNN 却天生串行,一千个词的句子就必须一步一步走满一千步,GPU 中的大量计算核大部分时间处于空闲。

训练的时候更受限制。你没法把一个批里不同位置的运算并行起来,因为位置之间互相依赖。序列一长,训练时间就线性增长,硬件再强也难以加快。这不是调整参数能解决的问题——是架构本身的形态决定的。简单说,RNN 慢,不是因为它计算量大,而是因为它无法同时计算。

六、注意力登场:翻译里的对齐问题

注意力机制最早出现在机器翻译这一具体任务中,因为它正好对应其中的一个难点。

早期的翻译模型是"编码器—解码器"结构:编码器把整句源语言读一遍,压缩成一个向量;解码器再从这个向量出发,一个词一个词地输出译文。注意,这又是那个固定大小的瓶颈——整句意思被压缩进一个向量里,句子越长,损失得越多。

还有一个更细的问题:对齐。翻译"我爱你"成"I love you",生成"love"的时候最该看的是"爱",生成"you"的时候最该看的是"你"。可编码器只给了解码器一个笼统的整句向量,它根本不知道此刻该关注原文的哪一个词。就像一个人把整篇原文压缩成一句概要,再照着概要写译文,写到哪里都无法对齐。

七、Bahdanau 注意力:让解码器回顾原文

2014 年,Bahdanau 等人给出了新的解法:不再压缩成一个向量,而是把编码器每一步的状态全部保留——一句话有几个词,就保存几份状态。

解码时,每要生成一个词,就让解码器拿着自己当前的状态,去和源句里每一个位置的状态算一遍相关度,分数越高、权重越大,然后按这些份量加权求和,拼出一个"这一步专用"的上下文向量。生成"love"时,"爱"那个位置自然拿到最高权重;生成"you"时,则轮到"你"获得更高权重。

等于说,解码器每写一个词,就回到原文里重点查看最该关注的那个位置。相关度是算出来的、可训练的,不是人手工标注的——模型自己学会了怎么对齐。这是注意力机制一次标志性的早期应用,虽然当时它还是搭在 RNN 上的一个附加模块。

八、从"跨句对齐"到"自己看自己"

到这儿,注意力的价值已经很清楚了:它绕开了固定向量的瓶颈,让模型能动态地决定看哪里。

那再往前推一步——这种事只能发生在"源句和解码器之间"吗?同一句话内部,能不能也这样处理?答案是肯定的。读"他"这个位置时,让它回头在整句话里找最相关的"小明",这就是自注意力:句子自己对自己做注意力,每个词都去全句里检索一遍。

真正革命性的一点在于:自注意力是一次把整句话铺开同时算的,所有位置两两算相关度,彼此之间没有先后依赖。RNN 那道串行的枷锁,就此被绕开了。2017 年那篇《Attention Is All You Need》做出了一个大胆选择——把 RNN 完全去掉,网络里只保留注意力和前馈层,Transformer 由此诞生。

下一节,我们把自注意力按零件拆开,看 Q、K、V 究竟在做什么。

参考资料

  1. Jeffrey L. Elman, Finding Structure in Time, Cognitive Science, 1990. crl.ucsd.edu/~elman/Papers/fsit.pdf(早期 RNN 的奠基工作)
  2. Sepp Hochreiter, Jürgen Schmidhuber, Long Short-Term Memory, Neural Computation, 1997. bioinf.jku.at/publications/older/2604.pdf(LSTM 原始论文)
  3. Yoshua Bengio, Patrice Simard, Paolo Frasconi, Learning Long-Term Dependencies with Gradient Descent is Difficult, 1994. ieeexplore.ieee.org/document/279181(梯度消失与长期依赖的经典分析)
  4. Dzmitry Bahdanau, Kyunghyun Cho, Yoshua Bengio, Neural Machine Translation by Jointly Learning to Align and Translate, 2014. arXiv:1409.0473(注意力机制的首次提出)
  5. Ashish Vaswani 等, Attention Is All You Need, NeurIPS 2017. arXiv:1706.03762(彻底去掉 RNN 的 Transformer)
  6. Andrej Karpathy, The Unreasonable Effectiveness of Recurrent Neural Networks, 2015. karpathy.github.io/2015/05/21/rnn-effectiveness(RNN 能做什么的直观演示)