当前位置:首页 » 《随便一记》 » 正文

使用神经网络识别手写数字

5 人参与  2022年10月07日 08:14  分类 : 《随便一记》  评论

点击全文阅读


PyTorch, MNIST

ModelTrainResult

本文目标:理解代码,能够复现
更多细节指路⭐️代码参考原博客写得非常详细?

实际上识别手写数字是大二《人工智能》的一个实验,当时用的是TensorFlow

在这里插入图片描述
对于这个数据集手动扩展训练数据的话,比如平移、旋转一个角度这样.
Neural Networks and Deep Learning.Michael Nielsen非常通俗易懂,以此为例带人入门神经网络.快看完了,真的对新手友好?

Model

# model.py# 继承于nn.Module这个父类class MnistNet(nn.Module):    # 初始化网络结构    def __init__(self):        super(MnistNet, self).__init__()        # 全连接        self.fc1 = nn.Linear(28 * 28 * 1, 28)        self.fc2 = nn.Linear(28, 10) # 尺寸,数据集的类别10    # 正向传播过程    def forward(self, x):        # 把三维的张量展平成一维向量        x = x.view(-1, 28 * 28 * 1)        x = self.fc1(x)  # [batch_size,28]        x = F.relu(x)  # [batch_size,28]        x = self.fc2(x)  # [batch_size,10]        # return x        # return F.sigmoid(x)        return F.log_softmax(x, dim=-1) # 对softmax取对数

Train

import torchfrom torch import nnfrom torch import optimimport torch.nn.functional as Fimport torchvision# 一般都要分批次进行训练,硬件算力非常有限train_batch_size = 64test_batch_size = 1000# MNIST数据集中图像的尺寸28*28img_size = 28def get_dataloader(train=True):    assert isinstance(train, bool), "train 必须是bool类型"    # 准备数据集,其中0.1307,0.3081为MNIST数据的均值和标准差,这样操作能够对其进行标准化    # 因为MNIST只有一个通道(黑白图片),所以元组中只有一个值    # 第一次使用要将download设置为True才会自动下载数据集    # torchvision.datasets在先导入pytorch中的数据集    dataset = torchvision.datasets.MNIST('/data', train=train, download=False,                                         transform=torchvision.transforms.Compose([                                             torchvision.transforms.ToTensor(),                                             torchvision.transforms.Normalize((0.1307,), (0.3081,)), ]))    # 准备数据迭代器    batch_size = train_batch_size if train else test_batch_size    dataloader = torch.utils.data.DataLoader(dataset, batch_size=batch_size, shuffle=True)    return dataloader# model.py···# 定义训练的网络模型mnist_net = MnistNet()# 优化器adam,学习率设为0.001optimizer = optim.Adam(mnist_net.parameters(), lr=0.001)# criterion = nn.NLLLoss()# criterion = nn.CrossEntropyLoss()train_loss_list = []train_count_list = []def train(epoch):    mode = True    mnist_net.train(mode=mode)    train_dataloader = get_dataloader(train=mode)    # loss_function = nn.CrossEntropyLoss()    print(len(train_dataloader.dataset))    print(len(train_dataloader))    # 遍历训练集    for idx, (data, target) in enumerate(train_dataloader):        # 清除历史梯度        optimizer.zero_grad()        # 正向传播        output = mnist_net(data)        # 计算损失        # loss = loss_function(output, target)  #交叉熵损失        loss = F.nll_loss(output, target) # 对数似然损失        loss.backward() # 反向传播        optimizer.step() # 优化器更新参数        if idx % 10 == 0: # print every 10 mini-batches            print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(                epoch+1, idx * len(data), len(train_dataloader.dataset),                       100. * idx / len(train_dataloader), loss.item()))            train_loss_list.append(loss.item())            train_count_list.append(idx * train_batch_size + (epoch - 1) * len(train_dataloader))            # 保存训练得到的参数            # python中有一种存储方式,可以存储为.pkl文件,可以将python项目过程中用到的一些暂时变量、或者需要提取、暂存的字符串、列表、字典等数据保存起来            torch.save(mnist_net.state_dict(), "./mnist_net.pkl")            torch.save(optimizer.state_dict(), './mnist_optimizer.pkl')# 测试def test():    test_loss = 0    correct = 0    mnist_net.eval()    test_dataloader = get_dataloader(train=False)    with torch.no_grad(): # 冻结参数:        # 在以下步骤中不用计算每个节点的损失梯度,以防止过度占用内存        for data, target in test_dataloader:            output = mnist_net(data)            test_loss += F.nll_loss(output, target, reduction='sum').item()            pred = output.data.max(1, keepdim=True)[1]  # 获取最大值的位置,[batch_size,1]            correct += pred.eq(target.data.view_as(pred)).sum()    test_loss /= len(test_dataloader.dataset)    print('\nloss: {:.4f}, Accuracy: {}/{} ({:.2f}%)\n'.format(        test_loss, correct, len(test_dataloader.dataset),        100. * correct / len(test_dataloader.dataset)))if __name__ == '__main__':    test()    for i in range(10):  # epoch自己根据需要调轮数        train(i)        test()

在这里插入图片描述

Result

在这里插入图片描述
原代码跑的epoch1的acc=93.26%
其实没训练过的时候,随便也有12%~13%
第一次
跑完acc有95.75%

但是《NNDL》上说精度能到99%,所以简单鼓捣一下

1、简单粗暴增加epoch次数
epoch = 10
acc=96.33%
dierci
epoch = 30
acc=96.33%
disici

2、损失函数
这里学到的,在pytorch中有两种方式实现交叉熵损失
①loss = nn.CrossEntropyLoss(input,target)

②把softmax概率传入对数似然损失得到的损失函数:

#1. 对输出值计算softmax和取对数output = F.log_softmax(x,dim=-1)#2. 使用torch中带权损失loss = F.nll_loss(output,target)

3、激活函数
把softmax换成sigmoid
第三次不明白

更改超参数得到改进不是很随便的,但是简单任务来看,训练epoch多一点,精度好一点,一般来讲.


点击全文阅读


本文链接:http://zhangshiyu.com/post/45185.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1