EECS498 · Sequence Models · 07

RNN: Carrying Information Through Time

进入 sequence 后,问题从“这张输入里有什么”变成“当前输出怎样依赖此前发生的事”。RNN 的答案是一份每一步都被重写的 hidden state。

80–100 分钟A4 CaptioningRecurrence · BPTT · bottleneck

30-second recall

30 秒回忆

你手写了 single-step RNN、whole-sequence forward/backward,并把 image features 变成初始 hidden state 生成 captions。

  1. h_t 同时依赖哪两类信息?
  2. token 1 的信息怎样到 token 10?
  3. 为什么 recurrence 难以沿 time 并行?

Before We Start

若 x_t=[N,D]、h_{t-1}=[N,H],Wx shape?

没有 hidden state 的 per-token classifier 能否区分同一词在不同 prefix 中的状态?

计算 h₁ 与 h₂ 可以完全并行吗?

Problem · 静态输入不再够用

图像分类一次接收完整 image;captioning 在 time t 生成词时,必须知道 image 以及先前生成了什么。最朴素的做法是对每个 word embedding 独立分类,但同一个 bank 或 it 在不同 prefix 中会得到同样处理。

如果没有 hidden state?

每一步只见 x_t,模型没有计算路径携带 x_1…x_{t-1}。输出可以随当前 token 变,却不能随历史改变。

从需求推出 recurrence

我们需要一份固定宽度的 state,读入当前 x_t,同时继承上一份 state:

a_t = x_t W_x + h_{t-1} W_h + b
h_t = tanh(a_t)

x_t       [N,D]
W_x       [D,H]
h_{t-1}   [N,H]
W_h       [H,H]
h_t       [N,H]
  1. x_tW_x 把当前 input 映射到 hidden feature space。
  2. h_{t-1}W_h 把历史摘要变换到同一 space。
  3. 相加让“现在”和“过去”共同决定 preactivation。
  4. tanh 提供非线性并限制 state 范围。
  5. 同一 W_x/W_h 在所有 time steps 共享,因此规则不随 t 改变。
Mental model

RNN 用一份不断更新的 H-dimensional hidden state 压缩过去;每个新 token 都在读取并重写这份摘要。

Worked Example · shape 与依赖一起走

取 N=2,T=3,D=4,H=5:

x[:,0,:] [2,4] + h0 [2,5] → h1 [2,5]
x[:,1,:] [2,4] + h1 [2,5] → h2 [2,5]
x[:,2,:] [2,4] + h2 [2,5] → h3 [2,5]

stack all hidden states → h [2,3,5]

Batch N=2 可同时处理;但 h2 的数值未出现前,h3 无法计算。T 轴上的依赖链没有因 tensor batching 消失。

x₁ → h₁
      ↓
x₂ → h₂
      ↓
x₃ → h₃
      ↓
... → h₁₀

token 1 到 token 10 的信息必须连续经历 9 次 state transition。路径长度随距离增长,这既影响信息保真,也影响 backward gradient。

Backpropagation Through Time

展开 recurrence 后,它就是共享参数的深计算图。若 loss 在 t=10,∂L/∂h₁ 包含许多 recurrent Jacobians 的乘积。典型 singular values 小于 1 时梯度反复缩小(vanishing);大于 1 时可能放大(exploding)。

∂L/∂h₁ = ∂L/∂h₁₀ · ∂h₁₀/∂h₉ · ... · ∂h₂/∂h₁

tanh 饱和区 derivative 接近 0,会进一步削弱长期 gradient。gradient clipping 可限制 explosion,却不创造一条短的 long-range path。

Your Code · 单步函数就是整条序列的原子

Your code · A4

A4/rnn_lstm_attention_captioning.py · rnn_step_forward()

View source →
affine = x.mm(Wx) + prev_h.mm(Wh) + b
next_h = torch.tanh(affine)
cache = (x, prev_h, Wx, Wh, next_h)

x.mm(Wx): [N,D]@[D,H]→[N,H];prev_h.mm(Wh): [N,H]@[H,H]→[N,H]。cache 保存 backward 局部导数所需的 activations/parameters,不是模型记忆本身。

Inline check. Wh 在 T=20 的 sequence 中有多少份 parameter copies?

Image captioning 中第一份记忆从哪里来?

你把 CNN image features 投影成 h₀,然后 word embeddings 逐步更新 state;vocab projection 从各 h_t 预测词。图像信息若要影响很晚的 word,也必须一路保存在 recurrent state 中。

image features[N,Dimg]
project to h₀[N,H]
word embeddings[N,T,W]
RNN hidden sequence[N,T,H]
vocab scores[N,T,V]

为什么这条路最终指向 Attention?

Recurrence

token 1 → h1 → h2 → ... → h10

长距离信息路径随距离增长;time steps sequential。

Attention

token 10 query ─────────→ token 1 value

内容匹配建立直接读取 edge;所有 query rows 可用 matrix multiply 同时计算。

Misconception diagnosis

RNN 不是“天然理解顺序”。它的结构令 h_t 只能从 h_{t-1} 到达,因此顺序被计算依赖编码;能否保留有用历史仍须训练。

End-of-Lesson Deep Checks

为什么 hidden state 既是 representation 又是 bottleneck?

它携带历史,但无论 sequence 多长都压入固定 H dimensions;早期细节必须在反复更新中保留。

为什么 batch 维可并行而 time 维不行?

不同 examples 无依赖;同一 example 的 h_t 需要刚算出的 h_{t-1}。

若 Wh=0,模型退化成什么?

h_t=tanh(x_tWx+b),各 time step 独立,不再携带 history。

Gradient clipping 解决 vanishing gradient 吗?

不直接解决;它限制过大 norm,主要处理 exploding gradient。

Transfer Questions

  1. 若每个 time step 都额外读取原始 image feature,image→late word 的路径如何改变?
  2. 双向 RNN 为什么不适合直接做严格 causal generation,但适合某些 sequence encoding?
  3. T=100 与 T=10 时,从第一个 token 到最后 loss 的 recurrent path length 各是多少?

闭卷解释

  1. 用 shape 解释一轮 rnn_step_forward。
  2. 为什么 scalar loss 能对共享 Wh 累积多个 time step 的 gradient?
  3. RNN 为什么有顺序 inductive bias,又为什么难并行?

Then I implemented: x_tWx + h_{t-1}Wh → tanh → h_t.

Now I understand: recurrence 用固定宽度 state 串起 sequence,但 long-range information 与 gradient 都必须穿过逐步链。

Connection · LSTM 要修哪一段?

普通 RNN 每一步通过 nonlinear transformation 完整重写 state。下一课增加更直接的 cell path 与 gates,改善长期记忆;随后检查它为何仍保留 sequential bottleneck。

Based on your implementation