RNN的输入、隐藏状态、输出形状和主要缺陷是什么?
沿时间步追踪x、h、output和hn,理解共享参数、序列输出以及长期依赖问题。
DETAILED ANSWER
直接结论
RNN在每个时间步同时接收当前输入x_t和上一时间步隐藏状态h_(t-1),生成新的h_t。同一套参数沿时间重复使用,因此能够传递历史信息,但也带来难并行、长期依赖和梯度消失或爆炸问题。
一个时间步发生了什么
z_t = W_ih × x_t + W_hh × h_(t-1) + 偏置
h_t = tanh(z_t)
x_t:当前token的Embedding。h_(t-1):上一时间步的隐藏状态。h_t:融合当前输入和历史信息后的新状态。W_ih:处理当前输入。W_hh:处理上一隐藏状态,并在所有时间步共享。
seq_len和PyTorch形状
seq_len表示一个样本包含多少个时间步;对文本来说,通常就是序列中的token数量。
PyTorch默认输入形状:
[seq_len, batch, input_size]
初始隐藏状态:
[num_layers, batch, hidden_size]
输出:
output:[seq_len, batch, hidden_size]
hn:[num_layers, batch, hidden_size]
output保存最后一层RNN在所有时间步的隐藏状态;hn保存每一层最后一个时间步的隐藏状态。对单向RNN有:
output[-1] = hn[-1]
文本生成为什么每个位置都要输出
文本生成需要在每个时间步预测下一个词:
RNN输出:[seq_len, batch, hidden_size]
展平:[seq_len × batch, hidden_size]
全连接层:[seq_len × batch, vocab_size]
这相当于为序列中的每个位置分别完成一次词表分类。
RNN的主要缺陷
- 长序列反向传播容易出现梯度消失或爆炸。
- 难以学习相距很远的信息依赖。
- 当前时间步依赖上一时间步,难以充分并行。
- 序列越长,训练和推理通常越慢。
面试口述
RNN在每个时间步同时接收当前输入和上一时刻隐藏状态,通过共享参数更新当前隐藏状态,因此能够保存历史信息。训练时使用BPTT沿时间反向传播。但长序列中的梯度需要连续经过循环权重和激活函数,容易出现梯度消失或爆炸,而且时间步之间存在依赖,无法充分并行。
