自然语言处理基础 03|门控循环单元 GRU

目录

摘要

[一、GRU 解决什么问题?](#一、GRU 解决什么问题?)

[二、GRU 的结构与原理](#二、GRU 的结构与原理)

[三、 API 介绍](#三、 API 介绍)

四、代码Demo

五、总结


摘要

基础 RNN 虽然引入隐藏状态实现序列记忆,但存在致命缺陷:长序列训练时梯度消失,句子很长时,模型会遗忘开头的信息。为了解决这个问题,研究者提出门控循环单元(Gated Recurrent Unit,GRU)。

GRU 保留了 RNN 逐时间步读取序列、参数共享的核心思路,新增门控机制,可控地决定:哪些记忆保留、哪些信息丢弃。GRU 是 LSTM 的轻量化版本,参数量更少、训练速度更快,工业场景里非常常用。

**一、**GRU 解决什么问题?

回顾基础 RNN 痛点:当句子很长时,早期时间步的信息,经过多层时间递推,梯度不断衰减,最后几乎丢失。

|-----------------------------------------------|
| "今天天气很好,阳光明媚,微风不燥,适合出门去公园散步,公园里花开了,五颜六色非常好看。" |

基础 RNN 读到后半句"好看"的时候,很容易遗忘最开头的「今天天气很好」这个关键上下文。

GRU 通过更新门、重置门两个门,对记忆做可控筛选,缓解长距离依赖与梯度消失问题。

**二、**GRU 的结构与原理

GRU 不再是简单直接覆盖旧记忆,而是用两个门控来控制隐藏状态的更新:

  • 重置门( Reset Gate ) :控制要不要忘掉过去的记忆;
  • 更新门( Update Gate ) :控制多大程度保留旧记忆,多大程度吸收新输入。

**1.**逐时间步计算公式

输入:当前时间步词嵌入 xt ,上一步隐藏状态 ht-1 。

  重置门

  更新门

  候选隐藏状态

  • :sigmoid 激活,输出 0~1 之间的值。越靠近 1 代表"打开门",靠近 0 代表"关闭门";
  • :哈达玛积,对应元素相乘。

门含义通俗解释

1. 重置门

越小,代表更多丢弃上一步旧记忆; 接近 1,保留过去记忆。适合场景:句子出现全新语义,需要清空旧记忆。

2. 更新门

决定新旧记忆的融合比例:

  • :几乎保留旧记忆,不接收新信息;
  • :几乎丢弃旧记忆,完全使用新候选状态 h ~t 。

|---------------------------------------------------------------------------------------------------------------------------------|
| 依然满足:所有时间步共享同一套权重 。参数是记忆规则,隐藏状态 ht 存储当前句子的上下文。 |

**2.**初始化

和 RNN 保持一致:每个新句子都要单独初始化 (零向量),句子之间记忆隔离,互不干扰。

句子读完后,最后时间步隐藏状态 依然压缩整句上下文信息,后续送入 MLP 做分类任务。

**三、**API 介绍

完整构造签名:

python 复制代码
torch.nn.GRU(input_size, hidden_size, num_layers=1, bias=True,
             batch_first=False, dropout=0.0, bidirectional=False)

|-------------------------|-------------------------------------------------|-------------------------|
| 参数 | 含义 | 文档例子取值 |
| input_size(embed_dim) | 每个时间步输入向量维度,词嵌入维度 | 8:单个词为 8 维向量 |
| hidden_size(hidden_dim) | 隐藏状态维度,记忆容量 | 16 |
| batch_first=True | 批量放第一维,输入 shape 变为 (batch, seq_len, input_size) | True,和 Embedding 输出直接对接 |

|-----------------------------------------------------------------------------------------------------------------|
| 输出说明: · output:(batch, seq_len, hidden_dim),保存每一个时间步的隐状态 · h_n:(num_layers, batch, hidden_dim),最后一层最后时间步隐状态 |

每个时间步隐藏状态维度固定 = hidden_dim=16;输入词嵌入 xt 依旧是 8 维。

四、代码Demo

python 复制代码
import torch
import torch.nn as nn

class GRUClassifier(nn.Module):
    def __init__(self, vocab_size, embed_dim, hidden_dim, num_classes):
        super().__init__()
        self.embedding = nn.Embedding(vocab_size, embed_dim)
        # GRU 层替换原来的 RNN
        self.gru = nn.GRU(embed_dim, hidden_dim, batch_first=True)
        self.fc = nn.Linear(hidden_dim, num_classes)

    def forward(self, x):
        # x: (batch, seq_len) 词索引
        emb = self.embedding(x)          # (batch, seq_len, embed_dim)
        output, h_n = self.gru(emb)      # output: (batch, seq_len, hidden_dim)
        h_last = h_n[-1]                 # 取最后一层隐状态 (batch, hidden_dim)
        logits = self.fc(h_last)         # (batch, num_classes)
        return logits

# 测试
vocab_size, embed_dim, hidden_dim, num_classes = 20, 8, 16, 2
model = GRUClassifier(vocab_size, embed_dim, hidden_dim, num_classes)
x = torch.tensor([[1, 2, 3, 4],
                  [5, 6, 7, 8]])
logits = model(x)
print(logits.shape)  # torch.Size([2, 2])

五、总结

优点

  1. 引入门控机制,有效缓解基础 RNN 的梯度消失问题,可以捕捉更长距离的上下文,长句子的理解效果明显优于基础 RNN;
  2. 训练稳定性更强,长序列训练时,不容易出现梯度剧烈衰减的情况;
  3. 保留基础 RNN 的核心优势:所有时间步参数共享,天然支持长度不固定的序列输入;
  4. 仅维护一组隐藏状态,模型逻辑直观,代码实现难度低。

缺点

  1. 和基础 RNN 相同,必须逐时间步串行计算,序列无法并行处理;
  2. 虽然改善了梯度消失,但面对极长的句子,远距离信息依然会有一定程度衰减;
  3. 相比基础 RNN,增加了门控相关权重,参数量更大,训练占用的内存资源更多;
  4. 模型计算流程比基础 RNN 复杂,单步运算耗时高于原始 RNN。
相关推荐
M158227690551 小时前
IO-Link 三件套:主站网关与智能传感方案
网络·工业通信
李福春1 小时前
技术思考问题23:AI Coding秒交差,谁替它验收?
人工智能·ai工程化·验收标准·深圳同盟·腾讯云架构师技术同盟·反演思维·ci门禁
枫叶丹41 小时前
知识库为什么搜不到答案:多向量检索与 Late Interaction
人工智能·chatgpt·开源·agent·codex
天府云创1 小时前
SRE之DeepSeek 10月15日故障分析、旁推和思考
网络·数据库·人工智能·故障处理·deepseek·api恢复
青桔柚子1 小时前
2026企业AI办公工具选型指南:如何匹配组织的智能任务需求
人工智能
johnsong1 小时前
AI会自保吗?
人工智能
Yan-英杰1 小时前
【论文精读】MSD-ResNet50:多尺度动态卷积 + CBAM,如何把梅花鹿个体识别准确率从 74.2% 提升到 88.7%?
人工智能·卷积神经网络·机器视觉
水如烟1 小时前
孤能子视角:EIS术语梳理法层与AI构建社会结构模型
人工智能
老唐7771 小时前
Transformer原理大白话讲解
人工智能·python·深度学习·神经网络·计算机视觉·ai·transformer