Navigation

    Gpushare.com

    • Register
    • Login
    • Search
    • Popular
    • Categories
    • Recent
    • Tags

    RNN Layer

    语音识别与语义处理领域
    1
    1
    35
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • 155****7220
      155****7220 last edited by

      一个RNN Layer如下图所示

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

      那么对于输入xtx_txt​来说,xtx_txt​的shape就是[3 100]

      接着再看上面的运算过程,其中hidden len就是memory的维度,假设是20。因此:

      $$
      \begin{aligned}
      h_{t+1} &= x_t @ w_{xh} + h_t @ w_{hh}\
      &= [3, 100] @ [20, 100]^T + [3, 20] @ [20, 20]^T \
      &= [3, 20]
      \end{aligned}
      $$

      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定义的方式有点不太一样,具体见下图

      参数中的xxx不是xtx_txt​,就是直接把$x=[\text{seq_len}, \text{batch}, \text{feature_len}]$带进去

      h0h_0h0​如果不写默认就是0,如果写的话,h0h_0h0​的维度是$[\text{layers},\text{batch}, \text{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都是有关联的,必须要把上面我写的内容看懂了才能理解

      hth_tht​和outoutout很容易搞混,我们先看一个2层的RNN模型

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

      • hth_tht​:最后一个时间戳上面所有的memory状态
      • outoutout:所有时间戳上的最后一个memory状态

      而第几个memory是针对层来说的,比方说第一层的memory就是第一个memory,最后一层的memory就是最后一个memory

      看下代码

      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]
      

      如果理解了上面outoutout和hth_tht​的shape,这里的输出也就不难想到了

      上面nn.RNN()的定义方式是直接把整个xxx输入,自动完成循环。下面再介绍一种定义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中的两句话,第一层的输入是xt和memory h1,第二层的输入是第一层的memory h1,以及第二层的memory h2

      1 Reply Last reply Reply Quote 1
      • First post
        Last post