MNIST数据集处理(Pytorch)

Pytorch学习

环境配置及安装
六十分钟快速入门
Pytorch官方教程中文版
Github代码examples

MNIST数据集:手写数字图片识别

参考Github代码:https://github.com/pytorch/examples/tree/master/mnist

# -*- coding: utf-8 -*-
"""
Created on Sun Jan 12 14:56:02 2020
"""

from __future__ import print_function#则意味着在新旧版本的兼容性方面存在差异,处理方法是按照最新的特性来处理
import torch
import argparse    #python自带的命令行参数解析包,可以用来方便地读取命令行参数
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets, transforms #torchvision包由流行的数据集、模型架构和用于计算机视觉的常见图像转换组成
from torch.optim.lr_scheduler import StepLR  #每过step_size个epoch,做一次学习率更新

class Net(nn.Module): #torch.nn.Module所有神经网络模块的基类
    def __init__(self):
        super(Net, self).__init__() #对继承自父类的属性进行初始化。而且是用父类的初始化方法来初始化继承的属性。
        #输入(N, C_in, H, W) 输出(N, C_out, H_out, W_out)
        #MNIST图像:28 * 28
        self.conv1 = nn.Conv2d(1, 32, 3, 1)  # 二维卷积层:输入通道数,输出通道数,kernel_size,stride
        self.conv2 = nn.Conv2d(32, 64, 3, 1)
        self.dropout1 = nn.Dropout2d(0.25)
        self.dropout2 = nn.Dropout2d(0.5)
        self.fc1 = nn.Linear(9216, 128)
        self.fc2 = nn.Linear(128, 10)   #10个数字,10类
    
    def forward(self, x):
        #28 * 28
        x = self.conv1(x) 
        #26 * 26
        x = F.relu(x)
        x = self.conv2(x)
        #24 * 24
        x = F.max_pool2d(x, 2) #池化
        #12 * 12
        x = self.dropout1(x)
        x = torch.flatten(x, 1)
        #9216 * 1
        x = self.fc1(x)
        #128 * 1
        x = F.relu(x)
        x = self.dropout2(x)
        x = self.fc2(x)
        #10 * 1
        output = F.log_softmax(x, dim = 1)   #(N, C, H, W)  转换成概率分布的形式,并且取对数
        return output
    
def train(args, model, device, train_loader, optimizer, epoch):
    model.train()#针对在网络train和eval时采用不同方式的情况,比如 BatchNormalization 和 Dropout
    for batch_idx, (data, target) in enumerate(train_loader):  #enumerate返回索引和值
        data, target = data.to(device), target.to(device)#将所有最开始读取数据时的tensor变量copy一份到device所指定的GPU上去
        optimizer.zero_grad() #梯度置零
        output = model(data)
        loss = F.nll_loss(output, target) #log_softmax对应nll_loss softmax对应CrossEntopyLoss
        loss.backward()  #反向
        optimizer.step() #更新参数空间。step函数使用的是当前参数空间对应的梯度,所以在optimizer使用之前要清零一下
        #间隔输出  某个batch的loss
        if batch_idx % args.log_interval == 0:
            print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
                epoch, batch_idx * len(data), len(train_loader.dataset),
                100. * batch_idx / len(train_loader), loss.item())) #item获得一个元素tensor的value
            #dataset的长度:数据集的长度 
            #loader的长度:batch的数量
            #data的长度:一个batch的大小 batch_size
def test(args, model, device, test_loader):
    model.eval()#测试模式
    test_loss = 0
    correct = 0
    with torch.no_grad():  #数据不需要计算梯度,也不会进行反向传播
        for data, target in test_loader:
            data, target = data.to(device), target.to(device)
            output = model(data)
            test_loss += F.nll_loss(output, target, reduction = 'sum').item() # sum up batch loss
            pred = output.argmax(dim = 1, keepdim = True) # get the index of the max log-probability
            correct += pred.eq(target.view_as(pred)).sum().item() 
            #view_as:返回被视作与给定的tensor相同大小的原tensor
            
    test_loss /= len(test_loader)
    #test_loss是累计了所有batch的loss, 所以取平均
    print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(
        test_loss, correct, len(test_loader.dataset), 
        100. * correct / len(test_loader.dataset)))


