Pytorch框架下(RNN+注意力机制)实战——附完整代码

一. 循环神经网络(RNN)

        循环神经网络(RNN)是一种神经网络架构,专门设计用于处理序列数据,如时间序列或文本。它的主要特点是在网络内部引入循环连接,使得信息可以在网络中传递。想象一下,你在阅读一段文字。对于一个标准的前馈神经网络(Feedforward Neural Network),它的输入是独立的,每一层的输出只与当前输入有关。RNN 允许信息在网络中传递,以捕捉序列中的上下文和依赖关系。RNN的关键部分是循环连接,允许网络在处理序列时保留过去的信息。每个时间步,RNN都会接收当前输入和前一个时间步的隐藏状态,然后生成新的隐藏状态。这就创造了一个能够记忆先前信息的机制,使得网络可以对序列中的不同部分进行建模。标准的RNN在面对较长序列时可能会面临梯度消失或梯度爆炸等问题,导致难以学习长期依赖关系。为了解决这个问题,出现了一些改进型的循环神经网络,如长短时记忆网络(LSTM)和门控循环单元(GRU),它们引入了特殊的机制来更有效地处理长期依赖。这里先介绍最基本的RNN,之后在详细介绍LSTM与GRU网络。

二. 注意力机制

       注意力机制是一种深度学习中的技术,它模拟人类在处理信息时的注意力分配过程。它的目标是使模型能够更加集中地关注输入数据的特定部分,而不是一次性处理所有信息。这种机制在处理序列数据、图像和其他结构化数据时特别有用。在传统的神经网络中,每个输入对最终的输出都有相同的权重,而注意力机制允许网络动态地调整这些权重,以便更关注输入的某些部分。这样可以提高模型对重要信息的感知能力,从而提高整体性能。在序列数据中,比如机器翻译中的句子,注意力机制使模型能够在每个时间步关注源语言句子的不同部分,而不是只关注最终的上下文向量。这有助于处理长句子和捕捉语言中的复杂结构。

注意力机制的核心思想是,对于每个输出(或上下文向量),模型会计算与输入序列中每个位置的相关性分数。这些分数通常通过某种度量(如点积、缩放点积等)计算。然后,利用这些相关性分数,对输入的不同部分进行加权平均,以生成最终的输出或上下文向量。

三. 数据集介绍

        这里使用的数据集还是前几期博客当中的温度数据集,因为想让大家可以明显看出网络不通对于预测结果的影响,数据集放下下放网盘当中,需要的自己取一下。

链接:temps.csv
提取码:4i1g

四. 代码详解

class Attention(nn.Module):
    def __init__(self, input_size, hidden_size):
        super(Attention, self).__init__()
        self.linear_in = nn.Linear(input_size, hidden_size, bias=False)
        self.linear_out = nn.Linear(hidden_size * 2, hidden_size)  # 为了将 RNN 输出和注意力上下文连接在一起
        self.tanh = nn.Tanh()
        self.softmax = nn.Softmax(dim=1)  # 将注意力机制分数归一化为权重

    def forward(self, rnn_output, encoder_output):
        rnn_output_mapped = self.linear_in(rnn_output)
        attn_scores = torch.bmm(rnn_output_mapped, encoder_output.transpose(1, 2))  # 计算注意力机制分数
        attn_scores = self.softmax(attn_scores)  # 将注意力分数转换为概率分布
        context = torch.bmm(attn_scores, encoder_output)    # 注意力分数计算编码器输出的加权和  算出上下文向量
        output = torch.cat((rnn_output, context), dim=2)
        output = self.tanh(self.linear_out(output))
        return output

        这里构建了一个比较容易的注意力机制类,其用于处理序列数据,将接收rnn_output将其映射到注意力的隐藏空间,计算注意力机制分数,然后将这些分数通过softmax函数归一化为注意力权重,利用这些权重计算编码器输出的加权和,形成注意力上下文向量。将RNN输出和注意力上下文连接在一起,经过线性层和激活函数的处理,得到最终的输出。

class AttentionRNN(nn.Module):
    def __init__(self, input_size, hidden_size, output_size):
        super(AttentionRNN, self).__init__()
        self.rnn = nn.RNN(input_size, hidden_size, batch_first=True)        # ture表示输入数据的形状为 (batch_size, sequence_length, input_size
        self.attention = Attention(hidden_size, hidden_size)
        self.fc = nn.Linear(hidden_size, output_size)

    def forward(self, x):
        rnn_output, _ = self.rnn(x)
        attention_output = self.attention(rnn_output, rnn_output)
        output = self.fc(attention_output[:, -1, :])
        return output

        这里定义一个三层网络结构的RNN模型,与其他RNN模型不同的点在于,这里添加了注意力机制,其通过上述定义的注意力机制类来完成。它接收 RNN 的输出rnn_out作为输入,同时也作为编码器输出,通过注意力机制计算出加权的注意力上下文向量。

五. 完整代码

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import torch
from torch import nn
from sklearn import preprocessing

plt.rcParams['font.sans-serif'] = ['SimHei']  # 设置中文字体为黑体
plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示为方块的问题

# 读取温度数据集
data = pd.read_csv("temps.csv")

