吴恩达深度学习课程五:自然语言处理 第一周:循环神经网络 (五)门控循环单元 GRU

此分类用于记录吴恩达深度学习课程的学习笔记。

课程相关信息链接如下:

  1. 原课程视频链接:[双语字幕]吴恩达深度学习deeplearning.ai
  2. github课程资料,含课件与笔记:吴恩达深度学习教学资料
  3. 课程配套练习(中英)与答案:吴恩达深度学习课后习题与答案

本篇为第五课的第一周内容,1.9的内容以及一些相关基础的补充。


本周为第五课的第一周内容,与 CV 相对应的,这一课所有内容的中心只有一个:自然语言处理(Natural Language Processing,NLP)

应用在深度学习里,它是专门用来进行文本与序列信息建模 的模型和技术,本质上是在全连接网络与统计语言模型基础上的一次"结构化特化",也是人工智能中最贴近人类思维表达方式 的重要研究方向之一。
这一整节课同样涉及大量需要反复消化的内容,横跨机器学习、概率统计、线性代数以及语言学直觉。

语言不像图像那样"直观可见",更多是抽象符号与上下文关系的组合,因此理解门槛反而更高

因此,我同样会尽量补足必要的背景知识,尽可能用比喻和实例降低理解难度。

本篇的内容关于门控循环单元 GRU,它通过改变 RNN 的隐藏层,来缓解 RNN 的梯度消失问题。

1. 什么是 GRU(Gated Recurrent Unit)?

前面的内容里中我们已经提到过:RNN 的核心机制,是把历史信息压缩进一个不断传递的隐藏状态中

结果就是我们已经分析过的结论:信息一旦隔得太远,就会在反复的线性变换和非线性映射中被不断稀释

在反向传播时就体现为梯度越来越小,最终几乎传不回去,导致"开头被遗忘",这就是 RNN 的长距离依赖问题

显然,这并不是改善训练技巧可以解决的问题,而是 RNN 本身的结构造成的限制,自然而然地就引出了 NLP 领域的新问题 :如何缓解 RNN 的长距离依赖问题? 即如何让模型"记得更久一些"?

于是,在 2014 年发表的一篇论文: On the Properties of Neural Machine Translation: Encoder--Decoder Approaches 中,提出了一种带有门控机制的循环单元结构 ,即后来被称为 GRU(Gated Recurrent Unit) 的模型。

该工作首次在 Encoder--Decoder 框架下系统性地引入 "更新门"和"重置门" ,通过对隐藏状态的信息流进行选择性控制,从结构层面缓解了传统 RNN 在长序列建模中面临的困难。

同年的另一篇论文:Empirical Evaluation of Gated Recurrent Neural Networks on Sequence Modeling 对其实际效果进行了系统评估。实验结果证明了其优越的性能,这也使其迅速成为实际 NLP 系统中广泛采用的基础循环单元之一。

出现了很多没见过的名词,别担心,下面我们就来详细展开。

1.1 GRU 的解题思路

首先,面对"如何让模型记得更久一些"的问题,GRU给出的答案是:

既然记不住全部,那我能不能只记重要的?

这是什么意思?回忆一下 普通 RNN 是如何进行记忆的:

\[新输入来了\rightarrow旧状态所有信息参与计算\rightarrow得到一个带有新输入信息的新隐藏状态 \]

我们已经很熟悉这个过程了:

但是,实际上,在真实语言中,我们并不是这样处理信息的。

举个例子:

"我昨天去北京出差,

在路上遇到了一个多年未见的朋友,
现在在......"

当你看到"他"的时候:

  • 不需要记住"北京","昨天"。
  • 但你必须记住"朋友"。
  • 换句话说,当前时刻的理解,并不依赖于全部历史内容,而只依赖于与当前判断相关的信息。

再概括来讲,人脑在处理序列信息时,隐含着一个非常重要的能力:选择性记忆

而 GRU 的设计,正是将这种"取舍能力",通过门控结构的形式,显式地引入到 RNN 的隐藏层更新过程中

