RNN Layer

作者: Jarkata | 来源:发表于2021-05-12 14:09 被阅读0次

本文为转载,原文链接: https://wmathor.com/index.php/archives/1392/

一个 RNN Layer 如下图所示


假设 x 的 shape 是 [10, 3, 100],翻译一下就是,10 个单词,每次训练 3 句话,每个单词用一个 100 维的 tensor 来表达

接着再看上面的运算过程,其中hidden len就是memory的维度,假设是20。因此:
\begin{align*} h_{t+1} &= x_t @ w_{xh} + h_t @ w_{hh}\\ &= [3, 100] @ [20, 100]^T + [3, 20] @ [20, 20]^T \\ &= [3, 20] \end{align*}

nn.RNN

用代码定义一个RNN Layer,然后查看其参数信息

import torch
import torch.nn as nn

rnn = nn.RNN(100, 20)
print(rnn._parameters.keys())
print(rnn.weight_ih_l0.shape) # w_{xh} [20, 100]
print(rnn.weight_hh_l0.shape) # w_{hh} [20, 20]
print(rnn.bias_ih_l0.shape) # b_{xh} [20]
print(rnn.bias_hh_l0.shape) # b_{hh} [20]

解释上面的代码前先看一下 PyTorch 中 RNN 类的参数(参考于 PyTorch 官网 RNN API

  • 必选参数input_size,指定输入序列中单个样本的尺寸大小,例如可能用一个1000长度的向量表示一个单词,则input_size=1000
  • 必选参数hidden_size,指的是隐藏层中输出特征的大小
  • 必选参数num_layers,指的是纵向的隐藏层个数,一般设置为1~10,default为1

现在上面的代码就很好理解了,nn.RNN(100, 20) 中 100 指的是用一个长度为 100 的向量表示一个单词,20 指的是 hidden_size

RNN 的 forward 函数与 CNN 定义的方式有点不太一样,具体见下图


参数中的x不是x_t,而是直接把x=[seq_length,batch,feature_len]带进去。h_0如果不写则默认是0,否则h_0的维度应该为[layers,batch,hidden_len]

看下代码

import torch
import torch.nn as nn

rnn = nn.RNN(input_size=100, hidden_size=20, num_layers=1)
x = torch.randn(10, 3, 100)
out, h_t = rnn(x, torch.zeros(1, 3, 20))
print(out.shape) # [10, 3, 20]
print(h_t.shape) # [1, 3, 20]

每个地方参数的 shape 都是有关联的,必须要把上面的内容看懂了才能理解。
h_tout很容易搞混,先看一个2层的RNN模型

在解释h_tout之前要先理解一个概念 —— 时间戳,时间戳是指左右而不是上下,什么意思呢,就是上图是一个两层的 RNN,假设这两层的 RNN 右边分别又各接一层,那这样的左右结构就是时间戳,基于此,给出h_tout的定义:

  • h_t: 最后一个时间戳上面所有的memory状态
  • out: 所有时间戳上的最后一个memory状态
    而第几个 memory 是针对层来说的,比方说第一层的 memory 就是第一个 memory,最后一层的 memory 就是最后一个 memory。

下面这张图可以帮助理解,红色框是out,蓝色框是h_t

看下代码

import torch
import torch.nn as nn

rnn = nn.RNN(input_size=100, hidden_size=20, num_layers=4)
x = torch.randn(10, 3, 100)
out, h_t = rnn(x)
print(out.shape) # [10, 3, 20]
print(h_t.shape) # [4, 3, 20]

如果理解了上面outh_t的 shape,这里的输出也就不难想到了。
上面nn.RNN()的定义方式是直接把整个x输入,自动完成循环。下面再介绍一种定义RNN的方式,需要手动完成循环。

nn.RNNCell

先看一下 PyTorch 的官方 API

参数和 nn.RNN 大体相似,但是注意 input_size 的 shape 是 (batch, input_size),而且 hidden_size 的 shape 也是 (batch, hidden_size),这就导致 forward 也不一样

看下代码

import torch
import torch.nn as nn

cell1 = nn.RNNCell(100, 20)
x = torch.randn(10, 3, 100)
h1 = torch.zeros(3, 20)
for xt in x:
    h1 = cell1(xt, h1)
print(h1.shape) # [3, 20]

上面就就是一层的 RNN,用 RNNCell 的方式,手动循环进行训练

下面在看一个两层的 RNN,用 RNNCell 的方式怎么做

import torch
import torch.nn as nn

cell1 = nn.RNNCell(100, 30) # 100 -> 30
cell2 = nn.RNNCell(30, 20)
x = torch.randn(10, 3, 100)
h1 = torch.zeros(3, 30)
h2 = torch.zeros(3, 20)
for xt in x:
    h1 = cell1(xt, h1)
    h2 = cell2(h1, h2)
print(h2.shape) # [3, 20]

第一层的作用是将一个 100 维的输入变为 30 维的 memory 输出,然后将输出带入到第二层,第二层的输出是一个 20 维的 memory。最重要的代码是 for 中的两句话,第一层的输入是 x_t 和 memory h_1,第二层的输入是第一层的 memory h_1,以及第二层的 memory h_2

相关文章

  • RNN Layer

    本文为转载,原文链接: https://wmathor.com/index.php/archives/1392/[...

  • LSTM

    简介 在深度RNN中,由于多hidden layer,存在梯度爆炸和梯度消失的问题。而停止学习,RNN会忘记在长序...

  • tf.keras.layers.AbstractRNNCell

    表示RNNCell的抽象对象 继承: Layer 这是实现具有自定义行为的RNN单元的基类. 每个 RNNCell...

  • ValueError: Variable rnn_layer/g

    前言 在代码中加入tf.reset_default_graph(),我试了,没用!当然没用,因为我的问题压根就不是...

  • 02-25:RNN算法

    RNN算法 1、RNN算法原理 (1)RNN变种GRU (2)RNN变种LSTM LSTM缺点分析: todo: ...

  • RNN中bidirectional和num_layer对outp

    Batch first 首先,我们要习惯接受batch_first=False(就是默认值)的思维,因为NLP中批...

  • RNN

    RNN资源整理:awesome-rnn GitHub 上的RNN项目: Awesome Tensorflow Im...

  • [tensorflow](六) RNN

    20181204 qzd 1 RNN简介 2 LSTM 3 RNN的变种 4 RNN样例应用

  • 「深度学习」循环神经网络 RNN 学习笔记

    循环神经网络 RNN 演化流程: RNN -> BRNN -> GRU -> LSTM RNN 「循环神经网络」 ...

  • 深入浅出循环神经网络 RNN

    本文主要针对循环神经网络 RNN 的原理、结构和应用进行介绍,介绍什么是 RNN,RNN的主要结构有哪些,RNN ...

网友评论

      本文标题:RNN Layer

      本文链接:https://www.haomeiwen.com/subject/eqdadltx.html