PyTorch深度学习实践:循环神经网络(RNN)

一、基础部分

1. 简单例子引入RNN

温度 (°C)气压 (百帕)天气状况
第1天251013晴天
第2天221005雨天
第3天211002雨天

在这个表格中,我们可以看到连续三天的不同气象数据。可以注意到的是,对于每一天来说,都有三个不同的特征。假如我们假定第1天为x1,第2天为x2,第3天为x3。同时,每天里面都包含三个特征(即温度,气压和天气状况)。因此,x1,x2和x3都分别可以看作是一个3维列向量。然后,我们再根据这三个向量去预测第4天的气象数据。

实际上,表格中都是带有时间序列模式的数据,而RNN专门处理的就是这种类别的数据。下图是一个简单的示意图。在这个图中可以看到,我们不仅要考虑x1,x2和x3之间的连接关系,还要考虑到它们具有先后的时间序列关系。换句话说,后一天的天气状况都要依赖于前一天的天气状况。
在这里插入图片描述

除了天气状况的数据外,类似的数据还有自然语言等。下面我们将以一个具体的语句解释一下RNN在自然语言处理中的应用。

在这里插入图片描述
对于这么一句话来说,它是有先后顺序的。正常说出的顺序就是我,爱,北京,天安门。但是如果打乱了这句话的顺序,我们可能就无法理解这句话是什么意思了,例如北京,爱,天安门,我的这种顺序。所以,这里就需要RNN来确定自然语言的正确排列顺序。


2. RNN流程示意图

在这里插入图片描述

若上图不理解,请移步b站上的一个相关视频,视频链接如下:
【循环神经网络】5分钟搞懂RNN,3D动画深入浅出

2.1 RNN流程示意图含义说明

2.1.1 xt 含义

xt 指的是,时间序列中时刻 t 的输入数据。同时,xt 是一个有维度(即特征数量)的向量,我们把这个维度称为输入维度。例如在前文的气象数据的例子中,xt 就是一个维度为3的列向量。

2.1.2 RNN Cell 含义

RNN Cell 本质上就是一个线性层,它可以将某一个维度映射到另一个维度的空间。例如上图中,RNN Cell 就把一个输入维度为3的向量 xt 映射到了一个输出维度为5的向量 ht。同时,RNN Cell 这个线性层是共享的(即图中右半部分的所有 RNN Cell 都是同一个线性层,且这个线性层的权重会参与到所有的运算流程里)。

2.1.3 ht 含义

ht 是输入向量 xt 经过 RNN Cell 处理得到的输出向量,我们也把输出向量 ht 叫做隐藏层(hidden)。

2.1.4 h0 含义

对于 h1 来说,我们需要输入一个 h0 参与到 RNN Cell 的运算过程中。例如,我们想根据图像生成文本,我们可以根据卷积神经网络和全连接层来生成 h0(先验知识),再把 h0 送到下一次 h1 的运算过程中,这样就能完成图像到文本的转换。
如果没有先验知识作为输入,我们就可以把 h0 设置为和 h1、h2 等输出向量维度相同,且全为0的列向量。例如,图中h1、h2 等输出向量维度为5,那么 h0 也是一个维度为5的全0列向量。

2.1.5 红色箭头上方 h1 和 h2 含义

我们不仅输出了 h1,还把 h1 送到了下一次 h2 的 RNN Cell 的运算过程中。h2 的含义同理。

2.2 RNN流程示意图伪代码

# 初始化 h0 为一个0向量
h0 = 0

# 定义一个线性层 linear
linear = Linear()

# 循环遍历 x, 经过线性层的运算, 计算出每一次的 h
for x in X:
    h = linear(x, h)

# 对 h = linear(x, h) 的具体解释
h1 = linear(x1, h0)
h2 = linear(x2, h1)
h3 = linear(x3, h2)

3. RNN计算示意图说明

在这里插入图片描述

3.1 xt 矩阵,Wih 矩阵和 bih 矩阵

我们在这里把之前向量的说法换成矩阵的说法。则 xt 是一个形状为 input_size * 1 的矩阵,Wih 是一个形状为 hidden_size * input_size 的权重矩阵,bih 是一个形状为 hidden_size * 1 的偏置矩阵。这里 Wih 符号如果换成 Whi 符号会有助于理解。

3.2 ht-1 矩阵,Whh 矩阵和 bhh 矩阵

ht-1 是一个形状为 hidden_size * 1 的矩阵,作为当前这一层的输入。Whh 是一个形状为 hidden_size * hidden_size 的权重矩阵,bhh 是一个形状为 hidden_size * 1 的偏置矩阵。

