深度学习--------------------------------门控循环单元GRU

目录

做RNN的时候处理不了太长的序列 ,这是因为把整个序列信息 全部放在隐藏状态里面,当时间很长的话,隐藏状态可能就会累计很多东西,所以对于前面很久以前的信息不易从中抽取出来了。

R t R_t Rt就是重置, Z t Z_t Zt就是更新
门是跟隐藏状态同样长度的一个向量,计算方式跟RNN的隐藏状态是一样的。


候选隐状态


假设 R t R_t Rt里面的元素靠近零的话,那么 R t R_t Rt点乘 H t − 1 H_{t-1} Ht−1就会变得像零。(就等于是把上一个时刻的隐藏状态忘掉。)
如果全部设成0就变成了初始状态,等于这个时刻开始前面的信息全部不要。
如果全部设成1,就表示所有前面的信息全部拿过来做当前的更新。


隐状态

H t H_t Ht等于 Z t Z_t Zt按元素点乘上一次的隐藏状态+(1- Z t Z_t Zt)按元素点乘候选隐藏状态

Z t Z_t Zt是一个控制单元,叫做update gate。它是在0-1之间的数字。
假设 Z t Z_t Zt都等于1。(就是不更新过去的状态,把过去的状态放到现在)


假设 Z t Z_t Zt都等于0。(不直接拿过去的状态了,基本上看现在的更新状态)

Z t Z_t Zt里面全0,且 R t R_t Rt里面全1的时候就回到我们RNN的情况下。


门控循环单元GRU从零开始实现代码

python 复制代码
import torch
from torch import nn
from d2l import torch as d2l

batch_size, num_steps = 32, 3
train_iter, vocab = d2l.load_data_time_machine(batch_size, num_steps)

初始化模型参数

python 复制代码
def get_params(vocab_size, num_hiddens, device):
    num_inputs = num_outputs = vocab_size

    def normal(shape):
        return torch.randn(size=shape, device=device) * 0.01

    # 定义一个函数,生成三组权重和偏置张量,用于不同的门控机制
    def three():
        return (normal((num_inputs, num_hiddens)),
                normal((num_hiddens, num_hiddens)),
                torch.zeros(num_hiddens, device=device))

    W_xz, W_hz, b_z = three()  # GRU多了这两行,更新门的权重和偏置
    W_xr, W_hr, b_r = three()  # GRU多了这两行,重置门的权重和偏置
    W_xh, W_hh, b_h = three()  # 候选隐藏状态的权重和偏置
    # 隐藏状态到输出的权重
    W_hq = normal((num_hiddens, num_outputs))
    # 输出的偏置
    b_q = torch.zeros(num_outputs, device=device)
    params = [W_xz, W_hz, b_z, W_xr, W_hr, b_r, W_xh, W_hh, b_h, W_hq, b_q]
    # 遍历参数列表中所有参数
    for param in params:
        param.requires_grad_(True)
    return params

定义隐藏状态的初始化函数

定义隐状态的初始化函数init_gru_state。与之前定义的init_rnn_state函数一样,此函数返回一个形状为(批量大小,隐藏单元个数)的张量,张量的值全部为零。

python 复制代码
def init_gru_state(batch_size, num_hiddens, device):
    return (torch.zeros((batch_size, num_hiddens), device=device), )

定义门控循环单元模型

python 复制代码
def gru(inputs, state, params):
    W_xz, W_hz, b_z, W_xr, W_hr, b_r, W_xh, W_hh, b_h, W_hq, b_q = params
    H, = state
    outputs = []
    for X in inputs:
        Z = torch.sigmoid((X @ W_xz) + (H @ W_hz) + b_z)
        R = torch.sigmoid((X @ W_xr) + (H @ W_hr) + b_r)
        H_tilda = torch.tanh((X @ W_xh) + ((R * H) @ W_hh) + b_h)
        H = Z * H + (1 - Z) * H_tilda
        Y = H @ W_hq + b_q
        outputs.append(Y)
    return torch.cat(outputs, dim=0), (H,)

训练

python 复制代码
vocab_size, num_hiddens, device = len(vocab), 256, d2l.try_gpu()
num_epochs, lr = 500, 1
model = d2l.RNNModelScratch(len(vocab), num_hiddens, device, get_params,
                            init_gru_state, gru)
d2l.train_ch8(model, train_iter, vocab, lr, num_epochs, device)

该部分总代码

python 复制代码
import torch
from torch import nn
from d2l import torch as d2l


