• Pytorch intermediate(三) RNN分类


    使用RNN对MNIST手写数字进行分类。RNN和LSTM模型结构

    pytorch中的LSTM的使用让人有点头晕,这里讲述的是LSTM的模型参数的意义。


    1、加载数据集

    1. import torch
    2. import torchvision
    3. import torch.nn as nn
    4. import torchvision.transforms as transforms
    5. import torch.utils.data as Data
    6. device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
    7. sequence_length = 28
    8. input_size = 28
    9. hidden_size = 128
    10. num_layers = 2
    11. num_classes = 10
    12. batch_size = 128
    13. num_epochs = 2
    14. learning_rate = 0.01
    15. train_dataset = torchvision.datasets.MNIST(root='./data/',train=True,transform=transforms.ToTensor(),download=True)
    16. test_dataset = torchvision.datasets.MNIST(root='./data/',train=False,transform=transforms.ToTensor())
    17. train_loader = Data.DataLoader(dataset=train_dataset,batch_size=batch_size,shuffle=True)
    18. test_loader = Data.DataLoader(dataset=test_dataset,batch_size=batch_size)

     2、构建RNN模型

    • input_size – 输入的特征维度

    • hidden_size – 隐状态的特征维度

    • num_layers – 层数(和时序展开要区分开)

    • bias – 如果为False,那么LSTM将不会使用,默认为True

    • batch_first – 如果为True,那么输入和输出Tensor的形状为(batch, seq, feature)

    • dropout – 如果非零的话,将会在RNN的输出上加个dropout,最后一层除外。

    • bidirectional – 如果为True,将会变成一个双向RNN,默认为False

           1、上面的参数来自于文档,最基本的参数是input_size, hidden_size, num_layer三个。input_size:输入数据向量维度,在这里为28;hidden_size:隐藏层特征维度,也是输出的特征维度,这里是128;num_layers:lstm模块个数,这里是2。

           2、h0和c0的初始化维度为(num_layer,batch_size, hidden_size

           3、lstm的输出有out和(hn,cn),其中out.shape = torch.Size([128, 28, 128]),对应(batch_size,时序数,隐藏特征维度),也就是保存了28个时序的输出特征,因为做的分类,所以只需要最后的输出特征。所以取出最后的输出特征,进行全连接计算,全连接计算的输出维度为10(10分类)。

           4、batch_first这个参数比较特殊:如果为true,那么输入数据的维度为(batch, seq, feature),否则为(seq, batch, feature)

           5、num_layers:lstm模块个数,如果有两个,那么第一个模块的输出会变成第二个模块的输入。

           总结:构建一个LSTM模型要用到的参数,(输入数据的特征维度,隐藏层的特征维度,lstm模块个数);时序的个数体现在X中, X.shape = (batch_size,  时序长度, 数据向量维度)。

           可以理解为LSTM可以根据我们的输入来实现自动的时序匹配,从而达到输入长短不同的功能。

    1. class RNN(nn.Module):
    2. def __init__(self, input_size,hidden_size,num_layers, num_classes):
    3. super(RNN, self).__init__()
    4. self.hidden_size = hidden_size
    5. self.num_layers = num_layers
    6. #input_size - 输入特征维度
    7. #hidden_size - 隐藏状态特征维度
    8. #num_layers - 层数(和时序展开要区分开),lstm模块的个数
    9. #batch_first为true,输入和输出的形状为(batch, seq, feature),true意为将batch_size放在第一维度,否则放在第二维度
    10. self.lstm = nn.LSTM(input_size,hidden_size,num_layers,batch_first = True)
    11. self.fc = nn.Linear(hidden_size, num_classes)
    12. def forward(self,x):
    13. #参数:LSTM单元个数, batch_size, 隐藏层单元个数
    14. h0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(device) #h0.shape = (2, 128, 128)
    15. c0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(device)
    16. #输出output : (seq_len, batch, hidden_size * num_directions)
    17. #(h_n, c_n):最后一个时间步的隐藏状态和细胞状态
    18. #对out的理解:维度batch, eq_len, hidden_size,其中保存着每个时序对应的输出,所以全连接部分只取最后一个时序的
    19. #out第一维batch_size,第二维时序的个数,第三维隐藏层个数,所以和lstm单元的个数是无关的
    20. out,_ = self.lstm(x, (h0, c0)) #shape = torch.Size([128, 28, 128])
    21. out = self.fc(out[:,-1,:]) #因为batch_first = true,所以维度顺序batch, eq_len, hidden_size
    22. return out

     训练部分

    1. model = RNN(input_size,hidden_size, num_layers, num_classes).to(device)
    2. print(model)
    3. #RNN(
    4. # (lstm): LSTM(28, 128, num_layers=2, batch_first=True)
    5. # (fc): Linear(in_features=128, out_features=10, bias=True)
    6. #)
    7. criterion = nn.CrossEntropyLoss()
    8. optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)
    9. total_step = len(train_loader)
    10. for epoch in range(num_epochs):
    11. for i,(images, labels) in enumerate(train_loader):
    12. #batch_size = -1, 序列长度 = 28, 数据向量维度 = 28
    13. images = images.reshape(-1, sequence_length, input_size).to(device)
    14. labels = labels.to(device)
    15. # Forward pass
    16. outputs = model(images)
    17. loss = criterion(outputs, labels)
    18. # Backward and optimize
    19. optimizer.zero_grad()
    20. loss.backward()
    21. optimizer.step()
    22. if (i+1) % 100 == 0:
    23. print(outputs.shape)
    24. print ('Epoch [{}/{}], Step [{}/{}], Loss: {:.4f}'
    25. .format(epoch+1, num_epochs, i+1, total_step, loss.item()))

    1. # Test the model
    2. with torch.no_grad():
    3. correct = 0
    4. total = 0
    5. for images, labels in test_loader:
    6. images = images.reshape(-1, sequence_length, input_size).to(device)
    7. labels = labels.to(device)
    8. outputs = model(images)
    9. _, predicted = torch.max(outputs.data, 1)
    10. total += labels.size(0)
    11. correct += (predicted == labels).sum().item()
    12. print('Test Accuracy of the model on the 10000 test images: {} %'.format(100 * correct / total))

  • 相关阅读:
    WebDAV之葫芦儿·派盘+百灵创作
    Leetcode 1582. 二进制矩阵中的特殊位置
    中华传统文化题材网页设计主题:基于HTML+CSS设计放飞青春梦想网页【学生网页设计作业源码】
    发送 Splunk UBA 的anomalies and threats to Splunk ES
    EclipseLink
    B+树的生成过程 怎么去看懂B+树
    navicate16在M1芯片运行问题
    介绍两种Revit绘制斜墙的方法及快速【梁随斜板】
    模板进阶:非类型模板参数,特化
    wo-gradient-card是一款采用uniapp实现的透明辉光动画卡片
  • 原文地址:https://blog.csdn.net/qq_41828351/article/details/90758748