简单展开一下,GRU 并没有改变 RNN 的整体框架:

  • 仍然是时间步 \(t = 1, 2, \dots\)
  • 仍然有输入 \(x^{<t>}\)
  • 仍然有隐藏状态 \(a^{<t>}\)

它真正改变的,只有一件事:在"旧状态 → 新状态"的过程中,加了两道可学习的"门"。 就是我们下面要说的 "更新门"和"重置门"

1.2 GRU 的更新门(Update Gate)

第一道门,叫 更新门(Update Gate)

它负责回答的问题是:

"当前这一步,我要保留多少过去的记忆?"

也就是说:

  • 更新门开得越大 → 旧状态保留得越多
  • 更新门关得越紧 → 当前输入对隐藏状态的影响越大

总结来说,更新门衡量的是:"这条历史信息,值不值得继续往后传?"

这一设计直接解决了 RNN 的一个问题:普通 RNN 每一步都会用新输入强行覆盖旧隐藏状态,

长期信息容易被逐步稀释,而更新门让模型可以选择性保留重要历史信息

我们回到之前的例子:

"我昨天去北京出差,

在路上遇到了一个多年未见的朋友,
现在在......"

在生成"他"对应的隐藏状态时:

  • 更新门会让模型保留"朋友"这个关键信息,因为它对理解代词至关重要
  • 同时,更新门会削弱"昨天""北京"等不相关信息的影响

于是,通过更新门,模型可以自动判断哪些历史值得继续传递,哪些可以淡化。

其实,这种思路和我们之前在优化算法部分介绍的 指数加权平均 很相似:旧状态像过去的平均值,更新门控制"平均时的新权重",让重要信息得到保留。

1.3 GRU 的重置门(Reset Gate)

第二道门,叫 重置门(Reset Gate)

它关心的不是"保留多少旧信息",而是:

"在生成新信息时,我要参考多少过去的历史?"

可以把它想象成 选择记忆开关

  • 当历史信息相关 → 重置门值接近 1 → 历史参与计算
  • 当历史信息不相关 → 重置门值接近 0 → 模型"暂时忘掉过去"

这个设计是为了应对语言序列中的一类常见情况:句子突然换话题、上下文跳转很大等前面的内容对当前判断几乎没帮助的情况。

还是这个例子:

"我昨天去北京出差,

在路上遇到了一个多年未见的朋友,
现在在......"

当生成"他"对应的新隐藏状态时:

  • 重置门会让模型只关注"朋友"这个历史信息
  • 忽略"昨天"、"北京"等与当前代词关系不大的信息

    只看概念和例子, 你可能会觉得:更新门和重置门好像是一个作用啊?
    实际上,这绝非冗余设计,我们展开看看:

1.4 更新门和重置门

实际上,更新门关注的是 "旧状态在下一步隐藏状态中保留多少" ,它是一种全局记忆控制 ,关注的是"以后 "。

而重置门关注的是 "在生成当前新隐藏状态时,历史信息是否被参考" ,它是一种局部选择性 ,关注的是"现在"。

功能 控制对象 比喻
更新门 记忆持续 上一隐藏状态整体传递 决定哪些历史要带到下一步,就像水龙头调节水流量
重置门 记忆使用 当前候选隐藏状态计算 决定本步是否参考历史,就像选择性翻阅笔记

最终,更新门 负责"信息能延续多远" ,重置门 负责"信息在当前是否参与生成"。

两道门结合,使 GRU 能够在长序列中保留重要历史信息,同时在必要时灵活忘掉无关历史,实现"更好、更有用的记忆"。

现在,了解了 GRU 的基本原理后,我们来看看如何实现 GRU 吧。

2. 如何实现 GRU ?

