深度学习笔记(一):PyTorch使用RNN对MNIST手写数字识别,一个项目进入深度学习。

import torch
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import time
import copy
from torch import nn
import torch.nn.functional as F
import torch.optim as optim
import torchvision
import torch.utils.data as data
from torchvision import transforms
# import hiddenlayer as hl
'''
数据准备
每个batch包含64张图像
训练集中包括60000张28*28的灰度图像
测试集中包括10000张28*28的灰度图像
'''
train_data = torchvision.datasets.MNIST(
    root = './mnist', train=True, transform= transforms.ToTensor(),
)
train_loader = data.DataLoader(
    dataset=train_data, batch_size=64, shuffle= True,drop_last=True
)

test_data = torchvision.datasets.MNIST(
   root= './mnist', train=False, transform= transforms.ToTensor()
)
test_loader = data.DataLoader(
  dataset = test_data, batch_size=64, shuffle=True,drop_last=True
)
'''
搭建RNN分类器
'''
class RNN(nn.Module):
    def __init__(self,input_dim,hidden_dim,layer_dim,output_dim):
        super(RNN, self).__init__()
        self.hidden_dim = hidden_dim   #RNN神经元个数
        self.layer_dim = layer_dim     #RNN的层数
        self.rnn = nn.RNN(input_dim,hidden_dim,layer_dim,batch_first=True,nonlinearity='relu')
        self.fc1 = nn.Linear(hidden_dim,output_dim)
    def forward(self,x):
        ## x:[batch,time_step,input_dim]
        ## 本例中time_step=图像所有像素数量/input_dim---就是28
        ## out:[batch,time_step,output_size]
        ## h_n:[layer_dim,batch,hidden_dim]
        out,h_n = self.rnn(x,None)  ##None表示h0会使用全0进行初始化
        ## 选取最后一个时间点的out输出
        out = self.fc1(out[:,-1,:])
        '''
        这块需要debug好好了解一下out维度的变化和全连接层连接的是什么
        '''
        return out

input_dim = 28  #图片每行的像素数量
hidden_dim = 128  #RNN神经元个数
layer_dim = 1     #RNN的层数
output_dim = 10   #隐藏层的输出维度(10类图像)

my_RNN = RNN(input_dim, hidden_dim, layer_dim, output_dim)
print(my_RNN)

'''
RNN分类器的训练与预测
对定义好的网络模型使用训练集进行训练,需要定义优化器和损失函数,优化器使用torch.optim.RMSprop()定义,
损失函数则使用交叉熵nn.Cross.EntropyLoss()函数定义,并且使用训练集对网络训练30个epochs
'''
optimizer = torch.optim.RMSprop(my_RNN.parameters(),lr=0.0001)
criterion = nn.CrossEntropyLoss()
train_loss_all = []
train_acc_all = []
test_loss_all = []
test_acc_all = []
num_epoch = 30
for epoch in range(num_epoch):
    print('Epoch{}/{}'.format(epoch,num_epoch-1))
    my_RNN.train()  #设置模型为训练模式
    corrects = 0
    train_num = 0
    for step,(b_x,b_y) in enumerate(train_loader):
        ##input:[batch, time_step, input_dim]   b_x:[64,1,28,28] b_y:[64]  是为什么,为什么要分成两个    b_x是特征,b_y是标签
        xdata = b_x.view(-1,28,28)
        # xdata:[64,28,28],view可以把四维转化为三维吗。  当然可以
        output = my_RNN(xdata)
        #output:[64,10] 二维
        pre_lab = torch.argmax(output,1)
        '''对于max这一步还是不懂 ,argmax得到的是最大值的序号索引,与max的区别是只返回索引,max都返回''' #pre_lab Tensor:64  torch.argmax(input,dim)
        ## dim=1 意味着要求每行最大的列标号
        loss = criterion(output, b_y)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        loss += loss.item() * b_x.size(0)
        corrects += torch.sum(pre_lab == b_y.data)
        train_num += b_x.size(0)   #size(0)的意思是第0维的数据总量,b_x.size(0) : 64
    ##计算经过一个epoch的训练集上的损失和精度
    train_loss_all.append((loss / train_num).detach().numpy())
    train_acc_all.append((corrects/train_num).detach().numpy())
    print('{}Train Loss:{:.4f} Train Acc:{:.4f}'.format(
        epoch, train_loss_all[-1], train_acc_all[-1]
    ))
    ###[-1]的原因是要显示每一轮最新的loss和acc

    ##设置模型为验证模式
    my_RNN.eval()
    corrects = 0
    test_num = 0
    for step,(b_x,b_y) in enumerate(test_loader):
        ## input : [batch,time_step,input_dim]
        xdata = b_x.view(-1,28,28)
        output = my_RNN(xdata)
        pre_lab = torch.argmax(output,1)
        loss = criterion(output,b_y)
        loss += loss.item() * b_x.size(0)
        corrects += torch.sum(pre_lab == b_y.data)
        test_num += b_x.size(0)
    ##计算经过一个epoch的训练后在测试集上的损失和精度
    test_loss_all.append((loss / test_num).detach().numpy())
    test_acc_all.append((corrects/test_num).detach().numpy())
    print('{} Test Loss {:.4f} Test Acc:{:.4f}'.format(
        epoch, test_loss_all[-1], test_acc_all[-1]
    ))

plt.figure(figsize=(14,5))
plt.subplot(1,2,1)
plt.plot(train_loss_all,'ro-',label = 'Train loss')
plt.plot(test_loss_all,'bs-',label = 'Val loss')
plt.legend()
plt.xlabel('epoch')
plt.ylabel('Loss')
plt.subplot(1,2,2)
plt.plot(train_acc_all,'ro-',label = 'Train acc')
plt.plot(test_acc_all,'bs-',label = 'Val acc')
plt.xlabel('epoch')
plt.ylabel('acc')
plt.legend()
plt.show()










通过这个实验,搞清楚了RNN神经网络的输入和输出维度的变化,掌握了训练过程。

下一步工作:

1、应该掌握如何构建dataset,把想要输入神经网络的数据维度捋清楚。搞清楚dataset类和dataloader,这是神经网络最核心的东西。

2、搞清楚模型的保存和加载,因为在大模型训练的时候需要经过一些epoch后将模型和参数进行保存。

3、找一个好的模板将训练、验证过程打包成函数,直接调用。画图函数也需要打包成函数。

总结收获:

1、搞清楚了rnn的内部运算

2、搞清楚了rnn的数据是怎么流动的,层与层是怎么连接的

 

3、训练过程中的loss和acc怎么求,之前一直有几句代码没有搞懂,尤其是argmax那里。 

 

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值