一、先接着第 1 讲的问题往下问

第 1 讲把语言模型的任务定成了一句话:P(xₜ₊₁ | x₁...xₜ)——给定前面所有的字,猜下一个。

这句公式里藏着一个没说破的工程问题:“前面所有的字"可以有任意长。第一个词的时候上下文只有 1 个 token,读到第一万个词的时候上下文有一万个 token。你不可能为每一种长度单独设计一个模型。

你读小说的时候是怎么处理这件事的?你不会在读到第 300 页时,把前 299 页重新摊开来看一遍。你脑子里始终维护着一个**“目前为止的印象”**——记得主角是谁、伏笔是什么、上一句刚发生了什么——每读一句新的话,就用这句话去更新一下这个印象,旧的原文本身可以忘掉。

这正是 1990 年前后研究者给神经网络版语言模型想出的第一个靠谱方案的直觉:循环神经网络(Recurrent Neural Network,RNN)。

二、打个比方:一个不断被重写的便利贴

想象你在传话筒游戏里,但规则改了一下:每个人不是把原话转述给下一个人,而是在一张便利贴上写下"到目前为止我理解的剧情摘要”,把便利贴连同下一句话一起传给下一个人。下一个人读到便利贴 + 新的一句话,擦掉重写一张新的便利贴,继续往下传。

便利贴₀ (空白)
   │  + 读到"从前有座山"
   ▼
便利贴₁ "开头是山"
   │  + 读到"山里有座庙"
   ▼
便利贴₂ "山里有庙"          ← 注意:不是"山+庙"两张贴纸叠着,是重写成一张新的
   │  + 读到"庙里有个老和尚"
   ▼
便利贴₃ "山中庙里一位老和尚"

⭐ 关键的设计选择在这里:便利贴的大小永远不变。不管你传了 3 句话还是 3000 句话,最新那张便利贴的字数上限是一样的。这个"大小固定、不断被重写"的便利贴,就是 RNN 里的隐藏状态(hidden state)。

三、把这个直觉写成公式

RNN 在每一个时间步做的事情,用符号写出来是:

hₜ = f(hₜ₋₁, xₜ)

读作:第 t 步的隐藏状态,由"上一步的隐藏状态"和"这一步新读到的词"共同决定,f 是一个带参数的神经网络(第 5 讲讲过的那种"一层"的推广)。

要预测下一个词,就是拿当前这张"便利贴" hₜ 去算词表上的概率分布:

P(xₜ₊₁ | x₁...xₜ) = g(hₜ)

⭐ 这里有一个对后面几讲很重要的设计特征:f 和 g 在每一个时间步都是同一套参数。 处理第 1 个词和处理第 10000 个词,用的是完全相同的一套权重——这叫参数共享(parameter sharing)。好处很直接:模型不需要为每一个可能的长度单独学一套参数,一套 f 可以套到任意长的序列上。

循环神经网络(RNN):通过在每个时间步复用同一组参数、把历史信息压缩进一个固定大小的隐藏状态里,从而处理任意长度序列的神经网络结构。

原始 RNN 很快被发现一个问题:训练时隐藏状态里的信号,传得越远衰减得越厉害(下一节详细讲)。1997 年 Hochreiter 和 Schmidhuber 提出的 LSTM(长短期记忆网络),给便利贴的更新机制加了三道"闸门":遗忘门(决定便利贴上哪些旧信息该擦掉)、输入门(决定新信息里哪些值得写上去)、输出门(决定便利贴上哪些内容此刻该被读出来用)。GRU 是它更精简的一个变体。

⚠️ 这一节到这里,LSTM 听起来像是把问题解决了。它只是把问题缓解了,没有解决——第四节会说明为什么闸门机制治标不治本,而且即便真能治好这一条,还有一条更致命的瓶颈是闸门完全无能为力的。

四、三个结构性瓶颈

这一节是本讲的重点。RNN 这个设计有三个问题,前两个是"效果"问题,第三个是"能不能训得起来"的问题——后者才是它最终被放弃的真正原因。

瓶颈一:固定大小的便利贴,是一个信息瓶颈

回到第二节的比方:便利贴的大小是固定的,但要概括的内容可以任意长。

这在信息论上是一个必然的矛盾:一个固定维度的向量,能装下的信息量是有上限的。读到第 10 个词的时候,hₜ 还能比较完整地保留这 10 个词的信息;读到第 10000 个词的时候,早期的细节必然被不断的"重写"挤掉——不是模型不想记,是容器的大小从设计上就不够。

第 1 步:  [山]
第 2 步:  [山, 庙]
第 3 步:  [山中庙, 和尚]              ← 开始概括,细节开始丢
第 100 步: [大概是某种佛教叙事......] ← 早期具体细节基本挤没了

瓶颈二:梯度消失——越远的词,学习信号越弱

这一条需要借用第 6 讲会正式讲的"反向传播",这里先给结论和直觉,细节留到那一讲。

训练神经网络,要靠一个叫梯度的信号,告诉每一个参数"往哪个方向调、调多少"。RNN 因为在每个时间步反复应用同一个 f,这个信号要一路往回传,经过多少个时间步,就要被同一套变换连续作用多少次。

⭐ 这和"利息复利"是同一种数学结构:如果每一步的信号会被乘上一个小于 1 的系数,传 3 步问题不大,传 300 步之后这个信号会指数级衰减到几乎为零——这叫梯度消失(vanishing gradient)。反过来,如果这个系数略大于 1,信号会指数级爆炸,训练直接发散,叫梯度爆炸(这个方向的问题更容易通过限制数值范围来工程解决)。