这里需要提前说明一点,如果你看了原视频,会发现吴恩达老师并没有过多提及重置门,而是用一个新概念:"记忆细胞" 来进行讲解。实际上,记忆细胞是之后的 LSTM 中的概念,因为 GRU 可以看作是 LSTM 的简化形式,因此同样可以使用,但个人感觉不正式引入的前提下并不好理解,最终还是选择使用 GRU 本身的概念来进行这部分内容,在下一篇 LSTM 的介绍中再正式引入记忆细胞。

在理解了 GRU 的核心思想和两道门的作用之后,我们可以进一步探讨如何在实际模型中实现 GRU 。实现上,其实并不复杂,本质上仍是对普通 RNN 的隐藏状态更新增加了门控计算。下面我们按逻辑逐步展开。

2.1 计算重置门

在 GRU 的实现逻辑中,对于当前步新隐藏状态的计算,第一步是计算重置门
重置门 \(r^{\langle t \rangle}\) 决定了历史隐藏状态 \(a^{\langle t-1 \rangle}\) 在生成当前候选 隐藏状态 \(\tilde{a}^{\langle t \rangle}\) 时被参考的比例。

来具体演示一下这个过程:

计算公式为:

\[r^{\langle t \rangle} = sigmoid\big( W_{xr} x^{\langle t \rangle} + W_{ar} a^{\langle t-1 \rangle} + b_r \big) \]

你可以比较明显的发现,实际上重置门就是一个使用 \(sigmoid\) 激活函数的全连接层,最终的激活值,也就是重置门值会被 \(sigmoid\) 压缩到 \(0\sim1\) 之间。用来表示一种权重

  • 当 \(r^{\langle t \rangle} \approx 1\) 时,第 \(i\) 个隐藏单元会充分参考历史信息
  • 当 \(r^{\langle t \rangle} \approx 0\) 时,第 \(i\) 个隐藏单元会 "忘掉"历史信息 ,只依赖当前输入生成候选隐藏状态

什么叫候选隐藏状态?这就是我们的下一步内容。

2.2 计算候选隐藏状态

在计算完重置门 \(r^{\langle t \rangle}\) 后,下一步是生成 候选隐藏状态 \(\tilde{a}^{\langle t \rangle}\),它表示当前步的新信息 ,结合了当前输入 \(x^{\langle t \rangle}\) 和经过重置门处理后的历史隐藏状态 \(a^{\langle t-1 \rangle}\)。

同样,我们在上一步的基础上进行演示:

摆出公式如下:

\[\tilde{a}^{\langle t \rangle} = \tanh\Big( W_{xa} x^{\langle t \rangle} + W_{aa} ( r^{\langle t \rangle} \odot a^{\langle t-1 \rangle} ) + b_a \Big) \]

其中\(r^{\langle t \rangle} \odot a^{\langle t-1 \rangle}\)是指逐元素乘 ,这是将重置门作用于历史隐藏状态。

你会发现,这时我们得到的候选隐藏状态 \(\tilde{a}^{\langle t \rangle}\) 就是是当前步的"新记忆" ,它既包含当前输入信息 \(x^{\langle t \rangle}\),也包含经过选择性过滤的历史信息 \(r^{\langle t \rangle} \odot a^{\langle t-1 \rangle}\)。

到这里,你可能觉得已经实现一些优化了,但 GRU 告诉你:这还不够好

2.3 计算更新门

在生成候选隐藏状态 \(\tilde{a}^{\langle t \rangle}\) 后,下一步是计算 更新门 \(z^{\langle t \rangle}\)。

而更新门的作用是:决定历史隐藏状态 \(a^{\langle t-1 \rangle}\) 与候选隐藏状态 \(\tilde{a}^{\langle t \rangle}\) 在最终隐藏状态 \(a^{\langle t \rangle}\) 中的融合比例

我们继续进行演示:

看完演示,我想一个问题已经呼之欲出了:更新门和重置门看起来就是把一个东西算了两遍啊?这么做的意义是什么?我直接把重置门值拿来用不行吗?

