吃透RNN


🔄 RNN 是如何训练的

1️⃣ 假设任务

任务:根据前面的词预测下一个词。
数据:句子 “I like AI”

目标:输入前 2 个词 → 预测第三个词 “AI”。


2️⃣ 前向传播(Forward)

  • 句子词向量化(embedding):

    • “I” → [1, 0, 0]
    • “like” → [0, 1, 0]
    • “AI” → [0, 0, 1]

第 1 步(输入 “I”)

h1=f(Whh0+Wxx1+b) h_1 = f(W_h h_0 + W_x x_1 + b) h1=f(Whh0+Wxx1+b)

输出隐藏状态 h1h_1h1

第 2 步(输入 “like”)

h2=f(Whh1+Wxx2+b) h_2 = f(W_h h_1 + W_x x_2 + b) h2=f(Whh1+Wxx2+b)

第 3 步(输入 “AI”)

h3=f(Whh2+Wxx3+b) h_3 = f(W_h h_2 + W_x x_3 + b) h3=f(Whh2+Wxx3+b)

最后输出:

y3=softmax(Wyh2) y_3 = \text{softmax}(W_y h_2) y3=softmax(Wyh2)

👉 预测第三个词的概率分布。


3️⃣ 损失函数

假设模型预测结果是:

  • “AI” 的概率 = 0.6
  • “like” 的概率 = 0.3
  • “I” 的概率 = 0.1

真实标签是 “AI”,所以损失函数 = 交叉熵:

L=−log⁡(0.6) L = -\log(0.6) L=log(0.6)


4️⃣ 反向传播(BPTT: Backpropagation Through Time)

这是 RNN 最特别的地方。

  • 普通神经网络只反向传播一层层参数。
  • RNN 有“时间展开”的结构,误差要沿着时间序列反传

举例:

  • 损失在第 3 步产生(预测错了)。
  • 误差不仅影响第 3 步的参数,还要往回传到第 2 步、第 1 步,因为它们的隐藏状态影响了后面的预测。

数学上:

∂L∂Wh=∑t∂L∂ht⋅∂ht∂Wh \frac{\partial L}{\partial W_h} = \sum_t \frac{\partial L}{\partial h_t} \cdot \frac{\partial h_t}{\partial W_h} WhL=thtLWhht

👉 也就是说,参数 WhW_hWh 的更新要考虑所有时间步。


5️⃣ 参数更新

使用梯度下降 / Adam 等优化器:

Wh=Wh−η⋅∂L∂Wh W_h = W_h - \eta \cdot \frac{\partial L}{\partial W_h} Wh=WhηWhL

Wx=Wx−η⋅∂L∂Wx W_x = W_x - \eta \cdot \frac{\partial L}{\partial W_x} Wx=WxηWxL

Wy=Wy−η⋅∂L∂Wy W_y = W_y - \eta \cdot \frac{\partial L}{\partial W_y} Wy=WyηWyL

其中 η\etaη 是学习率。


6️⃣ 小结(举例解释)

比如:

  • 第一次训练时,模型预测 “like” 的概率最高(错了)。
  • 反向传播会调整参数,让 “AI” 的概率升高,下次预测更准。
  • 训练很多次后,模型学会“当我看到 ‘I like’,下一个词更可能是 ‘AI’”。

一句话总结
RNN 训练的流程就是:

  1. 把序列展开成一连串的时间步;
  2. 前向传播得到输出;
  3. 计算损失(预测和真实差别);
  4. 反向传播误差,跨时间更新参数(BPTT);
  5. 迭代很多次,模型逐渐学会在序列上下文中预测。

2 啥是隐藏状态 为啥要有隐藏状态

1️⃣ 隐藏状态是什么?

简单说:
隐藏状态就是 RNN 的“记忆”,用来存储到当前时刻为止的上下文信息。

公式回顾:

ht=f(Whht−1+Wxxt+b) h_t = f(W_h h_{t-1} + W_x x_t + b) ht=f(Whht1+Wxxt+b)

  • xtx_txt:当前输入(比如“今天”这个词的向量)
  • ht−1h_{t-1}ht1:上一个时刻的隐藏状态(存的“昨天”的信息)
  • hth_tht:新的隐藏状态(融合了“昨天 + 今天”的信息)

2️⃣ 为什么需要隐藏状态?

如果没有隐藏状态,神经网络每次只看到一个输入:

  • 输入 “今天” → 模型只知道今天,没有上下文
  • 输入 “下雨” → 模型只知道下雨,不知道时间背景

👉 就像失忆症:模型每次只看一个词,没法记住前文。

有了隐藏状态,模型可以:

  • 在看到 “今天” 时,记住“时间是今天”;
  • 在看到 “下雨” 时,把“今天 + 下雨”都存起来;
  • 在预测 “要带什么” 时,利用前面存下来的“上下文”。

3️⃣ 举个例子

句子:

“我在北京出生,所以我最喜欢的城市是 ___”

  • 没有隐藏状态
    模型看到“最喜欢的城市是”,预测可能是“上海”“深圳”,它不知道“北京”出现过。

  • 有隐藏状态

    • 当看到“北京”时,隐藏状态 hth_tht 把“北京”存进去;
    • 当读到最后时,隐藏状态里还有“北京”的信息;
    • 于是模型可以预测“北京”。

👉 隐藏状态就是模型的“记忆仓库”。


4️⃣ 为什么叫“隐藏”?

因为它不是直接给我们看的 输出结果,而是模型在内部维护的一组数字。

  • 对人来说是“黑箱子”;
  • 对模型来说是“思维过程”。

比如:

  • 输入词向量维度可能是 300
  • 隐藏状态可以是 128 维的向量
  • 每一维都代表“记住了一点上下文信息”,但人类很难直接解读。

3 RNN 理解的难点 & 常见易错点


🔄 RNN 理解的难点

1. 隐藏状态的本质

  • 很多人觉得 隐藏状态 hth_tht 是某种“确定的知识点”,但其实它就是一个 向量(很多数字),存储了到目前为止的上下文信息。
  • 每一维没有明确的语义,比如第 27 维不一定就是“天气”,它是模型自己学出来的。

2. 时间展开 (Unrolling)

  • RNN 在训练时会 展开成一个多层网络,每个时间步都是一层。

  • 很多人没搞清楚:

    • RNN 的参数在所有时间步是共享的,不是每一步都不同。
    • 训练时,反向传播要跨越多个时间步 (BPTT: Backpropagation Through Time)。

3. 长依赖问题

  • RNN 容易 遗忘很久以前的信息,这是它的核心弱点。

  • 难点在于理解为什么:

    • 因为反向传播时,梯度会指数级衰减(梯度消失)或爆炸。
  • 所以 RNN 记短语还行,记长句就力不从心。


4. 输入与输出的多种形式

RNN 有不同的结构,很多人容易混淆:

  • 一对一:输入一句话 → 输出一个分类(情感分析)
  • 多对一:输入一段语音 → 输出一句话(语音识别)
  • 多对多:输入英文句子 → 输出中文句子(机器翻译)
    👉 很多人一开始没分清楚任务形式,导致理解错误。

5. 训练中的梯度传播

  • RNN 的训练不是只在当前时间步更新参数,而是要把误差 往回传
  • 很多人以为:“我预测最后一个词错了,只会更新最后一步的参数”。
  • 其实:最后一步的误差会沿时间反传,影响所有前面的隐藏状态和参数。

