动手学深度学习——RNN
1. 前言
前面我们已经顺着李沐这条线,依次学了:
-
序列模型
-
文本预处理
-
语言模型
-
语言模型代码
现在,一个很自然的问题就来了:
如果 n-gram 只能看固定长度上下文,那有没有一种模型,能够更灵活地“记住前面发生过什么”?
这就引出了这一节的主角:
RNN(Recurrent Neural Network,循环神经网络)
RNN 是深度学习中最经典的序列模型之一。
它的重要意义在于:
让模型在处理当前输入时,能够利用之前时刻留下来的状态信息。
也就是说,RNN 不再像普通前馈网络那样把每个输入完全当成独立样本处理,
而是把“历史”带到了当前时刻。
2. 为什么需要 RNN
先回顾一下前面的 n-gram 语言模型。
它的基本思想是:
-
用前 1 个词预测下一个词,得到 bigram
-
用前 2 个词预测下一个词,得到 trigram
-
更一般地,用前 n-1 个词预测当前词
这个思路虽然直观,但有明显问题:
2.1 上下文窗口固定
如果我们只看前两个词,那么更久之前的信息就看不到了。
2.2 长依赖处理困难
例如一句很长的话里,当前词可能和很久之前某个词有关,
而 n-gram 很难处理这种情况。
2.3 参数和统计代价迅速变大
上下文一旦拉长,组合爆炸,数据稀疏问题更严重。
所以,我们希望有一种模型,能够做到:
不必死板地固定窗口长度,而是把历史信息压缩进一个“状态”里,持续传下去。
这正是 RNN 的核心动机。
3. 什么是 RNN
RNN 的全称是:
Recurrent Neural Network
中文叫:
循环神经网络
这里“循环”两个字,不是说网络真的绕圈跑,
而是说它在时间维度上有一种“状态递归传递”的结构。
简单来说,RNN 在每个时间步都会做两件事:
第一件:接收当前输入
例如当前这个词、当前这个字符、当前这个时间点的数值。
第二件:接收上一时刻的隐藏状态
这个隐藏状态可以理解为:
模型对过去信息的内部记忆
于是,RNN 在当前时刻的输出,不仅取决于当前输入,
还取决于“过去留下来的状态”。
4. RNN 的核心思想
RNN 最核心的一句话就是:
当前状态 = 当前输入 + 过去状态 的共同函数
如果写成更数学一点的形式,通常是:
H_t = f(X_t, H_{t-1})
这里:
-
X_t:第 t 个时间步的输入 -
H_{t-1}:上一时刻隐藏状态 -
H_t:当前隐藏状态 -
f:某种非线性变换
这条式子非常重要,它基本就是整个 RNN 的灵魂。
它说明:
当前时刻不是孤立的,而是历史延续的一部分。
5. 什么是隐藏状态
“隐藏状态(hidden state)”是 RNN 里最关键的概念之一。
你可以把它理解为:
模型在当前时刻对“过去已经看到的信息”的内部摘要
例如处理一句话时:
-
第一个词来了,模型更新一次状态
-
第二个词来了,再结合前一个状态继续更新
-
第三个词来了,再往后传
于是到了第 t 步时,隐藏状态 H_t 就像是:
到目前为止,模型对前 t 个输入的“记忆压缩结果”
所以,RNN 的记忆能力,本质上就体现在隐藏状态的递推里。
6. RNN 和普通前馈网络的区别
这个对比一定要讲清楚。
6.1 普通前馈网络
普通神经网络通常是:
-
输入一个样本
-
经过若干层变换
-
输出结果
每个样本之间通常彼此独立,网络不会自动记住前一个样本发生了什么。
6.2 RNN
RNN 则不同:
-
它在处理当前输入时
-
会把上一时刻的隐藏状态也一起拿来用
也就是说:
RNN 不是只看“现在”,它还带着“过去的记忆”一起工作。
所以,RNN 比普通前馈网络更适合处理有顺序依赖的数据。
7. RNN 在时间维度上是怎么展开的
RNN 画结构图时,常常会画成一个重复单元,在时间维度上不断展开。
例如序列:
x1, x2, x3, x4
对应的 RNN 计算过程可以理解为:
-
x1和初始状态一起,得到h1 -
x2和h1一起,得到h2 -
x3和h2一起,得到h3 -
x4和h3一起,得到h4
这样一层层沿时间传播。
这就是为什么它叫“循环”网络:
同一个单元结构,在不同时间步被重复使用。
8. 为什么说 RNN 参数是共享的
RNN 在每个时间步上执行的计算形式是一样的。
也就是说:
-
第 1 步用一套参数
-
第 2 步还是这套参数
-
第 3 步仍然是这套参数
这叫做:
时间维上的参数共享
这一点非常重要,因为它意味着:
-
模型可以处理不同长度序列
-
参数量不会随着序列变长而线性暴涨
-
网络学到的是“一般性的时间递推规律”
所以 RNN 的本质不是“每一步一个新网络”,
而是“同一个网络单元反复使用”。
9. RNN 的基本公式
最基础的 RNN 公式通常写成:
H_t = tanh(X_t W_xh + H_{t-1} W_hh + b_h)
以及输出:
Y_t = H_t W_hq + b_q
这里可以这样理解:
第一部分:输入到隐藏层
X_t W_xh
表示当前输入对隐藏状态的影响。
第二部分:上一状态到当前状态
H_{t-1} W_hh
表示历史信息对当前状态的影响。
第三部分:非线性激活
tanh(...)
让模型有更强表达能力。
第四部分:隐藏状态到输出
H_t W_hq
把当前隐藏状态映射成输出。
这组公式,就是最原始 RNN 的核心计算。
10. 为什么这里常用 tanh
在基础 RNN 中,隐藏状态更新常常会用 tanh 激活函数。
原因主要是:
-
它能把数值压到
[-1, 1] -
有利于状态保持在相对稳定范围
-
历史上在 RNN 中使用非常普遍
当然,后面更复杂的循环模型里还会出现:
-
sigmoid
-
门控机制
但在最基础 RNN 这里,tanh 是最典型的起点。
11. RNN 在语言模型里是怎么用的
前面我们讲语言模型时,说目标是:
根据前文预测下一个 token
这和 RNN 天然非常匹配。
例如给定字符序列:
t, i, m, e
RNN 可以这样做:
-
读入
t,更新状态并预测下一个字符 -
读入
i,继续更新状态并预测下一个字符 -
读入
m,继续更新状态并预测下一个字符 -
读入
e,继续更新状态并预测下一个字符
因为隐藏状态会不断携带前文信息,
所以模型理论上不需要像 n-gram 那样只盯着固定窗口。
12. 为什么 RNN 比 n-gram 更灵活
这是 RNN 的核心优势之一。
n-gram
只能看固定长度的历史,例如前 2 个词、前 3 个词。
RNN
通过隐藏状态递推,可以把历史信息不断压缩、传递。
也就是说:
它不需要手工指定“只看前几个词”,而是让模型自己学会如何利用历史。
这就让 RNN 具备了更强的上下文建模能力。
13. RNN 的输出一定每步都有吗
不一定,但常见有两种情况。
13.1 每个时间步都输出
例如语言模型中:
-
每一步都要预测下一个 token
所以常常每个时间步都有输出。
13.2 只在最后输出
例如某些序列分类任务中:
-
输入整句话
-
最后判断情感是正面还是负面
这时候只需要最后时刻输出。
所以 RNN 是很灵活的,
关键看任务需要什么样的输出形式。
14. RNN 的优点是什么
RNN 经典,不是没有原因的。
14.1 能处理序列数据
它天然适合文本、时间序列、音频等顺序数据。
14.2 能利用历史信息
比普通前馈网络更适合建模前后依赖。
14.3 参数共享
同一套参数沿时间展开,模型紧凑而统一。
14.4 输入长度灵活
理论上可以处理任意长度序列。
所以在深度学习发展早期,RNN 是序列建模的核心主角之一。
15. RNN 的主要问题是什么
虽然 RNN 很经典,但它也有明显局限。
15.1 长期依赖难学
虽然理论上能记很久,
但实际训练中,远距离信息往往很难真正保留下来。
15.2 梯度消失和梯度爆炸
在时间维度展开很长后,反向传播会出现数值问题。
15.3 训练并行性较差
因为时间步之间有依赖关系,不能像普通前馈层那样完全并行。
这些问题也正是后面 GRU、LSTM 出现的原因。
16. 什么是梯度消失和梯度爆炸的直觉
你现在不用把它想得太复杂,先抓住直觉即可。
RNN 训练时,要沿着时间维反向传播梯度。
如果序列很长,那么梯度会经历很多次连乘。
于是可能出现两种情况:
梯度越来越小
最后几乎传不回前面,这叫梯度消失。
梯度越来越大
数值迅速膨胀,训练不稳定,这叫梯度爆炸。
这两种问题都会让基础 RNN 在长序列上训练变得困难。
17. 李沐这一节最想让你理解什么
这一节最重要的,不是立刻背熟所有公式,
而是先把 RNN 的基本思想吃透:
第一,RNN 通过隐藏状态把过去信息传到现在
这是它区别于普通网络的根本。
第二,RNN 的参数在时间步之间共享
它不是每一步一个新模型,而是同一个单元不断展开。
第三,RNN 很适合语言模型
因为语言模型本质上就是序列预测问题。
第四,RNN 虽然强,但基础版本有长期依赖问题
这就为后面 GRU、LSTM 做铺垫。
18. RNN 和前面内容是怎么接上的
回头看这条线会很顺:
文本预处理
把文本变成 token 和索引。
语言模型
明确目标是“预测下一个词”。
语言模型代码
构造输入输出序列、batch、采样方法。
RNN
用神经网络真正去建模这个序列预测任务。
所以 RNN 不是突然冒出来的新东西,
它是前面整条主线自然推进到这里的结果。
19. 本节总结
这一节我们学习了 RNN,核心内容可以总结为以下几点。
19.1 RNN 是经典的序列模型
它通过隐藏状态递推来建模顺序依赖。
19.2 当前隐藏状态由当前输入和上一隐藏状态共同决定
这是 RNN 的核心递推公式。
19.3 RNN 的参数在时间步之间共享
同一个单元结构沿时间展开使用。
19.4 RNN 很适合语言模型
因为它能够利用前文信息来预测下一个 token。
19.5 基础 RNN 存在长期依赖和梯度问题
这也正是后面 GRU、LSTM 的出发点。
20. 学习感悟
RNN 这一节特别重要,因为它让“序列模型”第一次真正有了神经网络形态。
前面我们更多是在讲:
-
序列是什么
-
语言模型在做什么
-
数据怎么组织
而到了 RNN,这些问题第一次被统一到一个可训练的网络结构里。
你会发现,RNN 最核心的美感就在于:
让模型在处理当前输入时,不忘记自己刚刚经历过什么。
这正是“记忆”在深度学习里的最初体现。
更多推荐


所有评论(0)