这就涉及到二者在模型中所承担的语义作用

  • 更新门用来记录全局 中的重要记忆,它直接影响最终输出,同样梯度也直接影响它。
  • 重置门用来保存局部 记忆,确保使用信息符合当前步需求,它通过候选状态间接 影响最终输出,因此梯度对它的作用就没有那么"长期"。

    因此:二者不能参数共享,而是一定要有独立的参数,以此通过反向传播实现二者的语义作用。
    同时要说明的是,我们这里演示的是逻辑上的计算顺序,你会发现二者的计算并不存在先后限制,因此在实际应用中可以同步计算二者。
    公式表示为:

\[z^{\langle t \rangle} = sigmoid\big( W_{xz} x^{\langle t \rangle} + W_{az} a^{\langle t-1 \rangle} + b_z \big) \]

其中,\(sigmoid\) 函数将输出压缩到 \([0,1]\),表示融合比例:

  • 当 \(z^{\langle t \rangle}_i \approx 1\) 时,第 \(i\) 个隐藏单元会更多保留历史信息
  • 当 \(z^{\langle t \rangle}_i \approx 0\) 时,第 \(i\) 个隐藏单元会更多采纳候选隐藏状态 \(\tilde{a}^{\langle t \rangle}\) 的新信息

最后,我们将用更新门将历史隐藏状态与候选隐藏状态融合 ,得到最终隐藏状态 \(a^{\langle t \rangle}\)。

2.4 计算最终隐藏状态

