当前位置:   article > 正文

MNIST手写数字识别_python手写数字的数据集mnist未输出图像

python手写数字的数据集mnist未输出图像

MNIST手写数字识别

MNIST手写数字识别主要从以下这个部分去讲解:

一、完成代码

二、运行结果

三、代码主要由哪几部分组成

四、剖析每一部分的代码

正文:

一、完成代码

# (1)加载必要的库
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets, transforms

# (2)定义超参数
BATCH_SIZE = 16  # 每批处理的数据
DEVICE = torch.device('cuda' if torch.cuda.is_available() else 'cpu')  # 用GPU还是CPU训练
EPOCHS = 10  # 训练数据集的轮次

# (3)构建pipeline,对图像做处理
pipeline = transforms.Compose([
    transforms.ToTensor(),  # /将图片转化成tensor
    transforms.Normalize((0.1307,), (0.3081,))  # 正则化:降低模型的复杂化
])

# (4)下载、加载数据
from torch.utils.data import DataLoader

# 下载数据集
train_set = datasets.MNIST('data', train=True, download=True, transform=pipeline)

test_set = datasets.MNIST('data', train=False, download=True, transform=pipeline)

# 加载数据
train_loader = DataLoader(train_set, batch_size=BATCH_SIZE, shuffle=True)

test_loader = DataLoader(test_set, batch_size=BATCH_SIZE, shuffle=True)


