广西民族大学高级人工智能课程—头歌实践教学实践平台-RNN 基础

本文介绍了如何使用 PyTorch 构建和训练基本的 RNN 模型,涵盖 RNN 的发展历史、原理以及如何在 PyTorch 中实现。通过预测正弦曲线的下一个值来展示 RNN 的应用。
摘要由CSDN通过智能技术生成

代码文件

import random
import torch
import numpy as np
import matplotlib.pyplot as plt
import warnings


warnings.filterwarnings("ignore")

# 数据生成
random.seed(42)
np.random.seed(42)
torch.manual_seed(42)

x = np.linspace(-10, 10, 1000)
y = np.sin(x) + np.random.uniform(-0.5, 0.5, 1000)

# 将numpy数组转换为torch张量
x = torch.tensor(x).float().view(-1, 1)
y = torch.tensor(y).float().view(-1, 1)

# 定义RNN模型
class RNN(torch.nn.Module):
    def __init__(self, input_size, hidden_size, output_size):
        super(RNN, self).__init__()
        self.hidden_size = hidden_size
        self.rnn = torch.nn.RNN(input_size, hidden_size, batch_first=True)
        self.linear = torch.nn.Linear(hidden_size, output_size)

    def forward(self, x, hidden):
        out, hidden = self.rnn(x, hidden)
        out = self.linear(out[:, -1, :])
        return out, hidden


# 初始化模型、优化器和损失函数
################### Begin #############################
model = RNN(1, 32, 1)
optimizer = torch.optim.Adam(model.parameters(), lr=0.01)
criterion = torch.nn.MSELoss()


###################  End  #############################

# 开始训练
seq_len = 10
for epoch in range(21):
    for i in range(x.size(0) - seq_len):
        inputs = x[i:i+seq_len]
        targets = y[i+1:i+seq_len+1]
        hidden = torch.zeros(1, 1, 32)
        output, hidden = model(inputs.unsqueeze(0), hidden)
        loss = criterion(output, targets)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
    if (epoch+1) % 5 == 0:
        print('Epoch: {}, Loss: {:.4f}'.format(epoch+1, loss.item()))


# 评估
predictions = []
hidden = torch.zeros(1, 1, 32) 
for i in range(x.size(0) - 1):
    input1 = x[i:i+1]
    output, hidden = model(input1.unsqueeze(0), hidden)
    predictions.append(output.detach().numpy())

predictions = torch.tensor(predictions).float().view(-1, 1)
print("predictions:", predictions)

# 我们可以通过绘制预测值和真实值的曲线来直观地看到预测效果
plt.plot(x.numpy(), y.numpy(), label='true')
plt.plot(x.numpy()[:-1], predictions.squeeze().numpy(), label='predict')
plt.legend()
output1 = "/data/workspace/myshixun/第一关/result_img/result1.png"
plt.savefig(output1)
plt.close()

题目描述

任务描述

本关任务:理解 RNN 的结构、原理和工作方式并学习用 PyTorch 实现 RNN 的基本架构。

相关知识

为了完成本关任务,你需要掌握:

  1. RNN 理论介绍;
  2. 使用 PyTorch 构建基本 RNN。
RNN 理论介绍
RNN 发展历史

循环神经网络(Recurrent Neural Networks,RNN)的发展历程可以追溯到1980年代。RNN 发展历程大概的概述如下:

  • 1982年:John Hopfield 首次介绍了一种新型神经网络模型,即 Hopfield 网络。Hopfield 网络可以被视为 RNN 的起点,它使用全连接的神经元并且所有连接都有相同的权重,以此实现动态稳定性。

  • 1986年:David Rumelhart, Geoffrey Hinton 和 Ronald Williams 提出了反向传播(backpropagation)算法。这个算法也被用于训练 RNN。

  • 1989年:Elman 发表论文,首次提出了今天我们称为 Elman 网络或者简单RNN的网络结构。这种网络将前一步的隐藏状态作为当前步的输入的一部分,实现了对序列数据的处理。

  • 1997年:Hochreiter 和 Schmidhuber 提出了长短期记忆(Long Short-Term Memory, LSTM)模型,这是一种特殊的 RNN,能够有效地解决梯度消失和梯度爆炸问题,以便学习长序列中的依赖关系。

  • 2000年:Felix Gers 和他的同事对 LSTM 进行了改进,添加了“遗忘门”,进一步增强了模型的性能。

  • 2014年:Cho 等人提出了门控循环单元(Gated Recurrent Unit, GRU)。GRU 是 LSTM 的一种变体,结构更简单,但保留了类似的性能。

  • 2015年:由于计算机硬件的改进,尤其是 GPU 的使用,以及更大数据集的可用性,RNN,特别是其 LSTM 和 GRU 变体,在许多任务中(包括机器翻译、语音识别等)都取得了显著的成功。

  • 近年来:随着注意力机制(attention)的提出,以及 Transformer 模型的出现,RNN在某些任务上(尤其是 NLP 任务)已被这些更新的架构所取代。然而,RNN 仍然在处理序列数据和建模时间依赖性方面有其独特的优势,仍在许多应用中被广泛使用。

