【深度学习基础模型】递归神经网络 (Recurrent Neural Networks, RNN) 详细理解并附实现代码。
【深度学习基础模型】递归神经网络 (Recurrent Neural Networks, RNN)
【深度学习基础模型】递归神经网络 (Recurrent Neural Networks, RNN)
文章目录
- 【深度学习基础模型】递归神经网络 (Recurrent Neural Networks, RNN)
- 1.算法原理介绍:递归神经网络 (Recurrent Neural Networks, RNN)
- 1.1 递归神经网络 (RNN) 概述
- 1.2 RNN 的关键特性
- 1.3 RNN 的工作原理
- 1.4 RNN 的问题:梯度消失与梯度爆炸
- 1.5 RNN 的应用
- 2.Python 实现 RNN 的应用实例
- 2.1代码实现:递归神经网络的实现及文本分类应用
- 2.2代码解释
- 3.总结
参考地址:https://www.asimovinstitute.org/neural-network-zoo/
论文地址:https://www.sciencedirect.com/science/article/abs/pii/036402139090002E
欢迎宝子们点赞、关注、收藏!欢迎宝子们批评指正!
1.算法原理介绍:递归神经网络 (Recurrent Neural Networks, RNN)
1.1 递归神经网络 (RNN) 概述
递归神经网络 (RNN) 是前馈神经网络 (FFNN) 的扩展,其主要特点是引入了时间维度上的依赖关系,使得网络具有记忆功能。
RNN 通过在不同时间步上共享权重,并通过递归连接在时间序列上传播信息,从而能够处理时间序列数据或顺序依赖性任务。
相比于传统的 FFNN,RNN 可以理解输入序列的顺序,并根据序列中前面的信息来调整当前的输出。
1.2 RNN 的关键特性
- 时间依赖性:RNN 中的每个神经元不仅接收当前时刻的输入,还接收上一个时刻的隐藏状态。这个特性使得 RNN 可以在序列数据中传播信息。
- 权重共享:所有时刻的隐藏层共享相同的权重矩阵,使得RNN能够处理可变长度的输入序列。
- 递归连接:通过递归连接,RNN 可以将前一时刻的隐藏状态作为当前时刻的输入,从而在时间步之间传播信息。
1.3 RNN 的工作原理
在一个标准的RNN 中,给定输入序列
X
=
(
x
1
,
x
2
,
…
,
x
T
)
X=(x_1,x_2,…,x_T)
X=(x1,x2,…,xT),隐藏状态
h
t
h_t
ht的更新公式如下:
h
t
=
σ
(
W
i
h
x
t
+
W
h
h
h
t
−
1
+
b
h
)
h_t=σ(W_{ih}x_t+W_{hh}h_{t-1}+b_h)
ht=σ(Wihxt+Whhht−1+bh)
其中:
- h t h_t ht是当前时刻的隐藏状态。
- W i h W_{ih} Wih是输入到隐藏状态的权重矩阵。
- W h h W_{hh} Whh是隐藏状态之间的递归权重矩阵。
- x t x_t xt是当前时间步的输入。
- b h b_h bh是偏置项。
- σ σ σ是激活函数(如 tanh 或 ReLU)。
最终,输出层的输出
y
t
y_t
yt计算如下:
y
t
=
σ
(
W
h
o
h
t
+
b
o
)
y_t=σ(W_{ho}h_t+b_o)
yt=σ(Whoht+bo)
1.4 RNN 的问题:梯度消失与梯度爆炸
由于 RNN 在每个时间步上进行梯度传播,如果序列较长,梯度在反向传播时会呈指数增长或减少,导致梯度爆炸或梯度消失问题。这限制了 RNN 处理长期依赖关系的能力。在实际应用中,长短期记忆网络 (LSTM) 和门控循环单元 (GRU) 被提出用来解决这个问题。
1.5 RNN 的应用
RNN 广泛用于处理与序列相关的任务,常见应用包括:
- 自然语言处理 (NLP):如文本生成、机器翻译、文本分类、情感分析等。
- 语音识别:将语音信号作为输入序列,通过 RNN 处理时间依赖性。
- 时间序列预测:例如股票价格预测、天气预报等。
2.Python 实现 RNN 的应用实例
我们将使用 Python 和深度学习框架 PyTorch 实现一个简单的 RNN,用于文本分类任务。
2.1代码实现:递归神经网络的实现及文本分类应用
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset
import numpy as np
# 创建简单的文本数据
# 假设我们有两个类别的文本数据,每个句子都是单词的索引表示
# 类别 0: "I love machine learning", "deep learning is great"
# 类别 1: "I hate spam emails", "phishing attacks are bad"
X = [
[1, 2, 3, 4], # "I love machine learning"
[5, 6, 7, 8], # "deep learning is great"
[1, 9, 10, 11], # "I hate spam emails"
[12, 13, 14, 15] # "phishing attacks are bad"
]
y = [0, 0, 1, 1] # 标签,0表示积极类别,1表示消极类别
# 转换为Tensor格式
X = torch.tensor(X, dtype=torch.long)
y = torch.tensor(y, dtype=torch.long)
# 定义数据集和数据加载器
dataset = TensorDataset(X, y)
dataloader = DataLoader(dataset, batch_size=2, shuffle=True)
# 定义 RNN 模型
class RNN(nn.Module):
def __init__(self, input_size, hidden_size, output_size, num_layers):
super(RNN, self).__init__()
self.hidden_size = hidden_size
self.num_layers = num_layers
self.embedding = nn.Embedding(input_size, hidden_size) # 嵌入层,将输入单词的索引转换为向量
self.rnn = nn.RNN(hidden_size, hidden_size, num_layers, batch_first=True) # RNN层
self.fc = nn.Linear(hidden_size, output_size) # 全连接层,用于分类输出
def forward(self, x):
# 初始化隐藏状态,形状为 (num_layers, batch_size, hidden_size)
h0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(x.device)
# 通过嵌入层转换输入
out = self.embedding(x)
# 通过 RNN 层
out, _ = self.rnn(out, h0)
# 取最后一个时间步的隐藏状态作为输出
out = out[:, -1, :]
# 通过全连接层得到最终的分类输出
out = self.fc(out)
return out
# 模型参数
input_size = 16 # 假设我们有16个不同的单词
hidden_size = 8 # 隐藏层大小
output_size = 2 # 二分类问题
num_layers = 1 # RNN层数
# 创建 RNN 模型
model = RNN(input_size, hidden_size, output_size, num_layers)
# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss() # 分类任务使用交叉熵损失函数
optimizer = optim.Adam(model.parameters(), lr=0.01)
# 训练模型
num_epochs = 20
for epoch in range(num_epochs):
for data, labels in dataloader:
# 前向传播
outputs = model(data)
loss = criterion(outputs, labels)
# 反向传播和优化
optimizer.zero_grad()
loss.backward()
optimizer.step()
if (epoch+1) % 5 == 0:
print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {loss.item():.4f}')
# 测试模型
with torch.no_grad():
test_sentence = torch.tensor([[1, 2, 3, 4]]) # 测试句子 "I love machine learning"
prediction = model(test_sentence)
predicted_class = torch.argmax(prediction, dim=1)
print(f'Predicted class: {predicted_class.item()}')
2.2代码解释
1.定义 RNN 模型:
self.embedding = nn.Embedding(input_size, hidden_size)
:这是嵌入层,用于将输入的单词索引(如“1, 2, 3, 4”)转换为高维向量表示。self.rnn = nn.RNN(hidden_size, hidden_size, num_layers, batch_first=True)
:定义 RNN 层,输入大小为hidden_size
,输出也为hidden_size
,序列是按批次为第一维度(batch_first=True)。- self.fc = nn.Linear(hidden_size, output_size):全连接层,将最后一个时间步的 RNN 输出映射为类别预测(输出大小为2,表示二分类任务)。
2.RNN 的前向传播:
h0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(x.device)
:初始化隐藏状态为0。out, _ = self.rnn(out, h0)
:RNN 前向传播,得到每个时间步的隐藏状态。out = out[:, -1, :]
:取最后一个时间步的输出,作为最终输出。out = self.fc(out)
:通过全连接层进行分类。
3.数据集生成与加载:
- 我们使用了简单的二分类文本数据(表示为单词索引序列),并转换为 PyTorch 的
TensorDataset
和DataLoader
。
4.训练与测试:
- 使用 Adam 优化器和交叉熵损失函数训练模型,并在每 5 个 epoch 打印一次损失。
- 在测试阶段,我们用一个测试句子进行分类预测,并打印出预测的类别。
3.总结
递归神经网络 (RNN) 是处理序列数据的重要工具,适用于自然语言处理、语音识别、时间序列预测等任务。然而,RNN 存在梯度消失与梯度爆炸问题,尤其是在处理长序列时。
在实际应用中,RNN 已被改进为 LSTM 和 GRU 等架构,解决了这些问题。通过 PyTorch 实现的 RNN 示例展示了其在文本分类中的应用。