⚠️ RNN 学习常见易错点

  1. 以为隐藏状态是固定知识

    • ❌ 错误理解:h 就是“记住北京”这种概念。
    • ✅ 正确理解:h 是一堆数字,经过训练,模型会把这些数字和“北京”对应上。
  2. 没理解参数共享

    • ❌ 错误理解:每个时间步用不同的权重。
    • ✅ 正确理解:所有时间步共享同一组参数(保证模型能泛化到任意长度序列)。
  3. 把 RNN 当成黑箱子,不知道怎么训练

    • ❌ 错误理解:RNN 训练和 CNN/MLP 一样简单。
    • ✅ 正确理解:RNN 的训练更难,需要 BPTT,容易梯度消失/爆炸,所以后来才有 LSTM/GRU 改进。
  4. 混淆输入序列和输出序列

    • 有些任务输入和输出长度不一样(比如翻译),很多人以为 RNN 只能一对一。
  5. 没理解长依赖问题

    • ❌ 错误理解:RNN 可以无限记忆。
    • ✅ 正确理解:RNN 在理论上可以,但实际上梯度问题让它记不了太长。

📌 总结

RNN 的难点和易错点主要集中在:

  • 隐藏状态到底是啥
  • 训练时时间展开 + 参数共享
  • 长依赖问题(为什么记不住很久以前的内容)
  • 任务形式的不同(多对一、多对多等)

4 展开 和 参数共享 两个核心点

1. 为什么要“展开”?

RNN 本身看起来像是一个循环:

ht=f(Wxxt+Whht−1+b) h_t = f(W_x x_t + W_h h_{t-1} + b) ht=f(Wxxt+Whht1+b)

这里:

  • xtx_txt:第 t 个输入
  • ht−1h_{t-1}ht1:上一步的隐藏状态
  • Wx,WhW_x, W_hWx,Wh:权重矩阵(参数,训练时要更新)
  • hth_tht:当前隐藏状态

这个循环很难直接训练,所以我们要 把时间轴展开,比如输入一个长度为 3 的序列:

x1 → [RNN] → h1
x2 → [RNN] → h2
x3 → [RNN] → h3

训练时,把它画成 3 层网络

x1 → (RNN单元, 参数 W) → h1
x2 → (RNN单元, 参数 W) → h2
x3 → (RNN单元, 参数 W) → h3

注意:虽然看起来像 3 层,但它们的参数 其实是同一份 W,只是数据不同。


2. 参数共享到底是啥?

很多人误解 RNN 以为每个时间步都有独立的参数:

  • ❌ 错误理解:

    W1 用于 h1
    W2 用于 h2
    W3 用于 h3
    
  • ✅ 正确理解:

    所有时间步都用同一套参数 W
    

这样做的原因是:

  • 让模型能处理任意长度的序列(句子有 5 个词还是 100 个词都可以)。
  • 保证在时间上保持一致性。

所以展开成 3 层只是 计算图上的复制,而不是参数上的复制。


3. BPTT:反向传播穿越时间

普通神经网络的反向传播,只要把误差从最后一层传回去就行。
但在 RNN 里,最后的输出不仅依赖最后的输入,还依赖前面所有隐藏状态。

举个例子:

序列:x1, x2, x3
输出:y3

如果 y3 错了,反向传播的时候:

  • 不仅要调整 W 对应 x3 的那次计算,
  • 还要往前传到 h2、h1,因为 h3 依赖 h2,h2 依赖 h1。

所以训练过程叫 Backpropagation Through Time (BPTT)

  • 就像把误差“倒流”回整个时间序列。

4. 一个具体例子

假设我们用 RNN 来预测句子最后一个词。输入 “我 爱 北”,目标输出 “京”。

  1. 正向传播:

    • x1=“我” → h1
    • x2=“爱” → h2
    • x3=“北” → h3 → y3=预测
  2. 输出 y3 错了(比如预测成“海”),计算误差。

  3. 反向传播:

    • 调整 h3 相关的参数(因为 y3 出错)
    • 误差往回传 → h2
    • 误差再传 → h1
    • 所有用到的参数 W_x, W_h 都会被更新。

✅ 所以总结:

  • RNN 展开成多层只是训练时的计算方式。
  • 每层不是独立的,参数在时间步之间共享。
  • BPTT 就是让误差沿着时间展开图往回传,从而更新所有时间步的参数。

看看案列


📝 输入序列

句子切成词或字(这里用字来举例):

[今][天][天][气][真][好][啊][,][我][喜][欢][太][阳]

