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

门控循环单元(GRU)

循环神经网络中的梯度计算

  • 当时间步数较大或者时间步较小时,循环神经网络的梯度较容易出现衰减或爆炸
  • 虽然裁剪梯度可以应对梯度爆炸,但无法解决梯度衰减的问题。
  • 通常由于这个原因,循环神经网络在实际中较难捕捉时间序列中时间步距离较大的依赖关系

门控循环神经网络(gated recurrent neural network)的提出,正是为了更好地捕捉时间序列中时间步距离较大的依赖关系。它通过可以学习的门来控制信息的流动。其中,门控循环单元(gated recurrent unit,GRU)是一种常用的门控循环神经网络。

门控循环单元

门控循环单元引入了重置门(reset gate)和更新门(update gate)的概念,从而修改了循环神经网络中隐藏状态的计算方式。

门控循环单元中的重置门和更新门的

  • 输入均为当前时间步输入Xt\boldsymbol{X}_tXt与上一时间步隐藏状态Ht−1\boldsymbol{H}_{t-1}Ht1
  • 输出由激活函数为sigmoid函数的全连接层计算得到。
    在这里插入图片描述

假设

  • 隐藏单元个数为hhh
  • 给定时间步ttt的小批量输入Xt∈Rn×d\boldsymbol{X}_t \in \mathbb{R}^{n \times d}XtRn×d(样本数为nnn,输入个数为ddd
  • 和上一时间步隐藏状态Ht−1∈Rn×h\boldsymbol{H}_{t-1} \in \mathbb{R}^{n \times h}Ht1Rn×h

重置门Rt∈Rn×h\boldsymbol{R}_t \in \mathbb{R}^{n \times h}RtRn×h和更新门Zt∈Rn×h\boldsymbol{Z}_t \in \mathbb{R}^{n \times h}ZtRn×h的计算如下:

Rt=σ(XtWxr+Ht−1Whr+br),Zt=σ(XtWxz+Ht−1Whz+bz),\begin{aligned} \boldsymbol{R}_t = \sigma(\boldsymbol{X}_t \boldsymbol{W}_{xr} + \boldsymbol{H}_{t-1} \boldsymbol{W}_{hr} + \boldsymbol{b}_r),\\ \boldsymbol{Z}_t = \sigma(\boldsymbol{X}_t \boldsymbol{W}_{xz} + \boldsymbol{H}_{t-1} \boldsymbol{W}_{hz} + \boldsymbol{b}_z), \end{aligned} Rt=σ(XtWxr+Ht1Whr+br),Zt=σ(XtWxz+Ht1Whz+bz),

其中

  • Wxr,Wxz∈Rd×h\boldsymbol{W}_{xr}, \boldsymbol{W}_{xz} \in \mathbb{R}^{d \times h}Wxr,WxzRd×hWhr,Whz∈Rh×h\boldsymbol{W}_{hr}, \boldsymbol{W}{hz} \in \mathbb{R}^{h \times h}Whr,WhzRh×h是权重参数
  • br,bz∈R1×h\boldsymbol{b}_r, \boldsymbol{b}_z \in \mathbb{R}^{1 \times h}br,bzR1×h是偏差参数。
  • sigmoid函数可以将元素的值变换到0和1之间。因此,重置门Rt\boldsymbol{R}_tRt和更新门Zt\boldsymbol{Z}_tZt中每个元素的值域都是[0,1][0, 1][0,1]

候选隐藏状态

门控循环单元将计算候选隐藏状态来辅助之后的隐藏状态计算。

  • 我们将当前时间步重置门的输出与上一时间步隐藏状态做按元素乘法(符号为⊙\odot)。
  • 如果重置门中元素值接近0,那么意味着重置对应隐藏状态元素为0,即丢弃上一时间步的隐藏状态。
  • 如果元素值接近1,那么表示保留上一时间步的隐藏状态。
  • 然后,将按元素乘法的结果与当前时间步的输入连结,再通过含激活函数tanh的全连接层计算出候选隐藏状态,其所有元素的值域为[−1,1][-1, 1][1,1]
    在这里插入图片描述
    时间步ttt的候选隐藏状态H~t∈Rn×h\tilde{\boldsymbol{H}}_t \in \mathbb{R}^{n \times h}H~tRn×h的计算为

H~t=tanh(XtWxh+(Rt⊙Ht−1)Whh+bh),\tilde{\boldsymbol{H}}_t = \text{tanh}(\boldsymbol{X}_t \boldsymbol{W}_{xh} + \left(\boldsymbol{R}_t \odot \boldsymbol{H}_{t-1}\right) \boldsymbol{W}_{hh} + \boldsymbol{b}_h),H~t=tanh(XtWxh+(RtHt1)Whh+bh),

其中

  • Wxh∈Rd×h\boldsymbol{W}_{xh} \in \mathbb{R}^{d \times h}WxhRd×hWhh∈Rh×h\boldsymbol{W}_{hh} \in \mathbb{R}^{h \times h}WhhRh×h是权重参数
  • bh∈R1×h\boldsymbol{b}_h \in \mathbb{R}^{1 \times h}bhR1×h是偏差参数。

从上面这个公式可以看出,重置门控制了上一时间步的隐藏状态如何流入当前时间步的候选隐藏状态。而上一时间步的隐藏状态可能包含了时间序列截至上一时间步的全部历史信息。因此,重置门可以用来丢弃与预测无关的历史信息。

隐藏状态

时间步ttt的隐藏状态Ht∈Rn×h\boldsymbol{H}_t \in \mathbb{R}^{n \times h}HtRn×h的计算使用当前时间步的更新门Zt\boldsymbol{Z}_tZt来对上一时间步的隐藏状态Ht−1\boldsymbol{H}_{t-1}Ht1和当前时间步的候选隐藏状态H~t\tilde{\boldsymbol{H}}_tH~t做组合:

Ht=Zt⊙Ht−1+(1−Zt)⊙H~t.\boldsymbol{H}_t = \boldsymbol{Z}_t \odot \boldsymbol{H}_{t-1} + (1 - \boldsymbol{Z}_t) \odot \tilde{\boldsymbol{H}}_t.Ht=ZtHt1+(1Zt)H~t.

在这里插入图片描述
更新门可以控制隐藏状态应该如何被包含当前时间步信息的候选隐藏状态所更新,如图所示。

  • 假设更新门在时间步t′t'ttttt′<tt' < tt<t)之间一直近似1。那么,在时间步t′t'tttt之间的输入信息几乎没有流入时间步ttt的隐藏状态Ht\boldsymbol{H}tHt
  • 实际上,这可以看作是较早时刻的隐藏状态Ht′−1\boldsymbol{H}{t'-1}Ht1一直通过时间保存并传递至当前时间步ttt
  • 这个设计可以应对循环神经网络中的梯度衰减问题,并更好地捕捉时间序列中时间步距离较大的依赖关系。

对门控循环单元的设计作总结:

  • 重置门有助于捕捉时间序列里短期的依赖关系;
  • 更新门有助于捕捉时间序列里长期的依赖关系。

实现GRU网络

读取数据集

import numpy as np
import torch
from torch import nn, optim
import torch.nn.functional as Fimport sys
sys.path.append("..") 
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')def load_data_jay_lyrics():"""加载周杰伦歌词数据集"""with zipfile.ZipFile('../data/jaychou_lyrics.txt.zip') as zin:with zin.open('jaychou_lyrics.txt') as f:corpus_chars = f.read().decode('utf-8')corpus_chars = corpus_chars.replace('\n', ' ').replace('\r', ' ')corpus_chars = corpus_chars[0:10000]idx_to_char = list(set(corpus_chars))char_to_idx = dict([(char, i) for i, char in enumerate(idx_to_char)])vocab_size = len(char_to_idx)corpus_indices = [char_to_idx[char] for char in corpus_chars]return corpus_indices, char_to_idx, idx_to_char, vocab_size(corpus_indices, char_to_idx, idx_to_char, vocab_size) = load_data_jay_lyrics()

初始化模型参数

num_inputs, num_hiddens, num_outputs = vocab_size, 256, vocab_sizedef get_params():def _one(shape):ts = torch.tensor(np.random.normal(0, 0.01, size=shape), device=device, dtype=torch.float32)return torch.nn.Parameter(ts, requires_grad=True)def _three():return (_one((num_inputs, num_hiddens)),_one((num_hiddens, num_hiddens)),torch.nn.Parameter(torch.zeros(num_hiddens, device=device, dtype=torch.float32), requires_grad=True))W_xz, W_hz, b_z = _three()  # 更新门参数W_xr, W_hr, b_r = _three()  # 重置门参数W_xh, W_hh, b_h = _three()  # 候选隐藏状态参数# 输出层参数W_hq = _one((num_hiddens, num_outputs))b_q = torch.nn.Parameter(torch.zeros(num_outputs, device=device, dtype=torch.float32), requires_grad=True)return nn.ParameterList([W_xz, W_hz, b_z, W_xr, W_hr, b_r, W_xh, W_hh, b_h, W_hq, b_q])

定义模型

def init_gru_state(batch_size, num_hiddens, device):return (torch.zeros((batch_size, num_hiddens), device=device), )#形状为(批量大小, 隐藏单元个数)的值为0的Tensor组成的元组。
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 = paramsH, = stateoutputs = []for X in inputs:Z = torch.sigmoid(torch.matmul(X, W_xz) + torch.matmul(H, W_hz) + b_z)R = torch.sigmoid(torch.matmul(X, W_xr) + torch.matmul(H, W_hr) + b_r)H_tilda = torch.tanh(torch.matmul(X, W_xh) + torch.matmul(R * H, W_hh) + b_h)H = Z * H + (1 - Z) * H_tildaY = torch.matmul(H, W_hq) + b_qoutputs.append(Y)return outputs, (H,)

训练模型并创作歌词

num_epochs, num_steps, batch_size, lr, clipping_theta = 160, 35, 32, 1e2, 1e-2
pred_period, pred_len, prefixes = 40, 50, ['分开', '不分开']def train_and_predict_rnn(rnn, get_params, init_rnn_state, num_hiddens,vocab_size, device, corpus_indices, idx_to_char,char_to_idx, is_random_iter, num_epochs, num_steps,lr, clipping_theta, batch_size, pred_period,pred_len, prefixes):if is_random_iter:data_iter_fn = data_iter_randomelse:data_iter_fn = data_iter_consecutiveparams = get_params()loss = nn.CrossEntropyLoss()for epoch in range(num_epochs):if not is_random_iter:  # 如使用相邻采样,在epoch开始时初始化隐藏状态state = init_rnn_state(batch_size, num_hiddens, device)l_sum, n, start = 0.0, 0, time.time()data_iter = data_iter_fn(corpus_indices, batch_size, num_steps, device)for X, Y in data_iter:if is_random_iter:  # 如使用随机采样,在每个小批量更新前初始化隐藏状态state = init_rnn_state(batch_size, num_hiddens, device)else: # 否则需要使用detach函数从计算图分离隐藏状态, 这是为了# 使模型参数的梯度计算只依赖一次迭代读取的小批量序列(防止梯度计算开销太大)for s in state:s.detach_()inputs = to_onehot(X, vocab_size)# outputs有num_steps个形状为(batch_size, vocab_size)的矩阵(outputs, state) = rnn(inputs, state, params)# 拼接之后形状为(num_steps * batch_size, vocab_size)outputs = torch.cat(outputs, dim=0)# Y的形状是(batch_size, num_steps),转置后再变成长度为# batch * num_steps 的向量,这样跟输出的行一一对应y = torch.transpose(Y, 0, 1).contiguous().view(-1)# 使用交叉熵损失计算平均分类误差l = loss(outputs, y.long())# 梯度清0if params[0].grad is not None:for param in params:param.grad.data.zero_()l.backward()grad_clipping(params, clipping_theta, device)  # 裁剪梯度sgd(params, lr, 1)  # 因为误差已经取过均值,梯度不用再做平均l_sum += l.item() * y.shape[0]n += y.shape[0]if (epoch + 1) % pred_period == 0:print('epoch %d, perplexity %f, time %.2f sec' % (epoch + 1, math.exp(l_sum / n), time.time() - start))for prefix in prefixes:print(' -', predict_rnn(prefix, pred_len, rnn, params, init_rnn_state,num_hiddens, vocab_size, device, idx_to_char, char_to_idx))train_and_predict_rnn(gru, get_params, init_gru_state, num_hiddens,vocab_size, device, corpus_indices, idx_to_char,char_to_idx, False, num_epochs, num_steps, lr,clipping_theta, batch_size, pred_period, pred_len,prefixes)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/507967.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

(pytorch-深度学习)长短期记忆(LSTM)

长短期记忆&#xff08;LSTM&#xff09; LSTM 中引入了3个门&#xff0c;即 输入门&#xff08;input gate&#xff09;遗忘门&#xff08;forget gate&#xff09;输出门&#xff08;output gate&#xff09;以及与隐藏状态形状相同的记忆细胞&#xff08;某些文献把记忆细…

(pytorch-深度学习)深度循环神经网络

深度循环神经网络 循环神经网络只有一个单向的隐藏层&#xff0c;在深度学习应用里&#xff0c;我们通常会用到含有多个隐藏层的循环神经网络&#xff0c;也称作深度循环神经网络。 下图演示了一个有LLL个隐藏层的深度循环神经网络&#xff0c;每个隐藏状态不断传递至当前层的…

(pytorch-深度学习)双向循环神经网络

双向循环神经网络 一般&#xff0c;我们认为循环神经网络模型都是假设当前时间步是由前面的较早时间步的序列决定的&#xff0c;因此它们都将信息通过隐藏状态从前往后传递。 有时候&#xff0c;当前时间步也可能由后面时间步决定。 例如&#xff0c;当我们写下一个句子时&…

pytorch实现梯度下降、随机梯度下降-图像直观展示

深度学习与优化算法原理 优化函数与深度学习 在一个深度学习问题中&#xff0c;通常需要预先定义一个损失函数。有了损失函数以后&#xff0c;使用优化算法试图将其最小化。 在优化中&#xff0c;这样的损失函数通常被称作优化问题的目标函数&#xff08;objective function…

小批量随机梯度下降

小批量随机梯度下降 在每一次迭代中&#xff0c;梯度下降使用整个训练数据集来计算梯度&#xff0c;因此它有时也被称为批量梯度下降&#xff08;batch gradient descent&#xff09;。 随机梯度下降在每次迭代中只随机采样一个样本来计算梯度。可以在每轮迭代中随机均匀采样…

动量法解决梯度下降的一些问题

动量法 目标函数有关自变量的梯度代表了目标函数在自变量当前位置下降最快的方向&#xff0c;因此&#xff0c;梯度下降也叫作最陡下降&#xff08;steepest descent&#xff09;。在每次迭代中&#xff0c;梯度下降根据自变量当前位置&#xff0c;沿着当前位置的梯度更新自变…

深度学习AdaGrad算法

AdaGrad算法 在一般的优化算法中&#xff0c;目标函数自变量的每一个元素在相同时间步都使用同一个学习率来自我迭代。 例如&#xff0c;假设目标函数为fff&#xff0c;自变量为一个二维向量[x1,x2]⊤[x_1, x_2]^\top[x1​,x2​]⊤&#xff0c;该向量中每一个元素在迭代时都使…

深度学习优化算法:RMSProp算法

RMSProp算法 在AdaGrad算法中&#xff0c;因为调整学习率时分母上的变量st\boldsymbol{s}_tst​一直在累加按元素平方的小批量随机梯度&#xff0c;所以目标函数自变量每个元素的学习率在迭代过程中一直在降低&#xff08;或不变&#xff09;。因此&#xff0c;当学习率在迭代…

深度学习优化算法-AdaDelta算法

AdaDelta算法 除了RMSProp算法以外&#xff0c;另一个常用优化算法AdaDelta算法也针对AdaGrad算法在迭代后期可能较难找到有用解的问题做了改进 [1]。 不一样的是&#xff0c;AdaDelta算法没有学习率这个超参数。 它通过使用有关自变量更新量平方的指数加权移动平均的项来替代…

深度学习优化算法-Adam算法

Adam算法 Adam算法在RMSProp算法基础上对小批量随机梯度也做了指数加权移动平均。Adam算法可以看做是RMSProp算法与动量法的结合。 算法内容 Adam算法使用了动量变量vt\boldsymbol{v}_tvt​和RMSProp算法中小批量随机梯度按元素平方的指数加权移动平均变量st\boldsymbol{s}_…

深度学习-计算机视觉--图像增广

图像增广 大规模数据集是成功应用深度神经网络的前提。图像增广&#xff08;image augmentation&#xff09;技术通过对训练图像做一系列随机改变&#xff0c;来产生相似但又不同的训练样本&#xff0c;从而扩大训练数据集的规模。 图像增广的另一种解释是&#xff0c;随机改…

pytorch深度学习-微调(fine tuning)

微调&#xff08;fine tuning&#xff09; 首先举一个例子&#xff0c;假设我们想从图像中识别出不同种类的椅子&#xff0c;然后将购买链接推荐给用户。一种可能的方法是先找出100种常见的椅子&#xff0c;为每种椅子拍摄1,000张不同角度的图像&#xff0c;然后在收集到的图像…

c语言封闭曲线分割平面_高手的平面课堂:8种常用的设计排版方式,告别通宵加班...

重复、对比、对齐以及亲密性是传统平面排版的四大原则&#xff0c;即将元素重复运用(包括颜色、形状、材质、字体、空间关系等)以增加画面的条理性和整体性&#xff1b;避免页面上的元素形态与关系构建过于相似&#xff1b;画面上的每一元素都应该与另一个元素存在某种视觉联系…

我的世界java版和基岩版对比_基岩版Beta1.11.0.1发布

本帖来自好游快爆-我的世界精选推荐原帖作者:好游快爆用户3302482我的世界基岩版1.11.0.1测试版发布了&#xff0c;Minecraft基岩版1.11仍未发布&#xff0c;1.11.0.1为测试版本&#xff0c;Beta版本可能不稳定&#xff0c;并不代表最终版本质量&#xff0c;请在加入测试版之前…

机器人电焊电流电压怎么调_【华光】HG1000型电焊机现场校准仪

机器简介HG-1000型电焊机现场校准仪是依据检定规程JJG124&#xff0d;2005《电流表、电压表、功率表和电阻表检定规程》、JJG(航天)38-1987《直流标准电流源检定规程》、JJG(航天)51-1999《交流标准电流源检定规程》的要求而设计的校准设备。主要用来校验各种用电焊机(如交流手…

循环机换变速箱油教程_变速箱油用循环机换还是重力换更好?一次讲清楚,新手司机学学...

现在换变速箱油有些只要几百块钱&#xff0c;有些要一两千&#xff0c;之所以差价这么大是因为这里面涉及到换变速箱油时用什么方法去换油的问题。目前比较常见换油法是重力换油法和循环换油法。重力换油法就跟平时换机油是一样的&#xff0c;把变速箱底部的螺丝拧开之后让油滴…

pytorch深度学习-机器视觉-目标检测和边界框简介

机器视觉之目标检测和边界框简介 在图像分类任务里&#xff0c;我们假设图像里只有一个主体目标&#xff0c;并关注如何识别该目标的类别。然而&#xff0c;很多时候图像里有多个我们感兴趣的目标&#xff0c;我们不仅想知道它们的类别&#xff0c;还想得到它们在图像中的具体…

消防荷载楼板按弹性还是塑性计算_第二节 消防登高面、消防救援场地和灭火救援窗...

一、定义1、消防登高面&#xff1a;登高消防车能够靠近高层主体建筑&#xff0c;便于消防车作业和消防人员进入高层建筑进行抢救人员和扑救火灾的建筑立面称为该建筑的消防登高面&#xff0c;也称建筑的消防扑救面。2、消防救援场地&#xff1a;在高层建筑的消防登高面一侧&…

深度学习-词嵌入(word2vec)

词嵌入&#xff08;word2vec&#xff09; 自然语言是一套用来表达含义的复杂系统。在这套系统中&#xff0c;词是表义的基本单元。顾名思义&#xff0c;词向量是用来表示词的向量&#xff0c;也可被认为是词的特征向量或表征。把词映射为实数域向量的技术也叫词嵌入&#xff0…

ggplot2箱式图两两比较_作图技巧024篇ggplot2在循环中的坑

“ggplot2在循环中的输出”生活科学哥-R语言科学 2020-12-23 8:28ggplot2用过之后&#xff0c;你肯定会爱上它&#xff1b;结合一些不错的包&#xff0c;可以得到非常有展现力的图片&#xff0c;但是呢&#xff0c;有时也会碰到一些奇怪的情况。今天来们来看看&#xff0c;其中…