梯度消失的直接后果是:模型学不会"第 1 个词和第 500 个词之间有关系"这种长距离依赖,因为从第 500 步往回传到第 1 步的学习信号,实际上已经传不到了。LSTM 的三道闸门,本质上是设计了一条更"平缓"的信息通路,让梯度衰减得慢一点——它把能有效处理的距离从几十步拉长到几百步,但没有从根本上取消这个衰减,序列足够长时,问题依然存在。

瓶颈三:顺序依赖——这才是真正压垮 RNN 的一条

前两条是"效果不够好",这一条是"训不动"。

看回公式 hₜ = f(hₜ₋₁, xₜ):要算出 h₁₀₀,必须先算出 h₉₉,而 h₉₉ 又必须先算出 h₉₈……这是一条环环相扣的链条,中间没有任何一步可以跳过。

h₁ ──▶ h₂ ──▶ h₃ ──▶ ... ──▶ hₙ
(每一步都必须等前一步算完才能开始,不能同时算)

这在"能不能对"这件事上没问题,但在"算得快不快"上是致命的。今天用来训练模型的硬件(GPU)最擅长的事情是大规模并行——同时做几万个互不依赖的计算。RNN 的这条链条从结构上堵死了并行的可能:不管你有多少块 GPU,处理一条长度为 1000 的序列,就是必须老老实实算 1000 步,一步都省不掉。

⭐ 这一条才是 RNN 真正被放弃的理由,而不是"效果不够好"。第 1 讲第五节说过,这个领域这些年的核心赌注是"规模换效果"。可是如果一个架构的计算量没法铺开到成千上万块芯片上同时算,“做得更大"这条路从一开始就走不通——不是不想训练更大的 RNN,是训练时间会长到不现实。2017 年那篇提出 Transformer 的论文,标题就叫《Attention Is All You Need》,直译过来几乎是在挑衅 RNN:“你需要的从来不是循环,是注意力”——第 9 讲会看到,它的核心改动之一,就是把这条必须顺序执行的链条,换成了一种可以整体一次性并行算完的结构。

五、和后面课程的关系

这一讲的三个瓶颈,不是三条孤立的吐槽,它们分别对应 Transformer 设计里三个针锋相对的回应:

RNN 的瓶颈 Transformer 的回应 对应章节
固定大小隐藏状态,历史被压缩变形 每个词直接访问所有其他词,不经过压缩 第 9 讲:自注意力
梯度消失,长距离依赖学不到 任意两个位置之间只隔一步计算,不随距离衰减 第 9 讲:自注意力
顺序依赖,无法并行 所有位置的计算可以同时进行 第 9、10 讲

⚠️ 但天下没有免费的午餐——这门课反复强调"每个设计决策在放弃什么”。RNN 每一步只需要常数级的计算和存储,处理任意长度序列的开销是线性增长的;第 9 讲会看到,自注意力为了让每个词都能直接看到所有其他词,付出的代价是计算量随序列长度平方级增长。RNN 输在了"能不能被硬件并行"上,但它在"计算量随长度增长的快慢"这个指标上其实是占优的——第 23 讲讲长上下文的工程瓶颈时,你会发现这个被 Transformer 甩开的旧账,其实一直没有被真正还清,只是被换了一种方式重新面对。

六、本讲小结

  • RNN 的核心设计:用一个大小固定的隐藏状态 hₜ = f(hₜ₋₁, xₜ) 滚动概括历史,所有时间步共享同一套参数,从而处理任意长度的序列。
  • 瓶颈一(信息瓶颈):固定大小的容器装不下任意长的历史,早期细节会被后续更新逐渐挤掉。
  • 瓶颈二(梯度消失):训练信号要经过和序列等长的连续变换往回传,长序列下会指数级衰减,导致模型学不到远距离的依赖关系;LSTM 靠三道闸门缓解,但不能根治。
  • ⭐ 瓶颈三(顺序依赖)才是致命伤:hₜ 依赖 hₜ₋₁,整条链无法并行计算。这不是"效果差",是"在现代并行硬件上训不动、训不快",直接堵死了"做得更大"这条路。
  • ⭐ RNN 不是"错误"的设计,是不适配硬件约束的设计——它在"每步计算量恒定、显存占用低"这件事上其实优于 Transformer,只是这个优点没能换来当年能用上的训练速度。
  • Transformer(第 9 讲起)针对性地解决前两个瓶颈、绕开第三个瓶颈,但代价是计算量随长度平方级增长——这条代价会在第 23 讲长上下文那一讲重新找上门。

思考题

  1. “便利贴"的比方里,为什么便利贴的大小必须固定?如果允许便利贴随着读到的内容越来越长而不断变大,会带来什么新的问题(提示:想想这和"任意长度"的处理能力之间的矛盾)?
  2. 梯度消失的"复利"类比里,如果每一步衰减系数是 0.9,传 10 步、100 步、1000 步分别会衰减到大约原来的多少(提示:0.9 的幂)?这个数字能不能说明为什么 LSTM 只能把"有效距离"从几十步拉长到几百步,而不是无限长?
  3. 为什么说"顺序依赖"是比"梯度消失"更根本的问题?如果只解决梯度消失(比如发明一种完全不衰减的门控机制),RNN 能不能像 Transformer 一样被训练到今天的规模?
  4. 参数共享(每个时间步用同一套 f)带来了"能处理任意长度"的好处,你能想到它可能带来什么坏处吗(提示:模型要用同一套参数应付句首和句尾完全不同的角色)?
  5. 本讲第五节的表格说 RNN 每步计算量恒定、Transformer 随长度平方增长——这是否意味着处理一个足够长的序列时,RNN 反而会比 Transformer 更快?现实中为什么很少有人这么做(可以先猜,第 23 讲会有更完整的答案)?