# 初始化模型参数
def get_params(vocab_size, num_hiddens, device):
    num_inputs = num_outputs = vocab_size

    def normal(shape):
        return torch.randn(size=shape, device=device) * 0.01

    # 定义一个函数,生成三组权重和偏置张量,用于不同的门控机制
    def three():
        return (normal((num_inputs, num_hiddens)),
                normal((num_hiddens, num_hiddens)),
                torch.zeros(num_hiddens, device=device))

    # 初始化GRU中的权重和偏置
    # 权重和偏置用于控制更新门
    W_xz, W_hz, b_z = three()  # GRU多了这两行
    # 权重和偏置用于控制重置门
    W_xr, W_hr, b_r = three()  # GRU多了这两行
    W_xh, W_hh, b_h = three()
    W_hq = normal((num_hiddens, num_outputs))
    b_q = torch.zeros(num_outputs, device=device)
    params = [W_xz, W_hz, b_z, W_xr, W_hr, b_r, W_xh, W_hh, b_h, W_hq, b_q]
    for param in params:
        param.requires_grad_(True)
    return params


# 定义隐藏状态的初始化函数
def init_gru_state(batch_size, num_hiddens, device):
    return (torch.zeros((batch_size, num_hiddens), device=device),)


# 定义门控循环单元模型
def gru(inputs, state, params):
    # 参数 params 解包为多个变量,分别表示模型中的权重和偏置
    W_xz, W_hz, b_z, W_xr, W_hr, b_r, W_xh, W_hh, b_h, W_hq, b_q = params
    H, = state
    outputs = []
    # 遍历输入序列中的每个时间步
    for X in inputs:
        # 更新门控机制 Z
        Z = torch.sigmoid((X @ W_xz) + (H @ W_hz) + b_z)
        # 重置门控机制 R
        R = torch.sigmoid((X @ W_xr) + (H @ W_hr) + b_r)
        H_tilda = torch.tanh((X @ W_xh) + ((R * H) @ W_hh) + b_h)
        H = Z * H + (1 - Z) * H_tilda
        Y = H @ W_hq + b_q
        outputs.append(Y)
    # 将所有输出拼接在一起,并返回拼接后的结果和最终的隐藏状态
    return torch.cat(outputs, dim=0), (H,)


batch_size, num_steps = 32, 35
train_iter, vocab = d2l.load_data_time_machine(batch_size, num_steps)
vocab_size, num_hiddens, device = len(vocab), 256, d2l.try_gpu()
num_epochs, lr = 500, 1
model = d2l.RNNModelScratch(len(vocab), num_hiddens, device, get_params, init_gru_state, gru)
d2l.train_ch8(model, train_iter, vocab, lr, num_epochs, device)
d2l.plt.show()

简洁代码实现

python 复制代码
from torch import nn
from d2l import torch as d2l

batch_size, num_steps = 32, 35
train_iter, vocab = d2l.load_data_time_machine(batch_size, num_steps)
vocab_size, num_hiddens, device = len(vocab), 256, d2l.try_gpu()
num_epochs, lr = 500, 1
num_inputs = vocab_size
gru_layer = nn.GRU(num_inputs, num_hiddens)
model = d2l.RNNModel(gru_layer, len(vocab))
model = model.to(device)
d2l.train_ch8(model, train_iter, vocab, lr, num_epochs, device)
d2l.plt.show()
相关推荐
NAGNIP6 小时前
一文搞懂深度学习中的通用逼近定理!
人工智能·算法·面试
冬奇Lab7 小时前
一天一个开源项目(第36篇):EverMemOS - 跨 LLM 与平台的长时记忆 OS,让 Agent 会记忆更会推理
人工智能·开源·资讯
冬奇Lab7 小时前
OpenClaw 源码深度解析(一):Gateway——为什么需要一个"中枢"
人工智能·开源·源码阅读
AngelPP11 小时前
OpenClaw 架构深度解析:如何把 AI 助手搬到你的个人设备上
人工智能
宅小年11 小时前
Claude Code 换成了Kimi K2.5后,我再也回不去了
人工智能·ai编程·claude
九狼11 小时前
Flutter URL Scheme 跨平台跳转
人工智能·flutter·github
ZFSS11 小时前
Kimi Chat Completion API 申请及使用
前端·人工智能
天翼云开发者社区13 小时前
春节复工福利就位!天翼云息壤2500万Tokens免费送,全品类大模型一键畅玩!
人工智能·算力服务·息壤
知识浅谈13 小时前
教你如何用 Gemini 将课本图片一键转为精美 PPT
人工智能
Ray Liang13 小时前
被低估的量化版模型,小身材也能干大事
人工智能·ai·ai助手·mindx