在前面的步骤中,我们已经得到了三样关键量:

  • 上一时刻的隐藏状态 \(a^{\langle t-1 \rangle}\)(历史记忆
  • 当前步生成的候选隐藏状态 \(\tilde{a}^{\langle t \rangle}\)(新记忆
  • 控制二者融合比例的更新门 \(z^{\langle t \rangle}\)

现在,GRU 要做的最后一件事,就是将"历史记忆"和"新记忆"按更新门的指示进行融合 ,从而得到当前时刻的最终隐藏状态 \(a^{\langle t \rangle}\),就像这样:

最终的计算公式为:

\[a^{\langle t \rangle} = z^{\langle t \rangle} \odot a^{\langle t-1 \rangle} + (1 - z^{\langle t \rangle}) \odot \tilde{a}^{\langle t \rangle} \]

同样其中 \(\odot\) 表示逐元素乘

这个公式本身就非常直观,它表达的正是更新门的语义含义:

  • \(z^{\langle t \rangle}\) 决定了历史信息保留的比例
  • \(1 - z^{\langle t \rangle}\) 决定了新信息写入的比例

也就是说:

  • 当 \(z^{\langle t \rangle}_i \approx 1\) 时, 第 \(i\) 个隐藏单元几乎直接复制上一时刻的状态,信息得以长期延续。
  • 当 \(z^{\langle t \rangle}_i \approx 0\) 时, 第 \(i\) 个隐藏单元主要采用当前步生成的新信息

2.5 小结

至此,一个 GRU 单元在时间步 \(t\) 的完整计算流程就结束了,完整顺序是这样的:

  1. 计算重置门 \(r^{\langle t \rangle}\) → 用于调节历史隐藏状态在生成候选隐藏状态 \(\tilde{a}^{\langle t \rangle}\) 时的参考程度:

\[ r^{\langle t \rangle} = sigmoid(W_{xr} x^{\langle t \rangle} + W_{ar} a^{\langle t-1 \rangle} + b_r) \]

  1. 计算候选隐藏状态 \(\tilde{a}^{\langle t \rangle}\) → 使用当前输入 \(x^{\langle t \rangle}\) 和重置门调节后的历史信息 :

\[ \tilde{a}^{\langle t \rangle} = \tanh(W_{x\tilde{a}} x^{\langle t \rangle} + W_{a\tilde{a}} (r^{\langle t \rangle} \odot a^{\langle t-1 \rangle}) + b_{\tilde{a}}) \]

  1. 计算更新门 \(z^{\langle t \rangle}\) → 决定历史信息与新候选状态在最终隐藏状态中的融合比例:

\[ z^{\langle t \rangle} = sigmoid(W_{xz} x^{\langle t \rangle} + W_{az} a^{\langle t-1 \rangle} + b_z) \]

  1. 计算最终隐藏状态 \(a^{\langle t \rangle}\) → 使用更新门进行加权融合:

\[ a^{\langle t \rangle} = z^{\langle t \rangle} \odot a^{\langle t-1 \rangle} + (1 - z^{\langle t \rangle}) \odot \tilde{a}^{\langle t \rangle} \]

综合来看,GRU 缓解长距离依赖问题的方式可以概括为一句话:通过更新门建立"可复制的长期记忆通路",通过重置门实现"按需使用的局部历史选择",从结构上同时保护了信息和梯度的长期传递。

它并不是"记忆更强",而是更聪明地决定什么时候记、什么时候用、什么时候不动

而且,你会发现 RGU 中同样有残差的思想:

从结构视角看,GRU 的更新门在时间维度上实现了一种"可学习的残差连接":当更新门接近 1 时,隐藏状态几乎被原样复制,使信息与梯度能够跨越多个时间步稳定传播,这与 ResNet 通过恒等映射缓解深层网络退化问题在思想上是一致的。

3. 总结

概念 原理 比喻
GRU 的核心思想 不再"全部记住",而是通过门控机制选择性地记忆与使用历史信息 记笔记时只标重点,而不是全文背诵
更新门(Update Gate) 控制上一时刻隐藏状态在当前隐藏状态中保留的比例,直接决定最终输出 水龙头:决定旧记忆"流"到下一步的多少
重置门(Reset Gate) 控制历史信息在生成当前候选隐藏状态时是否被参考 翻笔记:这一步要不要看以前的内容
候选隐藏状态 在重置门调节下,由当前输入与部分历史信息生成的新记忆 当前这一步新写下的草稿想法
最终隐藏状态 使用更新门在旧隐藏状态与候选隐藏状态之间进行加权融合 在"照抄旧稿"和"采用新稿"之间做权衡
更新门 vs 重置门 更新门决定信息能"走多远",重置门决定信息"现在用不用" 一个管未来,一个管当下
门不共享参数的原因 二者承担不同语义角色,通过反向传播分别学习"长期保留"和"局部使用"的策略 长期计划和临时决策不能用同一套标准
梯度传播机制 更新门接近 1 时,隐藏状态近似复制,梯度可跨时间步稳定传播 给梯度修了一条高速公路
GRU 与残差思想 在时间维度上引入"可学习的恒等映射",避免每一步都强制更新 ResNet 的 skip connection,沿时间轴展开
相关推荐
薛不痒14 小时前
深度学习之优化模型(数据预处理,数据增强,调整学习率)
深度学习·学习
酩酊仙人15 小时前
fastmcp构建mcp server和client
python·ai·mcp
格林威15 小时前
传送带上运动模糊图像复原:提升动态成像清晰度的 6 个核心方案,附 OpenCV+Halcon 实战代码!
人工智能·opencv·机器学习·计算机视觉·ai·halcon·工业相机
棒棒的皮皮16 小时前
【深度学习】YOLO模型速度优化Checklist
人工智能·深度学习·yolo·计算机视觉
AI街潜水的八角17 小时前
基于Pytorch深度学习神经网络MNIST手写数字识别系统源码(带界面和手写画板)
pytorch·深度学习·神经网络
资深web全栈开发19 小时前
深度对比 LangChain 8 种文档分割方式:从逻辑底层到选型实战
深度学习·自然语言处理·langchain
540_54019 小时前
ADVANCE Day45
人工智能·python·深度学习
云和数据.ChenGuang19 小时前
人工智能实践之基于CNN的街区餐饮图片识别案例实践
人工智能·深度学习·神经网络·机器学习·cnn
纪伊路上盛名在19 小时前
如何为我们的GPU设备选择合适的CUDA版本和Torch版本?
pytorch·深度学习·torch·cuda·英伟达