# (5) 构建网络模型
class Digit(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = nn.Conv2d(1, 10, 5)  # 卷积层 1:灰度图片的通道, 10:输出通道, 5: 卷积核
        self.conv2 = nn.Conv2d(10, 20, 3)  # 卷积层 10:输入通道,20 :输出通道,3:卷积核大小
        self.fc1 = nn.Linear(20 * 10 * 10, 500)  # 全连接层 20*10*10:输入通道,500:输出通道
        self.fc2 = nn.Linear(500, 10)  # 全连接层  500:输入通道,10:输出通道

    def forward(self, x):  # 前向传播
        input_size = x.size(0)  # batch_size  BATCH_SIZE = 16  # 每批处理的数据
        x = self.conv1(x)  # 第一个卷积层 输入:batch*1*28*28 , 输出:batch*10*24*24(28-5+1 = 24)
        x = F.relu(x)  # 激活函数 保持shape不变,输出:batch*10*24*24
        x = F.max_pool2d(x, 2, 2)  # 池化层 最大池化 输入:batch*10*24*24 输出:batch*10*12*12

        x = self.conv2(x)  # 第二个卷积层 输入:batch*10*12*12 输出:batch*20*10*10(12-3+1=10)
        x = F.relu(x)  # 激活函数

        x = x.view(input_size, -1)  # 拉平,把二维图片拉成一维度的,-1:自动计算维度:20*20*10 = 2000

        x = self.fc1(x)  # 全连接层 输入:batch*2000 输出:batch*500
        x = F.relu(x)  # 激活层,保持shpae不变

        x = self.fc2(x)  # 全连接层2 输入:batch*500  输出:batch*10

        output = F.log_softmax(x, dim=1)  # 计算分类就,每个数字的概率值
        return output  # 把概率值给返回回去


# (6) 定义优化器
model = Digit().to(DEVICE)  # 创建一个模型,并把模型放在设备上面去

optimizer = optim.Adam(model.parameters())  # 定义一个优化器,更新模型的参数。优化器有很多种,这只是其中的一个


# (7)定义训练方法
def train_model(model, device, train_loader, optimizer,
                epoch):  # model:模型, device:运行模型的设备(cpu还是gpu), optimizer:优化器,epoch:训练集训练的轮数  EPOCHS = 10  # 训练数据集的轮次
    # 模型训练
    model.train()
    for batch_index, (data, target) in enumerate(train_loader):
        # 部署到DEVICE上去
        data, target = data.to(device), target.to(device)
        # 梯度初始化为0
        optimizer.zero_grad()
        # 训练后的结果
        output = model(data)
        # 计算损失
        loss = F.cross_entropy(output, target)  # 此处使用的是交叉熵损失,交叉熵损失适用于多分类的情况
        # 找到概率值最大的下标
        pred = output.max(1, keepdim=True)  # pred = output.argmax(dim=1)  1:表示维度,这里是指横轴
        # 反向传播
        loss.backward()
        # 参数优化 上一步的反向传播哦,不进行参数更新吗?
        optimizer.step()
        if batch_index % 3000 == 0:  # 每处理3000张图片打印一次损失函数
            print('Train Epoch : {} \t Loss : {:.6}'.format(epoch, loss.item()))  # 输出的数字是6位


# (8)定义测试方法
def test_model(model, device, test_loader):
    # 模型验证  验证什么?
    model.eval()
    # 正确率
    correct = 0.0
    # 测试损失  测试损失?这个是做什么用的?
    test_loss = 0.0
    with torch.no_grad():  # 不会计算梯度,也不会进行反向传播
        for data, target in test_loader:
            # 部署到device上
            data, target = data.to(device), target.to(device)
            # 测试数据
            output = model(data)
            # 计算测试损失
            test_loss = F.cross_entropy(output, target).item()
            # 找到概率值最大的下标
            pred = output.max(1, keepdim=True)[1]  # 值,索引
            # 累计正确的值
            correct += pred.eq(target.view_as(pred)).sum().item()
        test_loss /= len(test_loader.dataset)
        print('Test -- Average loss : {:.4f}, Accuracy : {:.3f}\n'.format(test_loss,
                                                                          100 * correct / len(test_loader.dataset)))


# (9)调用方法(7)(8)
for epoch in range(1, EPOCHS + 1):
    train_model(model, DEVICE, train_loader, optimizer, epoch)
    test_model(model, DEVICE, test_loader)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121

二、运行结果

三、代码主要由哪几部分组成

1、加载必要的库
2、定义超参数
3、构建pipeline,对图像做处理
4、下载、加载数据
 5、构建网络模型
 6、定义优化器
 7、定义训练方法
 8、定义测试方法
 9、调用方法(7)(8)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

四、剖析每一部分的代码

1、加载必要的库
(1)import torch.optim as optim
#导入的是优化器
(2)from torchvision import datasets, transforms
#这个是为了操作MNSIT数据集
  • 1
  • 2
  • 3
  • 4
  • 5
# (1)加载必要的库
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets, transforms
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
2、定义超参数
(1)参数:模型f(x,y)中的y称为模型的参数,可以通过优化算法进行学习。深度学习中,这些参数可以通过训练集进行自动修改的数
(2)超参数:用来定义模型结构或优化策略
(3)BATCH_SIZE = 16  # 每批处理的数据
	# 每次处理图片的数量
(4)EPOCHS = 10  # 训练数据集的轮次
	# 对于训练集进行训练的轮次,有些训练集太小,训练一次并不能取得很好的效果,所以需要多次训练。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
# (2)定义超参数
BATCH_SIZE = 16  # 每批处理的数据
DEVICE = torch.device('cuda' if torch.cuda.is_available() else 'cpu')  # 用GPU还是CPU训练
EPOCHS = 10  # 训练数据集的轮次
  • 1
  • 2
  • 3
  • 4

3、构建pipeline,对图像做处理 (1)ToTensor() #
将图片从它保存的格式,转化成python能够处理的格式。总的来说,就是MNIST数据集在实际生活中,会被各种行业的人所使用,而大家对于MNIST的使用都不是一样的,但是官网又不可能为所有不同的使用方式,单独保存一种图片的保存格式,所以官方会把图片保存为一种格式,但保存的格式可以在使用时进行修改,并提供了各种修改图片格式的函数,比如下面的ToTensor()便是对图片处理的一种函数。而在数据集中图片的存储格式可能是下面这两中格式。

输入模式为(L、LA、P、I、F、RGB、YCbCr、RGBA、CMYK、1)的PIL Image 或 numpy.ndarray (形状为H x W x C)数据范围是[0, 255]

对于上面这两种图片格式,并不是我们想要的,而且这两种图片的格式,在我们的代码中可能是不能够处理的,所以需要对数据集中的图片数据进行ToTensor()处理。
https://www.bilibili.com/read/cv10342533/(该链接对image中的几种输入模式做了详细的解释)
(2)transforms.Normalize((0.1307,), (0.3081,)) # 正则化:降低模型的复杂化 #
Normalize :模型出现过拟合现象时,降低模型的复杂度 疑问:
(1)这儿是对图片进行处理,过拟合是在进行了测试集测试过后与训练集做对比,才能够知道是否有过拟合现象,但这段代码中,好像测试集处理完了,就没进行下一步工作了,那么在这儿的正则化处理有用嘛,还是说这儿的正则化处理是在模型训练的时候,就一直存在损失函数中,在训练集中就一直的防止模型过拟合。
(2)正则化是防止模型吧,因为正则化的时间是在训练过程中,而你如果想要知道模型是否过拟合,必须要经过测试集测试完之后才能够知道。

# (3)构建pipeline,对图片做处理
pipeline = transforms.Compose([
    transforms.ToTensor(),  # /将图片转化成tensor
    transforms.Normalize((0.1307,), (0.3081,))  # 正则化:降低模型的复杂化
])
  • 1
  • 2
  • 3
  • 4
  • 5
4、下载、加载数据
(1)from torch.utils.data import DataLoader
	# 里面有处理数据的一些方法和函数
(2)from torchvision import datasets, transforms
	# torchvision 把一些经典的数据集都保存在datasets中,方便用户自行下载。
(3)train_set = datasets.MNIST('data', train=True, download=True, transform=pipeline)
	# datasets后面直接写你需要下载的数据集的名字。
	# 'data',:下载下来的数据集,放在此时代码文件所在根目录下的data文件中,如果没有data文件夹,系统会自动的创建一个data文件夹。
	#  train=True :由于我们所要下载的是一个训练集,所以这儿的train参数我们赋值为True,如果我们下载的是一个测试集,那么这里应该赋值为Flase。
	# download=True:‘这个参数是询问你是否下载,确实没有搞懂什么要这样去询问用户,我肯定需要下载闪,但也有其他可能,比如它可能直接在网络上传输数据集的图片信息,不把训练集下载带本地。(这只是本人的一些猜想,这里先记着这么用吧,以后遇到了新的使用方式再去记吧,毕竟现在是一个信息爆炸的时代,不要尝试去搞懂这个的所用用法,很多用法可能你一辈子都用不到。)
	#transform=pipeline:这儿使用到了我们前面写的pipeline,这里就更好理解了,在datasets中存储的图片你的格式与我们所需要的格式是不用的,当我们需要使用存储的数据集时,我们需要把图片的格式转化成我们需要的格式,比如:在数据集中图片的存储是彩色图片,但是我们代码处理的图片得是灰色的,这时,我们就需要把图片处理成灰色的,把我们所需图片的要求通过tranform参数,传递给内部函数。
(4)train_loader = DataLoader(train_set, batch_size=BATCH_SIZE, shuffle=True)
	# batch_size=BATCH_SIZE:为啥下载完数据,还需要对数据进行加载呢?我的理解下载的数据可能是放在一个容器里面,但是我们最后要把图片送到模型中去训练,但是一次送多少张图片进去呢?这儿就设定了一次送16中图片进去训练。
	# shuffle=True:这个是询问你是否把图片打乱,将图片打乱训练可以提高模型的泛化能力,防止过拟合,也可以提高模型准确率。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

# (4)下载、加载数据
from torch.utils.data import DataLoader

# 下载数据集
train_set = datasets.MNIST('data', train=True, download=True, transform=pipeline)

test_set = datasets.MNIST('data', train=False, download=True, transform=pipeline)

# 加载数据
train_loader = DataLoader(train_set, batch_size=BATCH_SIZE, shuffle=True)

test_loader = DataLoader(test_set, batch_size=BATCH_SIZE, shuffle=True)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
 5、构建网络模型
  • 1

# (5) 构建网络模型
class Digit(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = nn.Conv2d(1, 10, 5)  # 卷积层 1:灰度图片的通道, 10:输出通道, 5: 卷积核
        self.conv2 = nn.Conv2d(10, 20, 3)  # 卷积层 10:输入通道,20 :输出通道,3:卷积核大小
        self.fc1 = nn.Linear(20 * 10 * 10, 500)  # 全连接层 20*10*10:输入通道,500:输出通道
        self.fc2 = nn.Linear(500, 10)  # 全连接层  500:输入通道,10:输出通道

    def forward(self, x):  # 前向传播
        input_size = x.size(0)  # batch_size  BATCH_SIZE = 16  # 每批处理的数据
        x = self.conv1(x)  # 第一个卷积层 输入:batch*1*28*28 , 输出:batch*10*24*24(28-5+1 = 24)
        x = F.relu(x)  # 激活函数 保持shape不变,输出:batch*10*24*24
        x = F.max_pool2d(x, 2, 2)  # 池化层 最大池化 输入:batch*10*24*24 输出:batch*10*12*12

        x = self.conv2(x)  # 第二个卷积层 输入:batch*10*12*12 输出:batch*20*10*10(12-3+1=10)
        x = F.relu(x)  # 激活函数

        x = x.view(input_size, -1)  # 拉平,把二维图片拉成一维度的,-1:自动计算维度:20*20*10 = 2000

        x = self.fc1(x)  # 全连接层 输入:batch*2000 输出:batch*500
        x = F.relu(x)  # 激活层,保持shpae不变

        x = self.fc2(x)  # 全连接层2 输入:batch*500  输出:batch*10

        output = F.log_softmax(x, dim=1)  # 计算分类就,每个数字的概率值
        return output  # 把概率值给返回回去


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
 6、定义优化器
  • 1

# (6) 定义优化器
model = Digit().to(DEVICE)  # 创建一个模型,并把模型放在设备上面去

optimizer = optim.Adam(model.parameters())  # 定义一个优化器,更新模型的参数。优化器有很多种,这只是其中的一个,有点反向传播改变参数的值的意思


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
 7、定义训练方法
  • 1

# (7)定义训练方法
def train_model(model, device, train_loader, optimizer,
                epoch):  # model:模型, device:运行模型的设备(cpu还是gpu), optimizer:优化器,epoch:训练集训练的轮数  EPOCHS = 10  # 训练数据集的轮次
    # 模型训练
    model.train() # 这个代码没有写train方法,那么这个方法应该是继承自父类的
    for batch_index, (data, target) in enumerate(train_loader):
        # 部署到DEVICE上去
        data, target = data.to(device), target.to(device)
        # 梯度初始化为0
        optimizer.zero_grad()
        # 训练后的结果
        output = model(data)
        # 计算损失
        loss = F.cross_entropy(output, target)  # 此处使用的是交叉熵损失,交叉熵损失适用于多分类的情况
        # 找到概率值最大的下标
        pred = output.max(1, keepdim=True)  # pred = output.argmax(dim=1)  1:表示维度,这里是指横轴
        # 反向传播
        loss.backward()
        # 参数优化 上一步的反向传播哦,不进行参数更新吗?
        optimizer.step()
        if batch_index % 3000 == 0:  # 每处理3000张图片打印一次损失函数
            print('Train Epoch : {} \t Loss : {:.6}'.format(epoch, loss.item()))  # 输出的数字是6位


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
 8、定义`在这里插入代码片`测试方法
  • 1

# (8)定义测试方法
def test_model(model, device, test_loader):
    # 模型验证  验证什么?
    model.eval()
    # 正确率
    correct = 0.0
    # 测试损失  测试损失?这个是做什么用的?
    test_loss = 0.0
    with torch.no_grad():  # 不会计算梯度,也不会进行反向传播
        for data, target in test_loader:
            # 部署到device上
            data, target = data.to(device), target.to(device)
            # 测试数据
            output = model(data)
            # 计算测试损失
            test_loss = F.cross_entropy(output, target).item()
            # 找到概率值最大的下标
            pred = output.max(1, keepdim=True)[1]  # 值,索引
            # 累计正确的值
            correct += pred.eq(target.view_as(pred)).sum().item()
        test_loss /= len(test_loader.dataset)
        print('Test -- Average loss : {:.4f}, Accuracy : {:.3f}\n'.format(test_loss,
                                                                          100 * correct / len(test_loader.dataset)))


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
 9、调用方法(7)(8)
  • 1
# (9)调用方法(7)(8)
for epoch in range(1, EPOCHS + 1):
    train_model(model, DEVICE, train_loader, optimizer, epoch)
    test_model(model, DEVICE, test_loader)

  • 1
  • 2
  • 3
  • 4
  • 5




  • 1
  • 2
  • 3
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/正经夜光杯/article/detail/907784
推荐阅读
相关标签
  

闽ICP备14008679号