def main():
    # Training settings
    parser = argparse.ArgumentParser(description = 'Pytorch MNIST Example')  #ArgumentParser类生成一个对象,description描述信息
    parser.add_argument('--batch-size', type = int, default = 64, metavar = 'N',  #增加参数
                        help = 'input batch size for training (default:64)')
    parser.add_argument('--test-batch-size', type = int , default = 1000, metavar = 'N',
                        help = 'input batch size for testing (default:1000)')
    parser.add_argument('--epochs', type = int, default = 1, metavar = 'N',  #避免跑太久,先设为1
                        help = 'number of eopchs to train (default:14)')  #help用来描述这个选项的作用
    parser.add_argument('--lr', type = float, default = 1.0, metavar = 'LR', #metavar用在help信息的输出中
                        help = 'learning rate (default:1.0)')
    parser.add_argument('--gamma', type = float, default = 0.7, metavar = 'M',
                        help = 'Learning rate step gamma (default:0.7)')
    parser.add_argument('--no-cuda', action = 'store_true', default = False,
                        help = 'disables CUDA training')
    parser.add_argument('--seed', type = int, default = 1, metavar = 'S',
                        help = 'random seed (default:1)')
    parser.add_argument('--log-interval', type = int, default = 10, metavar = 'N',
                        help = 'how many batches to wait before logging training status')
    parser.add_argument('--save-model', action = 'store_true', default = False,
                        help = 'For Saving the current Model')
    
    args = parser.parse_args()  #parser对象的parse_args()获取解析的参数
    use_cuda = not args.no_cuda and torch.cuda.is_available() #有GPU:args.no_cuda=false,torch.cuda.is_available=true
    
    torch.manual_seed(args.seed)#设置种子用于生成随机数,以使得结果是确定的

    device = torch.device("cuda" if use_cuda else "cpu")
    #num_workers:加载数据时使用多少子进程 
    kwargs = {'num_workers' : 1, 'pin_memory' : True} if use_cuda else{}
    train_loader = torch.utils.data.DataLoader(
        #在训练模型时使用到此函数,用来把训练数据分成多个小组,此函数每次抛出一组数据。
        #直至把所有的数据都抛出。就是做一个数据的初始化。
        #DataLoader就是用来包装所使用的数据,每次抛出一批数据 
        # 从数据库中每次抽出batch_size个样本
        datasets.MNIST('../data',train = True, download = True,
                       transform = transforms.Compose([
                           transforms.ToTensor(),
                           transforms.Normalize((0.1307,),(0.3081,))
                           ])),
        batch_size = args.batch_size, shuffle = True, **kwargs) #batch_size表示batch大小,shuffle:是否打乱数据顺序
    test_loader = torch.utils.data.DataLoader(
        datasets.MNIST('../data', train=False, transform=transforms.Compose([
                           transforms.ToTensor(),
                           transforms.Normalize((0.1307,), (0.3081,))
                       ])),
        batch_size=args.test_batch_size, shuffle=True, **kwargs)
    
    model = Net().to(device)
    optimizer = optim.Adadelta(model.parameters(), lr = args.lr)
    
    scheduler = StepLR(optimizer, step_size = 1, gamma = args.gamma)
    for epoch in range(1, args.epochs + 1):
        train(args, model, device, train_loader, optimizer, epoch)
        test(args, model, device, test_loader)
        scheduler.step()  #用来更新优化器的学习率
        
    
    if args.save_model:
        torch.save(model.state_dict(), "mnist_cnn.pt")#state_dict 是一个简单的python的字典对象,将每一层与它的对应参数建立映射关系

if __name__ == '__main__':
    main()
        
 #(注释皆为自己理解,如有错误,欢迎指出)    

只跑了一轮
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

发布了34 篇原创文章 · 获赞 51 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_39480875/article/details/104130713