# 处理日期信息
data['date'] = pd.to_datetime(data[['year', 'month', 'day']])
data['ordinal_date'] = data['date'].apply(lambda x: x.toordinal())

# 提取特征和标签
features = data[['ordinal_date', 'temp_1', 'temp_2', 'friend']]
labels = data['actual']

# 标准化特征
scaler = preprocessing.StandardScaler()
features = scaler.fit_transform(features)

# 转换为PyTorch张量
x_data = torch.tensor(features, dtype=torch.float32).view(-1, 1, features.shape[1])
y_data = torch.tensor(labels.values, dtype=torch.float32).view(-1, 1)

#将RNN输出和计算得到的上下文向量沿着特征维度(dim=2)拼接起来
# 定义注意力机制
class Attention(nn.Module):
    def __init__(self, input_size, hidden_size):
        super(Attention, self).__init__()
        self.linear_in = nn.Linear(input_size, hidden_size, bias=False)
        self.linear_out = nn.Linear(hidden_size * 2, hidden_size)  # 为了将 RNN 输出和注意力上下文连接在一起
        self.tanh = nn.Tanh()
        self.softmax = nn.Softmax(dim=1)  # 将注意力机制分数归一化为权重

    def forward(self, rnn_output, encoder_output):
        rnn_output_mapped = self.linear_in(rnn_output)
        attn_scores = torch.bmm(rnn_output_mapped, encoder_output.transpose(1, 2))  # 计算注意力机制分数
        attn_scores = self.softmax(attn_scores)  # 将注意力分数转换为概率分布
        context = torch.bmm(attn_scores, encoder_output)    # 注意力分数计算编码器输出的加权和  算出上下文向量
        output = torch.cat((rnn_output, context), dim=2)
        output = self.tanh(self.linear_out(output))
        return output


# 定义带有注意力机制的RNN模型
class AttentionRNN(nn.Module):
    def __init__(self, input_size, hidden_size, output_size):
        super(AttentionRNN, self).__init__()
        self.rnn = nn.RNN(input_size, hidden_size, batch_first=True)        # ture表示输入数据的形状为 (batch_size, sequence_length, input_size
        self.attention = Attention(hidden_size, hidden_size)
        self.fc = nn.Linear(hidden_size, output_size)

    def forward(self, x):
        rnn_output, _ = self.rnn(x)
        attention_output = self.attention(rnn_output, rnn_output)
        output = self.fc(attention_output[:, -1, :])
        return output


# 实例化带有注意力机制的RNN模型
input_size = features.shape[1]
hidden_size = 128
output_size = 1
attention_rnn = AttentionRNN(input_size, hidden_size, output_size)

# 损失函数和优化器
criterion = nn.MSELoss(reduction='mean')
optimizer = torch.optim.Adam(attention_rnn.parameters(), lr=0.001)

# 训练带有注意力机制的RNN模型
losses = []
for epoch in range(15000):
    y_pred = attention_rnn(x_data)
    loss = criterion(y_pred, y_data)

    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

    # 打印损失
    if epoch % 100 == 0:
        losses.append(loss.item())
        print(f'Epoch {epoch}, Loss: {loss.item()}')

# 使用带有注意力机制的RNN模型进行预测
with torch.no_grad():
    predictions = attention_rnn(x_data).numpy()

# 绘制训练损失
plt.plot(losses)
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.title('训练损失曲线')
plt.show()

# 绘制实际值与预测值
dates = data['date']
plt.plot(dates, labels, 'b-', label='实际值')
plt.plot(dates, predictions, 'ro', label='预测值')
plt.xticks(rotation=60)
plt.legend()
plt.xlabel('日期')
plt.ylabel('最高温度(华氏度)')
plt.title('实际 vs 预测')
plt.show()

 

  • 8
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论
好的,您想了解关于PyTorch中使用LSTM和注意力机制的相关内容,是吗? 在PyTorch中,可以使用nn.LSTM来创建LSTM模型,使用nn.Linear来创建全连接层。 关于注意力机制,可以使用nn.MultiheadAttention来实现注意力机制是一种机制,它可以关注输入序列中的不同部分并在模型中加以利用。在PyTorch中,可以使用nn.MultiheadAttention层来实现这一机制,该层将输入序列划分为多个头,并计算它们之间的注意力权重。 下面是一个使用LSTM和注意力机制的示例代码: ``` import torch import torch.nn as nn class LSTMAttention(nn.Module): def __init__(self, input_size, hidden_size, num_layers, num_classes): super(LSTMAttention, self).__init__() self.hidden_size = hidden_size self.num_layers = num_layers self.lstm = nn.LSTM(input_size, hidden_size, num_layers, batch_first=True) self.fc = nn.Linear(hidden_size, num_classes) self.attention = nn.MultiheadAttention(hidden_size, num_heads=8) def forward(self, x): h0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(device) c0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(device) out, _ = self.lstm(x, (h0, c0)) out, _ = self.attention(out, out, out) out = self.fc(out[:, -1, :]) return out ``` 这是一个简单的LSTM模型,其中包含一个注意力机制。该模型将输入序列传递给LSTM层,然后将LSTM输出传递给注意力层。最后,使用全连接层将输出转换为所需的数量的类别。 希望这可以回答您的问题!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

睡不醒的恒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值