3.3 tanh( ) 激活函数

将前面 3.1 和 3.2 两步计算得到的结果相加,即 Wih * xt + bih + Whh * ht-1 + bhh,再将其放入 tanh( ) 中做一个激活。在 RNN 中,tanh( ) 用的最普遍,其取值范围是 [-1,1]。

3.4 ht 矩阵

经过 3.3 一步的计算过程后,得到的结果就是 ht 矩阵,即当前这一层的隐藏层的输出。

二、具体代码部分

4. RNN 构造方法1 (使用RNNCell)

4.1 初始化不同参数及解释

在这里插入图片描述

4.1.1 batchSize

气象数据举例:有1组天气变化的时间序列的训练数据
自然语言举例:有多少个句子,即同时处理多少个句子的同一个位置的字

4.1.2 seqLen

气象数据举例:这1组训练数据中,一共有3天
自然语言举例:每个句子中有多少个字

4.1.3 InputSize

气象数据举例:3天的时间序列中,每天有3个不同的天气特征
自然语言举例:每个句子中,每个字的词嵌入向量维度

4.1.4 hiddenSize

气象数据举例:hidden 层中都是2维的向量
自然语言举例:自己定义 hidden 层中向量维度

4.2 构造线性层并计算每一层的输出 ht

在这里插入图片描述

4.3 完整代码

import torch

# 初始化参数
batch_size = 1
seq_len = 3
input_size = 4
hidden_size = 2

# 构建 RNNCell 的线性层
# 单个 RNN,即循环神经网络的单个部分
cell = torch.nn.RNNCell(input_size=input_size, hidden_size=hidden_size)

# 生成(3,1,4)的标准正态分布的的随机数, 张量
dataset = torch.randn(seq_len, batch_size, input_size)
# 生成为(1,2)的全为0.的数, 张量
hidden = torch.zeros(batch_size, hidden_size)

# 用 enumerate 函数来遍历数据集, 并返回每次迭代的索引值(idx)和对应的元素(input)
for idx, input in enumerate(dataset):
    print('=' * 20, idx, '=' * 20)
    print(f'Input size: {input.shape}')
    # 计算每一层的输出 ht
    hidden = cell(input, hidden)
    print(f'Output size: {hidden.shape}')
    print(hidden)
# 输出结果
==================== 0 ====================
Input size: torch.Size([1, 4])
Output size: torch.Size([1, 2])
tensor([[-0.5207,  0.7236]], grad_fn=<TanhBackward0>)
==================== 1 ====================
Input size: torch.Size([1, 4])
Output size: torch.Size([1, 2])
tensor([[-0.8958,  0.8798]], grad_fn=<TanhBackward0>)
==================== 2 ====================
Input size: torch.Size([1, 4])
Output size: torch.Size([1, 2])
tensor([[-0.9120,  0.8529]], grad_fn=<TanhBackward0>)

5. RNN 构造方法2 (使用RNN)

5.1 初始化不同参数及解释

在这里插入图片描述

5.1.1 numLayers

RNN 的层数,天气状况的例子中,RNN 只有1层。

5.2 构造线性层并计算每一层的输出 ht 和最终的一个输出 hN

在这里插入图片描述

在这里插入图片描述

5.3 完整代码

import torch

# 初始化参数
batch_size = 1
seq_len = 3
input_size = 4
hidden_size = 2
num_layers = 1

# 构建 RNN 的线性层
cell = torch.nn.RNN(input_size=input_size, hidden_size=hidden_size, num_layers=num_layers)

# 生成(3, 1, 4)的标准正态分布的的随机数, 张量
inputs = torch.randn(seq_len, batch_size, input_size)
# 生成为(1, 1, 2)的全为0.的数, 张量
hidden = torch.zeros(num_layers, batch_size, hidden_size)

# 输出最后一个隐藏层, 还有最后的 hN
out, hidden = cell(inputs, hidden)

print(f'Output size: {out.shape}')
print(f'Output: {out}')
print(f'Hidden size: {hidden.shape}')
print(f'Hidden: {hidden}')
# 输出结果
Output size: torch.Size([3, 1, 2])
Output: tensor([[[ 0.9128, -0.2513]],
                [[ 0.3892,  0.6347]],
                [[ 0.8947,  0.6750]]], grad_fn=<StackBackward0>)
Hidden size: torch.Size([1, 1, 2])
Hidden: tensor([[[0.8947, 0.6750]]], grad_fn=<StackBackward0>)
  • 34
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值