RNN 原理

RNN,即循环神经网络(Recurrent Neural Networks),是一种常见的神经网络类型,尤其在处理序列数据(如文本、时间序列等)方面,RNN表现出强大的能力。这种模型的特点是能够保持在前一步的状态,并在下一步中利用这些信息,这使得RNN具有“记忆”的特性,能够在处理序列数据时处理前后之间的依赖关系。

,

RNN结构

一个基本的 RNN 单元的工作原理如下:

对于每一个时间点t,RNN 会有一个输入 xt​ 和一个输出 ht​。这个输出也被称为隐藏状态或者记忆。重要的是,这个隐藏状态不仅仅依赖于当前时间点的输入,也会依赖于前一个时间点的隐藏状态。这就是“循环”二字的由来:信息会在网络中循环不断的向前传播。

在数学上,我们可以用下面的公式来描述这种操作:

ht​=f(Wx​∗xt​+Wh​∗ht−1​+b)

其中,Wx​ 和 Wh​ 是输入权重和循环权重,b 是偏置项,f 是非线性激活函数,如 tanh 或 ReLU。

上述描述的是最简单的RNN结构,即 "Elman RNN" 或者 "SimpleRNN"。在实践中,为了解决梯度消失和梯度爆炸问题,以及更有效地学习长期依赖,我们经常使用更复杂的 RNN 变体,例如长短期记忆网络(LSTM)和门控循环单元(GRU)。

值得注意的是,尽管 RNN 有处理序列数据的能力,但是由于“梯度消失”的问题,它们常常难以捕捉序列中的长距离依赖关系。因此,在实践中,LSTM 和 GRU 这样的 RNN 变体更为常见。

使用 PyTorch 构建基本 RNN
PyTorch 介绍

PyTorch 是一个基于 Python 的科学计算包,提供深度学习研究平台,提供最大的灵活性和速度:

  • 张量计算(类似 NumPy)与强大的 GPU 加速:PyTorch 提供了丰富的操作符,并且支持在 GPU 上运行。

  • 动态神经网络:PyTorch 使用动态计算图,意味着你可以随时修改和构建你的神经网络。这也使得调试和网络修改更为方便。

  • 自动求导系统:PyTorch 具有强大的自动求导系统,能够自动计算神经网络的梯度。

  • 丰富的 API 和工具:PyTorch 提供了大量的预训练模型,损失函数,优化器等,可以帮助快速搭建和训练神经网络。

  • Python 优先:PyTorch 不是使用 Python 包装低级语言编写的,而是直接用 Python 实现,所以可以用 Python 来使用 PyTorch,并且能够很好的与 Python 生态系统融合。

  • 强大的社区支持:PyTorch 有一个非常活跃的社区,可以从中找到大量的开源代码,学习资源和已解决的问题。

PyTorch 实现 RNN 的基本架构

接下来我们使用 PyTorch 创建并训练简单的 RNN 模型的示例。我们假设我们的任务是预测正弦曲线的下一个值。