假设我们的任务是:预测下一个字
👉 输入“今”,目标是“天”;输入“天”,目标是“天”;直到输入“太”,目标是“阳”。


🔄 训练过程(逐步展开)

1. 嵌入层 (Embedding)

每个字会被转成一个向量。
比如 “今” → [0.2, 0.5, -0.1, …] (128维向量)。


2. RNN 正向传播

前 3 个字为例:

  • t=1 输入 “今”

    h1 = f(Wx * x1 + Wh * h0 + b)
    

    得到隐藏状态 h1。

  • t=2 输入 “天”

    h2 = f(Wx * x2 + Wh * h1 + b)
    

    h2 记住了 “今+天”的信息。

  • t=3 输入 “天”

    h3 = f(Wx * x3 + Wh * h2 + b)
    

    h3 记住了 “今+天+天”的上下文。

依次类推直到 “阳”。


3. 输出层

在每个时间步,都会基于隐藏状态 h_t 输出一个预测:

y_t = softmax(Wy * h_t + c)

比如:

  • 输入 “今” → 输出 “天”(预测下一个字)
  • 输入 “天” → 输出 “天”
  • 输入 “气” → 输出 “真”
  • 输入 “喜” → 输出 “欢”
  • 输入 “太” → 输出 “阳”

4. 计算损失 (Loss)

每个时间步都有一个预测 y_t,和真实下一个字 y*_t。
损失函数一般用交叉熵:

Loss = Σ cross_entropy(y_t, y*_t)

5. 反向传播 (BPTT)

误差会“穿越时间”传回去:

  • 预测 “阳” 错了,更新 h12 → h11 → h10 … → h1
  • 同时更新共享参数 (Wx, Wh, Wy, b, c)。

这就是 Backpropagation Through Time


🚀 一个小例子(简化)

输入:“我 喜 欢 太 阳”
目标:“喜 欢 太 阳 ☀”

时间步输入字隐藏状态 h输出预测目标字Loss
t=1h1✅ 0
t=2h2✅ 0
t=3h3✅ 0
t=4h4海 ❌❌ 1
t=5h5☀️☀️✅ 0

总 Loss = 1。
反向传播时,会把 t=4 的错误梯度传回 h4、h3、h2、h1,更新所有参数。


✅ 总结:

  1. 输入字 → 向量化 → RNN 逐步处理 → 输出预测
  2. 每个时间步的输出和真实下一个字对比,计算损失
  3. 误差沿着时间展开的计算图反传 (BPTT),更新共享参数


📖 RNN 关键专业术语 & 通俗解释

1. 输入向量 (Input vector, xtx_txt)

  • 专业解释:序列在第 t 个时间步的输入,可以是词向量、像素、特征等。
  • 通俗解释:比如一句话“我爱北京”,在 t=1 时,输入就是“我”的数字表示。

2. 隐藏状态 (Hidden state, hth_tht)

  • 专业解释:RNN 在每个时间步保存的“记忆向量”,通过递归方式传递。
  • 通俗解释:就像大脑的短期记忆,看了“我”,再看到“爱”,脑子里记的就是“我+爱”。

3. 参数共享 (Parameter sharing)

  • 专业解释:RNN 在不同时间步使用相同的权重矩阵 Wx,WhW_x, W_hWx,Wh
  • 通俗解释:就像你用同一本字典去翻译一本书的每一页,而不是每一页换一本字典。

4. 时间展开 (Unrolling)

  • 专业解释:把 RNN 在时间维度的循环展开成一条链式结构,便于计算和训练。
  • 通俗解释:原本 RNN 像一只“走圈圈的时钟”,展开后就像“把指针走过的轨迹画成直线”,方便看清楚。

5. 输出 (Output, yty_tyt)

  • 专业解释:在每个时间步,基于隐藏状态预测出的结果,比如下一个字。
  • 通俗解释:看到“我爱”,你大概率会说“北京”;RNN 的输出就是这种预测。

6. 损失函数 (Loss function)

  • 专业解释:衡量预测结果和真实结果之间差距的函数。
  • 通俗解释:就像考试成绩,分数差距越大,说明学得越差。

