循环神经网络学习

本文介绍了循环神经网络(RNN)的基本原理,包括其如何利用历史信息处理序列数据,并以词性标注为例展示了RNN的工作流程。接着,详细阐述了长短期记忆网络(LSTM)的门控机制,用于解决RNN的梯度消失问题。最后,提供了一个使用PyTorch实现的LSTM模型进行手写数字识别的例子,包括数据预处理、模型定义、训练过程和结果展示。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

循环神经网络学习


循环神经网络RNN

在这里插入图片描述
在时刻t,一旦得到当前输入数据x_t,循环神经网络会结合前一时刻t−1得到的隐式编码ℎ_t−1,如下产生当前时刻隐式编码ℎ_t:
ℎ_t=Φ(U×x_t+W×ℎ_t−1)

这里Φ(∙)是激活函数,一般可为Sigmoid或者Tanh激活函数,使模型能够忘掉无关的信息,同时更新记忆内容。U与W为模型参数。从这里可看出,当前时刻的隐式编码输出ℎ_t不仅仅与当前输入数据x_t相关,与网络已有的“记忆”ℎ_t−1也有着密不可分的联系

以词性标注为例子给出了一个输入序列数据(x_1,⋯,x_t−1,x_t,x_t+1,…,x_T)被循环神经网络处理的示意图。

在这里插入图片描述
参数W_x将x_t映射为隐式编码ℎ_t、参数W_o将ℎ_t映射为预测输出O_t、ℎ_t−1通过参数W_ℎ参与ℎ_t的生成。图中W_x、W_o和W_ℎ是复用参数。

也可以像这样理解:
在这里插入图片描述
其中,前一刻的S(t-1) 参与后一刻S(t)的计算。

长短期记忆网络LSTM

在这里插入图片描述

这一部分可以看一下B站上的大佬视频,我就做个总结:lstm原理
在这里插入图片描述

lstm主要就是要理解几个门的计算:

看一下总体计算公式

在这里插入图片描述

其具体运算如下:前四个方程对应下面四个激活函数运算后的结果,分别把前一步的隐藏信息h(t-1)和当前输入的信息x(t)进行矩阵相乘,特征融合操作,然后,遗忘权重f(t)与前一步的细胞信息单元C(t-1)点乘,再与新输入的特征信息i(t)点乘g(t)相加(其中g(t)可以看作特征选择的操作)得到新的细胞信息C(t),接着再进行第6步的运算,就可以得到当前的隐藏状态输出结果了,再对这给隐藏状态结果进行线性层映射,softmax操作,可以进行分类问题的实现

在这里插入图片描述

关于维度问题:
如输入一段话:(x_1,⋯,x_t−1,x_t,x_t+1,…,x_T),x_t-1可以看出成一个单词,该单词在NLP任务中是通常被映射成(1,512)的词向量,这里用1d表示。lstm中的i(t)、f(t)、o(t)维度和h(t)相同,可以记为1h,这个h是在调用lstm模块时自己设置的。所以联系上文公式,我们在训练时是训练的权重矩阵,W(i,i)、W(i,f)等,它们都是dh维的,而W(h,i)、W(h,f)与隐藏信息状态做运算,是hh的。

RNN LSTM 手写数字识别

# 1. 加载数据集
import torch
import torch.nn as nn
import torchvision.transforms as transforms
import torchvision.datasets as datasets
import torchvision
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt



# 6. 定义函数:显示一批数据
def imshow(inp, title=None):
    inp = inp.numpy().transpose((1, 2, 0))
    mean = np.array([0.485, 0.456, 0.406]) # 均值
    std = np.array([0.229, 0.224, 0.225]) # 标准差
    inp = std * inp + mean
    inp = np.clip(inp, 0, 1) # 限速值限制在0-1之间
    plt.imshow(inp)
    plt.show()
    if title is not None:
        plt.title(title)
    #plt.pause(1)




# 7. 定义RNN模型
class RNN_Model(nn.Module):
    def __init__(self, input_dim, hidden_dim, layer_dim, output_dim):
        super(RNN_Model, self).__init__()
        self.hidden_dim = hidden_dim
        self.layer_dim = layer_dim
        self.rnn = nn.RNN(input_dim, hidden_dim, layer_dim, batch_first=True, nonlinearity='relu')
        # 全连接层
        self.fc = nn.Linear(hidden_dim, output_dim)

    def forward(self, x):
        # (layer_dim, batch_size, hidden_dim)
        h0 = torch.zeros(self.layer_dim, x.size(0), self.hidden_dim).requires_grad_().to(device)
        # 分离隐藏状态,避免梯度爆炸
        out, hn = self.rnn(x, h0.detach())
        out = self.fc(out[:, -1, :])
        return out


# 1. 定义模型
class LSTM_Model(nn.Module):
    def __init__(self, input_dim, hidden_dim, layer_dim, output_dim):
        super(LSTM_Model, self).__init__()  # 初始化父类中的构造方法
        self.hidden_dim = hidden_dim
        self.layer_dim = layer_dim
        # 构建LSTM模型
        self.lstm = nn.LSTM(input_dim, hidden_dim, layer_dim, batch_first=True)
        # 全连接层
        self.fc = nn.Linear(hidden_dim, output_dim)

    def forward(self, x):
        # 初始化隐层状态全为0
        # (layer_dim, batch_size, hidden_dim)
        h0 = torch.zeros(self.layer_dim, x.size(0), self.hidden_dim).requires_grad_().to(device)
        # 初始化cell state
        c0 = torch.zeros(self.layer_dim, x.size(0), self.hidden_dim).requires_grad_().to(device)
        # 分离隐藏状态,以免梯度爆炸
        out, (hn, cn) = self.lstm(x, (h0.detach(), c0.detach()))
        # 只需要最后一层隐层的状态
        out = self.fc(out[:, -1, :])
        return out