数据集建立 首先,我们需要做的是创建并处理我们的数据集。我们将使用 numpy 来创建一个正弦曲线,并将其转化为 PyTorch 张量:

 
  1. import torch
  2. import numpy as np
  3. # 数据生成
  4. random.seed(42)
  5. np.random.seed(42)
  6. torch.manual_seed(42)
  7. x = np.linspace(-10, 10, 1000)
  8. y = np.sin(x) + np.random.uniform(-0.5, 0.5, 1000)
  9. # 将numpy数组转换为torch张量
  10. x = torch.tensor(x).float().view(-1, 1)
  11. y = torch.tensor(y).float().view(-1, 1)

首先,通过 numpy 在 -10 到 10 的区间内生成 1000 个均匀分布的值。然后,通过计算这些值的正弦函数,并添加一些随机的噪声,生成目标数据 y。最后,将这些数据转换为 PyTorch 张量。

定义 RNN 模型 首先通过 RNN 层进行处理,然后将RNN的输出通过一个线性层得到最后的预测结果。注意,我们只关心每个序列的最后一个输出。

 
  1. # 定义RNN模型
  2. class RNN(torch.nn.Module):
  3. def __init__(self, input_size, hidden_size, output_size):
  4. super(RNN, self).__init__()
  5. self.hidden_size = hidden_size
  6. self.rnn = torch.nn.RNN(input_size, hidden_size, batch_first=True)
  7. self.linear = torch.nn.Linear(hidden_size, output_size)
  8. def forward(self, x, hidden):
  9. out, hidden = self.rnn(x, hidden)
  10. out = self.linear(out[:, -1, :])
  11. return out, hidden

训练模型 然后,初始化模型、优化器和损失函数。这里的优化器是 Adam,它是一种常用的优化器,其特点是能自动调整学习率。在每个 epoch,我们都会通过模型得到预测值,然后使用均方误差(MSE)损失函数来计算误差。然后,我们通过反向传播算法来更新我们的模型参数。

 
  1. # 初始化模型、优化器和损失函数
  2. model = RNN(1, 32, 1)
  3. optimizer = torch.optim.Adam(model.parameters(), lr=0.01)
  4. criterion = torch.nn.MSELoss()
  5. # 开始训练
  6. seq_len = 10
  7. for epoch in range(21):
  8. for i in range(x.size(0) - seq_len):
  9. inputs = x[i:i+seq_len]
  10. targets = y[i+1:i+seq_len+1]
  11. hidden = torch.zeros(1, 1, 32)
  12. output, hidden = model(inputs.unsqueeze(0), hidden)
  13. loss = criterion(output, targets)
  14. optimizer.zero_grad()
  15. loss.backward()
  16. optimizer.step()
  17. if (epoch+1) % 5 == 0:
  18. print('Epoch: {}, Loss: {:.4f}'.format(epoch+1, loss.item()))

模型评估 接下来,进行预测。首先,创建一个新的隐藏状态,然后对于 x 中的每个值,将其作为输入传递给模型,并保存模型的预测结果。

 
  1. # 评估
  2. predictions = []
  3. hidden = torch.zeros(1, 1, 32)
  4. for i in range(x.size(0) - 1):
  5. input1 = x[i:i+1]
  6. output, hidden = model(input1.unsqueeze(0), hidden)
  7. predictions.append(output.detach().numpy())
  8. predictions = torch.tensor(predictions).float().view(-1, 1)
  9. print("predictions:", predictions)
  10. # 我们可以通过绘制预测值和真实值的曲线来直观地看到预测效果
  11. plt.plot(x.numpy(), y.numpy(), label='true')
  12. plt.plot(x.numpy()[:-1], predictions.squeeze().numpy(), label='predict')
  13. plt.legend()
  14. output1 = "/data/workspace/myshixun/第一关/result_img/result1.png"
  15. plt.savefig(output1)
  16. plt.close()

编程要求

根据提示,在右侧编辑器 Begin-End 区域补充代码,完成初始化模型、优化器和损失函数的过程。

测试说明

平台会对你编写的代码进行测试:

测试输入:; 预期输出:

 
  1. Epoch: 5, Loss: 0.0940
  2. Epoch: 10, Loss: 0.0932
  3. Epoch: 15, Loss: 0.0932
  4. Epoch: 20, Loss: 0.0947
  5. predictions: tensor([[-0.9260],
  6. [ 0.3595],
  7. [-0.7287],
  8. [ 0.2340],
  9. [-0.3546],
  10. ......)

开始你的任务吧,祝你成功!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值