7. 反向传播 (Backpropagation)

  • 专业解释:通过链式法则,把误差从输出层往输入层逐层传回去,更新参数。
  • 通俗解释:老师告诉你“最后一步写错了”,你就会反思“是不是前面公式写错了”,一步步找原因。

8. 时间反向传播 (BPTT, Backpropagation Through Time)

  • 专业解释:把普通的反向传播扩展到时间维度,误差会沿着时间步往回传递。
  • 通俗解释:如果最后一句话答错了,老师会追溯整个推理过程,甚至回到第一步,看看从哪开始偏的。

9. 梯度消失 / 梯度爆炸 (Gradient vanishing / exploding)

  • 专业解释:在长序列中,误差信号会因为链式相乘变得极小(消失)或极大(爆炸)。
  • 通俗解释:就像一串电话传话,传到第 100 个人时,要么声音小得听不见(消失),要么吼得太大声全乱套(爆炸)。

10. 长依赖问题 (Long-term dependency problem)

  • 专业解释:RNN 很难捕捉序列中相隔很远的依赖关系。
  • 通俗解释:比如听了“我昨天在北京”,过了很久才听到“吃了烤鸭”,普通 RNN 已经忘记“北京”了。

🎯 总结(精简版对照表)

专业术语通俗解释
输入向量当前看到的字/词的数字表示
隐藏状态大脑的短期记忆
参数共享所有时间步用同一本字典
时间展开把循环拉直成一条链
输出模型预测的下一个字
损失函数考试分数差距
反向传播错题往前查原因
BPTT错题往前查到整个时间过程
梯度消失/爆炸传话时声音越来越小/越来越大
长依赖问题前面很久的信息记不住

05-21
### 关于RNN的概念及其使用 #### RNN的核心概念 循环神经网络(Recurrent Neural Network, RNN)是一种专门用于处理序列数据的神经网络结构。它能够捕捉到输入数据中的时间依赖性和上下文信息,这是传统神经网络无法做到的[^4]。RNN的主要特点是其隐藏层的状态会随着每一次的时间步传递下去,从而形成一种“记忆”机制。这种特性使其非常适合应用于自然语言处理、语音识别等领域。 在具体实现上,RNN通过共享权重的方式,在不同时间步间重复利用相同的参数集合 \(W_i\) 和 \(W_h\)[^3]。这种方式不仅减少了模型所需的总参数量,还增强了模型对于时间序列数据的学习能力。 #### 解决实际问题时的选择策略 当面对具体的任务需求时,如何合理设置RNN的层数和单元数成为了一个重要考量因素。一般来说,增加层数与单元数目有助于提升模型的表现力,但这同时也增加了过拟合的风险。因此建议采用交叉验证的方法寻找最优配置[^1]。 另外值得注意的是,并非所有的应用场景都适合运用RNN。如果待分析的数据并不具备明显的顺序特征,则可能更适合选用卷积神经网络(CNN)或其他全连接型架构代替[^1]。 #### 提高训练效率的技术手段 针对RNN存在的梯度消失/爆炸等问题以及较低效的收敛速度状况,业界提出了多种改进措施。其中包括但不限于引入批量标准化(Batch Normalization),加入注意力(Attention)模块或是切换至Adam,RMSprop这类更为先进的优化器方案来加速整个迭代过程[^1]。 尽管如此,由于标准版RNN固有的串行计算属性限制了完全意义上的并行操作可行性,不过借助当今高性能GPU设备强大的并发运算优势依然可以在一定程度缓解此瓶颈影响。 #### Python代码示例:构建简单的RNN模型 以下是基于PyTorch框架创建一个基础版本单隐含层含有256个节点大小的RNN实例片段: ```python import torch.nn as nn num_hiddens = 256 vocab_size = len(vocab) # 定义RNNrnn_layer = nn.RNN(input_size=vocab_size, hidden_size=num_hiddens) ``` 上述代码展示了如何快速搭建起所需的基础组件部分[^2]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值