如果你用手机输入法打:
我 今天 中午 在 食堂 吃了 一个 ___
它大概率会跳出"苹果""米饭""面条",而不是"飞机""汽车""石头"。
你有没有想过:输入法怎么知道后面该接食物?
这背后可能就有一种神经网络的思想------RNN,循环神经网络。
别被名字吓到。
RNN 说白了就是一个会边读边记小本本的神经网络。它按顺序读东西,每读一个,就翻翻旧笔记,再写新笔记,然后根据笔记猜下一个。
下面我们用一个例子从头讲到尾,把 RNN 的背景、原理、优缺点都揉进去。
一、为什么需要 RNN?
普通神经网络像什么?像你看一张张单独的照片。
比如判断一张图是不是猫,它只看这一张图,不需要记得上一张图是什么。
但很多问题不是照片,而是连续剧:
· 读句子:词是一个一个来的;
· 听语音:声音是一段一段来的;
· 看股票:价格是一天一天变的;
· 测天气:温度是一小时一小时变的;
· 甚至 DNA:碱基也是一个一个排列的。
这些东西有顺序,而且前面的内容会影响后面。
比如:
我 昨天 去 超市 买了 两个 ___
如果只看"两个",你猜"苹果"可以,"飞机"也可以,"汽车"也可以。
但结合前面的"去超市""买了",你大概率猜"苹果、香蕉、面包",不会猜"飞机"。
再比如:
狗咬人
人咬狗
词一样,顺序不同,意思完全相反。
普通神经网络容易把句子当成一堆词,分不清顺序。
RNN 就是为了解决这种"有顺序、要记忆"的问题。
二、RNN 的核心:记忆小本本
RNN 的做法是:一个词一个词读,手里拿个小本本。
这个小本本,专业上叫隐藏状态。
你可以把它理解成记忆。
每读一个词,RNN 就做几件事:
-
看当前这个词;
-
翻翻小本本,看看前面记了什么;
-
把"当前词 + 旧记忆"合起来,写成新记忆;
-
根据新记忆,猜下一个词。
一句话:
当前输入 + 旧记忆 = 新记忆。
而且,读每个词时,它用的是同一套规则。
不会读"我"用一套大脑,读"吃"又换一套大脑。
这叫参数共享,好处是参数量少,还能处理长短不一的句子。
RNN 里的"循环"在哪?
就是:上一步的记忆,会传给下一步。
像接力棒一样,一棒一棒传下去。
如果用稍微正式一点的话说:
· 第 t 步的输入叫 x_t,比如第 t 个词;
· 第 t 步的记忆叫 h_t;
· 上一步记忆叫 h_{t-1};
· 新记忆由当前输入和旧记忆共同决定;
· 输出 y_t 根据新记忆产生。
你不用记公式,只要记住:每一步都在更新小本本。
三、完整例子:输入法怎么猜出"苹果"
我们还是用输入法这个例子。
用户输入:
我 今天 中午 在 食堂 吃了 一个 ___
RNN 开始一个词一个词读。
我们可以用一个表格来看它的小本本怎么变:
时间步 读到的词 旧记忆 新记忆(小本本更新) 输出/预测
1 我 空 说话人是我 还不用猜
2 今天 说话人是我 说话人是我,时间大概是今天 还不用猜
3 中午 今天 时间是今天中午 还不用猜
4 在 今天中午 下面可能要出现地点 还不用猜
5 食堂 可能接地点 地点是食堂,食堂常和吃饭有关 还不用猜
6 吃了 地点食堂 动作是吃,后面可能接食物 还不用猜
7 一个 动作是吃 数量是一个,后面很可能接名词,而且是能吃的东西 开始预测
8 ? 食堂+吃了+一个 综合记忆:在食堂吃了一个...... 苹果 0.40,米饭 0.30,面条 0.20,飞机 0.01,汽车 0.01
于是输入法跳出:苹果。
你看,它不是只看"一个",而是记得前面有"食堂""吃了",所以猜食物。
如果把句子打乱:
一个 吃了 食堂 在 中午 今天 我
RNN 读到的顺序变了,小本本的内容也会乱,猜出来的东西可能很奇怪。
这正好说明:RNN 不是把词当一堆袋子,而是按顺序理解。
四、RNN 怎么学会猜的?
一开始,RNN 的小本本乱写,猜得也不准。
比如用户输入:
我 今天 中午 在 食堂 吃了 一个 ___
正确答案是"苹果",但 RNN 猜了"飞机"。
老师就说:错了,调整规则。
调整的时候,错误会从"飞机"往回传:
· 最后一步:不该猜飞机;
· "一个"那一步:应该更强调后面接食物;
· "吃了"那一步:应该记住"吃";
· "食堂"那一步:应该记住地点和吃饭有关。
这个过程反复几百万次,RNN 就慢慢学会:
看到"食堂 + 吃了 + 一个",后面大概率是食物。
专业上把这个训练叫 BPTT,时间反向传播。
你不用记名字,只要理解成:把整句话读完,算总错误,然后倒着追责,改小本本的记法。
训练时还会用到一个东西叫损失函数。
比如正确答案是"苹果",模型给"苹果"的概率只有 0.1,给"飞机"的概率却有 0.6,那损失就很大。
损失越大,说明错得越离谱,模型就要大改;损失小,就小改。
通过不断调整,模型才慢慢变准。
五、RNN 的优点
还是用输入法这个例子。
第一,能处理变长句子。
用户打"吃了"可以猜,打"我今天中午在食堂吃了一个"也可以猜。
第二,有记忆。
它能记住"食堂""吃了",所以不会猜飞机。
第三,懂顺序。
"我打你"和"你打我",RNN 读的顺序不同,小本本不同,结果也不同。
第四,参数共享。
读"我"和读"吃"用的是同一套规则,不用给每个词单独配一套系统。
第五,适合序列数据。
文本、语音、股票、天气,都能用类似思路。
第六,是很多高级模型的基础。
LSTM、GRU、Transformer 都和它有关系。
六、RNN 的缺点
RNN 不是万能的,它也有明显短板。
缺点一:记性不够长
我们把句子加长:
我 昨天 在 图书馆 借了 一本 关于 历史 的 书,今天 我 想 去 还 那 本 ___
这里正确答案应该是"书"。
但如果中间隔了太多词,普通 RNN 可能已经忘了前面借的是"书",反而猜"历史"。
这就是长依赖弱:
隔得太远的信息,普通 RNN 记不住。
就像你听一个人讲故事,讲了半小时,前面的人名你可能已经忘了。
缺点二:传话游戏会出问题
训练时,错误要从最后往回传。
如果句子很长,传着传着:
· 信息越来越小,最后没了,叫梯度消失;
· 信息越来越大,最后乱套,叫梯度爆炸。
就像传话游戏,传 10 个人还行,传 100 个人就全变样了。
梯度消失会让前面的词学不到东西;梯度爆炸会让训练不稳定,甚至崩掉。
缺点三:不能并行,算得慢
RNN 必须读完"我"才能读"今天",读完"今天"才能读"中午"。
不能同时算,所以训练慢。
像接力赛,不能所有棒同时跑。
现在很多大模型用 Transformer,就是因为它能并行处理,训练快得多。
缺点四:单向 RNN 只能看过去
有些填空需要看未来。比如:
我 今天 心情 很 ___,因为 考试 得了 满分。
只看前面"心情很",你可能猜"开心",也可能猜"难过"。
但看到后面"得了满分",就知道应该填"开心"。
普通单向 RNN 只能看过去,看不到后面的"满分"。
所以后来有了双向 RNN,同时看前面和后面。
缺点五:层数多了难训练
像很多个传话游戏串起来,越深越难教。
每多一层,信息传递就更复杂,梯度问题也更严重。
缺点六:记忆容量有限
小本本只有那么大,不可能记住所有细节。
重要的信息可能被挤掉,不重要的信息反而占地方。
七、后来怎么改进?
还是输入法这个例子。
· LSTM / GRU:给小本本加"门"。
重要的"书""食堂""吃了"一直留着;不重要的"今天""中午"可以慢慢忘掉。
就像笔记本有了"保留""删除""重点标记"按钮。
· 双向 RNN:同时看前文和后文。
填空时既看前面,也看后面。
· 深层 RNN:把多个 RNN 叠起来,像从"字"到"词"到"句"到"段"逐层理解。
· Encoder-Decoder:先读完整句话,再生成另一句话。
机器翻译就常用这个结构。
· Transformer:不再一个词一个词读,而是把整句话一起放桌上,谁和谁相关就直接注意。
比如它一眼看到"吃了"和"苹果"关系强,"今天"和"苹果"关系弱。
现在很多大模型都基于这种思想。
八、RNN 还能用在哪?
除了输入法,RNN 和它的变体还用在很多地方:
· 语音识别:把声音序列转成文字。
· 机器翻译:把中文句子转成英文句子。
· 情感分析:判断评论是好评还是差评。
· 文本生成:写诗、写故事、写代码。
· 股票预测:根据历史价格猜未来趋势。
· 天气预测:根据过去几小时的数据猜下一小时。
· 音乐生成:根据前面的音符生成后面的旋律。
· 手写识别:根据笔迹序列识别文字。
只要数据有顺序,RNN 就有用武之地。
九、一句话总结
RNN 就是输入法里的那个"边读边记小本本"。
用户打:
我 今天 中午 在 食堂 吃了 一个
它一边读,一边更新记忆,最后根据记忆猜:
苹果。
它的核心是:
当前输入 + 旧记忆 = 新记忆。
优点:能处理序列、有记忆、懂顺序、支持变长输入。
缺点:记不长、传话易丢或炸、不能并行、单向只能看过去。
所以后来有了 LSTM、GRU、双向 RNN 和 Transformer。
下次手机输入法猜中你下一个词时,也许背后就有这种"边读边记"的思想。