def train(train_loader,test_loader,net,Loss_Function,learning_rate,plot_loss,plot_accuary,model_name):
    model=net

    #nn.CrossEntropyLoss()
    # 10. 定义优化器
    learning_rate = learning_rate

    optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)
    # 13. 模型训练
    sequence_dim = 28  # 序列长度
    loss_list = []  # 保存loss
    accuracy_list = []  # 保存accuracy
    iteration_list = []  # 保存循环次数

    iter = 0
    for epoch in range(EPOCHS):
        for i, (images, labels) in enumerate(train_loader):
            model.train()  # 声明训练
            # 一个batch的数据转换为RNN的输入维度
            images = images.view(-1, sequence_dim, input_dim).requires_grad_().to(device)
            labels = labels.to(device)
            # 梯度清零(否则会不断累加)
            optimizer.zero_grad()
            # 前向传播
            outputs = model(images)
            # 计算损失
            loss = Loss_Function(outputs, labels)
            # 反向传播
            loss.backward()
            # 更新参数
            optimizer.step()
            # 计数器自动加1
            iter += 1
            # 模型验证
            if iter % 500 == 0:
                model.eval()  # 声明
                # 计算验证的accuracy
                correct = 0.0
                total = 0.0
                # 迭代测试集,获取数据、预测
                for images, labels in test_loader:
                    images = images.view(-1, sequence_dim, input_dim).to(device)
                    # 模型预测
                    outputs = model(images)
                    # 获取预测概率最大值的下标
                    predict = torch.max(outputs.data, 1)[1]
                    # 统计测试集的大小
                    total += labels.size(0)
                    # 统计判断/预测正确的数量
                    if torch.cuda.is_available():
                        correct += (predict.cuda() == labels.cuda()).sum()
                    else:
                        correct += (predict == labels).sum()
                # 计算
                accuracy = correct / total * 100
                # 保存accuracy, loss, iteration
                loss_list.append(loss.data)
                accuracy_list.append(accuracy)
                iteration_list.append(iter)
                # 打印信息
                print("loop : {}, Loss : {}, Accuracy : {}".format(iter, loss.item(), accuracy))
    if plot_loss==True:
        # 可视化 loss
        plt.plot(iteration_list, loss_list)
        plt.xlabel('Number of Iteration')
        plt.ylabel('Loss')
        plt.title(model_name)
        plt.show()
    if plot_accuary==True:
        # 可视化 accuracy
        plt.plot(iteration_list, accuracy_list, color='r')
        plt.xlabel('Number of Iteration')
        plt.ylabel('Accuracy')
        plt.title(model_name)
        plt.savefig('{}_mnist.png'.format(model_name))
        plt.show()


if __name__ == "__main__":
    # 2. 下载mnist数据集
    trainsets = datasets.MNIST(root='./data', train=True, download=True, transform=transforms.ToTensor()) # 格式转换

    testsets = datasets.MNIST(root='./data', train=False, transform=transforms.ToTensor())


    print(trainsets.data.shape)
    # 4.定义超参数
    BATCH_SIZE = 32 # 每批读取的数据大小
    EPOCHS = 10 # 训练10轮

    # 5. 创建数据集的可迭代对象,也就是说一个batch一个batch的读取数据
    train_loader = torch.utils.data.DataLoader(dataset=trainsets, batch_size=BATCH_SIZE, shuffle=True)

    test_loader = torch.utils.data.DataLoader(dataset=testsets, batch_size=BATCH_SIZE, shuffle=True)

    # 查看一批batch的数据


    # 8. 初始化模型
    input_dim = 28  # 输入维度
    hidden_dim = 100  # 隐层的维度,神经元
    layer_dim = 2  # 2层RNN
    output_dim = 10  # 输出维度

    model_rnn = RNN_Model(input_dim, hidden_dim, layer_dim, output_dim)
    model_lstm=LSTM_Model(input_dim, hidden_dim, layer_dim, output_dim)

    # 判断是否有GPU
    device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
    model_lstm.to(device=device)
    #  定义损失函数
    criterion = nn.CrossEntropyLoss()

    train(train_loader,test_loader,model_lstm,criterion,learning_rate=0.01,plot_loss=True,plot_accuary=True,model_name="lstm")








在这里插入图片描述
在这里插入图片描述
其数据维度如下:

import torch
import torch.nn as nn
import torchvision.transforms as transforms
import torchvision.datasets as datasets
import torchvision
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

trainsets = datasets.MNIST(root='./data', train=True, download=True, transform=transforms.ToTensor()) # 格式转换

testsets = datasets.MNIST(root='./data', train=False, transform=transforms.ToTensor())


#print(trainsets.data.shape)
 # 4.定义超参数
BATCH_SIZE = 32 # 每批读取的数据大小
EPOCHS = 1 # 训练10轮

# 5. 创建数据集的可迭代对象,也就是说一个batch一个batch的读取数据
train_loader = torch.utils.data.DataLoader(dataset=trainsets, batch_size=BATCH_SIZE, shuffle=True)

test_loader = torch.utils.data.DataLoader(dataset=testsets, batch_size=BATCH_SIZE, shuffle=True)
for epoch in range(EPOCHS):
    for i, (images, labels) in enumerate(train_loader):
        print(images.shape)
        print(labels.shape)



        images = images.view(-1, 28, 28)
        labels = labels
        print(images.shape)
        print(labels.shape)
        print(labels)
        break

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值