Pytorch从0到1之循环神经网络——(6)

开篇

上次我们说到了卷积神经网络,CNN是一种在图像领域经常被使用的一种重要的基础网络。我们熟悉的网络例如VGG,ResNet,Inception-v3,GoogLeNet,AlexNet等等众多著名网络中都有CNN身影。
那今天我们就要介绍一种在语音识别和自然语言处理领域和CNN具有同样低位的另一种网络——循环神经网络RNN。如BERT,Skip-Gram,CBOW等模型。它有两个很重要的部分,LSTM和GRU。详细的RNN知识在这里就不做介绍了,大家可以移步RNN基础知识及LSTM,GRU进行自我学习。

废话不多说,我们开始吧。

循环神经网络RNN

引入库

import torchvision
import torch
import torch.nn as nn
import torchvision.transforms as transforms

设备的配置及参数的设置

device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
sequence_length = 28# RNN的处理对象都是一段语音序列或者一段次序列,此参数表示序列长度
input_size = 28# 输入层的特证数
hidden_size = 128# 隐藏层的特征数
num_layers = 2# RNN层数
num_classes = 10# 输出类别
batch_size = 100# 批数
num_epochs = 2# 训练轮数
learning_rate = 0.01# 学习率

MNIST数据的引入及加载

train_dataset = torchvision.datasets.MNIST(root='../../data/',
                                           train=True,
                                           transform=transforms.ToTensor(),
                                           download = True)
test_dataset = torchvision.datasets.MNIST(root = '../../data/',
                                          train=False,
                                          transform=transforms.ToTensor())
train_loader = torch.utils.data.DataLoader(dataset = train_dataset,
                                           shuffle = True,
                                           batch_size = batch_size)
test_loader = torch.utils.data.DataLoader(dataset = test_dataset,
                                          shuffle = False,
                                          batch_size = batch_size)~

RNN类的创建

class RNN(nn.Module):
    def __init__(self,input_size,hidden_size,num_layers,num_classes):
        super(RNN, self).__init__()
        self.hidden_size = hidden_size
        self.num_layers = num_layers
        """
        batch_first: If ``True``, then the input and output tensors are provided as (batch, seq, feature)——batch_first官方源码解释
        即如果batch_first等于True,则这个input和output的shape都是batch在第一维的
        """
        self.lstm = nn.LSTM(input_size,hidden_size,num_layers,batch_first=True)
        self.fc = nn.Linear(hidden_size,num_classes)
    def forward(self, x):
        # 设置初始的隐藏单元的状态和cell的状态        
        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)

        # 前向传播LSTM
        out,_ = self.lstm(x,(h0,c0))
        # out:tensor of shape (batch_size,seq,feature)
        # 我们只解码out最后一个time_step的隐藏单元状态
        out = self.fc(out[:,-1,:])
        return out

在这里插入图片描述这里希望大家可以理解上文的h到底是什么了。h就是我们在传播时隐藏层的状态,真正循环的其实是它,上一个隐藏层的状态会来计算当前时间步的隐藏层状态,这个位置在计算的时候通常采用的激活函数为tanh。然后i再利用我们当前算得的隐藏层状态来计算标签y,标签y通常采用softmax来计算。
在LSTM中不仅仅是细胞的状态C会在整个网络中流动,隐藏层单元的状态h也会在网络中流动,因为我们在计算候选细胞状态,更新细胞状态以及经过该层后输出的新隐层单元状态都需要h的参与。
在这里插入图片描述

具体大家还是看上文分享的链接,讲的很全面了。
模型的构建以及优化器和损失函数的定义

model = RNN(input_size,hidden_size,num_layers,num_classes).to(device)


criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam((model.parameters()),lr = learning_rate)~

分类问题,我们依然使用交叉熵损失函数和Adam优化器。
训练模型

total_step = len(train_loader)
for epoch in range(num_epochs):
    for i,(images,labels) in enumerate(train_loader):
        images = images.reshape(-1,sequence_length,input_size)
        labels = labels.to(device)

        # Forward pass
        outputs = model(images)
        loss = criterion(outputs,labels)

        # Backward amd optimize
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

        if ( i + 1 ) % 100 == 0:
            print ('Epoch [{}/{}], Step [{}/{}], Loss: {:.4f}'
                   .format(epoch+1, num_epochs, i+1, total_step, loss.item()))

测试模型及保存模型

model.eval()
with torch.no_grad():
    correct = 0
    total = 0
    for images,labels in test_loader:
        images = images.reshape(-1,sequence_length,input_size)
        labels = labels.to(device)
        outputs = model(images)
        _,predicted = torch.max(outputs.data,1)
        total += labels.size(0)
        correct += (predicted == labels).sum().item()
        print('Test Accuracy of the model on the 10000 test images: {} %'.format(100 * correct / total))

# Save the model checkpoint
torch.save(model.state_dict(), 'model.ckpt')~

这里的model.eval()依然是我们昨天所说的问题,有一些Module它需要我们去设置model,如果是eval的测试状态,内部会自动调整参数,与训练集不同的。
这里面有一个隐含的Module就是LSTM中的Dropout。在训练的时候我们会丢弃一些单元,但是测试的时候dropout我们设置为1,不丢弃任何单元。

循环神经网络RNN也是非常重要的基础模型,它更主要的应用是在NLP领域,例如文本翻译,语音识别,以及情感分类等等。RNN与CNN也有一个结合之处是当下比较火的,就是我们小时候经常做的题目——看图说话。CNN对图像进行分类分析,RNN通过CNN输出的特征进行语言描述。也是一个也别有趣的领域。
下次我们说RNN一个拓展网络——双向循环网络biRNN

原创文章 101 获赞 13 访问量 2328

猜你喜欢

转载自blog.csdn.net/weixin_44755413/article/details/105817003
今日推荐