使用的软件是pycharm

环境是在anaconda下创的虚拟环境pytorch

整个过程大体为,在画板手写数字,用python代码实现手写数字的批量生成,定义超参数,创建数据集包括训练集和数据集,创建dataloader,构建神经网络,对结果的一种展示。

主要有三个文件,一个number文件夹,包括other文件夹、train文件夹、test文件夹,一个名为CreateHandNumberByPython的 .ipynb 文件,存放的代码用来实现用python实现手写数字的批量产出,https://www.cnblogs.com/AdaminXie/p/8379749.html,这个网站就是编辑这个 .ipynb 的来源,一个名为CNN的 .ipynb 文件,用来实现上述整个过程的其它环节。这三个文件是需要手动创建的。number文件夹下的train和test这两个文件夹是第一个.ipynb文件自动生成的。other文件夹需要手动创建,并手动导入图片,让一个同学手写一些个图片并放进去,像素大小这里是30×30,用电脑中的画板软件就能写出来这样大小像素的图片。下面一次展示另外两个.ipynb 文件的代码。

# 导入相关的库包模块
import random      # random模块,用来获取随机数
import os
from PIL import Image, ImageDraw, ImageFont#%%random.seed(1)          # 设置随机数种子#%%# path_img = "number/train/"   # 设置文件存储路径
path_img = "number/test/"   # 设置文件存储路径# 创建函数mfi,用于创建文件夹number1-9.
def mkdir_for_images():if not os.path.isdir(path_img):os.mkdir(path_img)for i in range(0, 10):  # range包头不包尾# if os.path.isdir(path_img + "train_number_" + str(i)):#     pass# else:#     print(path_img + "train_number_" + str(i))#     os.mkdir(path_img + "train_number_" + str(i))if os.path.isdir(path_img + "test_number_" + str(i)):   # 使用os.path.isdir()函数判断某一路径是否为目录passelse:print(path_img + "test_number_" + str(i))os.mkdir(path_img + "test_number_" + str(i))mkdir_for_images()#%%# 删除路径下的图片 / Clear images in 'number/number_x/'
def clear_images():for i in range(0, 10):# dir_nums = os.listdir(path_img + "train_number_" + str(i))dir_nums = os.listdir(path_img + "test_number_" + str(i))for tmp_img in dir_nums:if tmp_img in dir_nums:# print("delete: ", tmp_img)# os.remove(path_img + "train_number_" + str(i) + "/" + tmp_img)os.remove(path_img + "test_number_" + str(i) + "/" + tmp_img)print("删除完毕", "\n")clear_images()#%%# 生成单张扭曲的数字图像
def generate_single():# 先绘制一个 50*50 的白色背景图像im_50_blank = Image.new('RGB', (50, 50), (255, 255, 255))# 创建画笔draw = ImageDraw.Draw(im_50_blank)# 生成随机数 0-9num = str(random.randint(0, 9))     # randint包头又包尾,random.randint(a, b)生成指定范围内的整数# 设置字体arial,这里选取字体大小 20font = ImageFont.truetype('arial.ttf', 20)# xy 是左上角开始的位置坐标draw.text(xy=(18, 11), font=font, text=num, fill=(0, 0, 0))# 随机旋转-10 ~ 10角度random_angle = random.randint(-10, 10)im_50_rotated = im_50_blank.rotate(random_angle)# 图形扭曲参数params = [1 - float(random.randint(1, 2)) / 100,0,0,0,1 - float(random.randint(1, 10)) / 100,float(random.randint(1, 2)) / 500,0.001,float(random.randint(1, 2)) / 500]# 创建扭曲im_50_transformed = im_50_rotated.transform((50, 50), Image.PERSPECTIVE, params)# 生成新的 30*30 空白图像(截取10-40像素里的内容)im_30 = im_50_transformed.crop([10, 10, 40, 40])return im_30, num#%%# 生成手写体数字 0-9 存入指定文件夹 0-9
def generate_number_0_to_9(n):cnt_num = []for i in range(10):cnt_num.append(0)for m in range(0, n + 1):img, generate_num = generate_single()img_gray = img.convert('1')for j in range(0, 10):if generate_num == str(j):cnt_num[j] = cnt_num[j] + 1# train# print("Generate:", path_img + "train_number_" + str(j) + "/" + str(j) + "_" + str(cnt_num[j]) + ".png")# img_gray.save(path_img + "train_number_" + str(j) + "/" + str(j) + "_" + str(cnt_num[j]) + ".png")# testprint("Generate:", path_img + "test_number_" + str(j) + "/" + str(j) + "_" + str(cnt_num[j]) + ".png")img_gray.save(path_img + "test_number_" + str(j) + "/" + str(j) + "_" + str(cnt_num[j]) + ".png")print("\n")print("生成的数字 0-9 的分布:")for k in range(0, 10):print("数字:", k, ",一共创捷了", cnt_num[k], "个。")def main():# 运行 xx + 1 次generate_number_0_to_9(2000)if __name__ == '__main__':main()

接下来是第二个.ipynb的代码

"""导入各种包"""
import torch
# 导入对图像的预处理模块
from torch.utils.tensorboard import SummaryWriter
from torchvision import transforms
# 导入dataset的分批读取包
from torch.utils.data import DataLoader
# 导入神经网络包nn(可以定义和运行神经网络)
import torch.nn as nn
# 有些导入functional这个包中包含了神经网络中使用的一些常用函数,这些函数的特点:不具有可学习的参数(RelU,pool,DropOut等)
import torch.nn.functional as F
# optim中实现了大多数的优化方法来更新网络权重和参数,如SGD、Adam
import torch.optim as optim
import time
import matplotlib.pyplot as plt
import random
from numpy import argmax
import numpy as np
from PIL import Image
from glob import glob
from torch.utils import data#%%# Basic Params-----------------------------
'''定义各个超参数'''epoch = 5  # 模型训练轮数
learning_rate = 0.01  # 设置SGD中的初始学习率
gpu = torch.cuda.is_available()
momentum = 0.5  # 设置SGD中的冲量
allNumberPath = glob(r"./number/*/*/*.png")  # 所有数字路径
trainPath = glob(r"./number/train/*/*.png")  # 训练集路径
# for i in trainPath:
#     print(i)
testPath = glob(r"./number/test/*/*.png")  # 测试集路径
handPath = glob(r"./number/other/*/*.png") # 手写集路径#%%# Create Data-------------------------------
'''创建数据集整体框架'''# 对数据进行转换处理
transform = transforms.Compose([transforms.Resize((30, 30)),transforms.ToTensor(),transforms.Normalize((0.1307,), (0.3081,))    # 减去均值,除以方差。对数据进行标准化,去更好的响应激活函数。
])class MyDataset(torch.utils.data.Dataset):  # 需要继承torch.utils.data.Datasetdef __init__(self, img_path, label, transform):  # 初始化# TODO# 初始化一些参数和函数,方便在__getitem__函数中调用。self.img = img_path  # 数字图片路径self.label = label  # 标签self.transforms = transform  # 预处理# 也就是在这个模块里,我们所做的工作就是初始化该类的一些基本参数。passdef __getitem__(self, index):  # 切片,用于获取相应图片# TODOimg = self.img[index]label = self.label[index]# 1、根据list从文件中读取一个数据(例如,使用numpy.fromfile,PIL.Image.open)。pil_img = Image.open(img)pil_img = pil_img.convert("L")# 2、预处理数据(例如torchvision.Transform)。data = self.transforms(pil_img)# 3、返回数据对(例如图像和标签)。return data, label# 这里需要注意的是,这步所处理的是index所对应的一个样本。def __len__(self):  # 获取长度# 返回数据集大小return len(self.img)#%%# add labels--------------------------------
"""为每张图片制作对应标签"""# 训练用图片标签
train_species = []
for i in range(0, 10):train_species.append("train_number_" + str(i))# 测试用图片标签
test_species = []
for i in range(0, 10):test_species.append("test_number_" + str(i))# 手写图片标签
hand_species = []
for i in range(0, 10):hand_species.append("hand_number_" + str(i))
print(hand_species)
# 将标签与文件夹名字捆绑,存到字典里
# enumerate:带序号的输出里面内容,dict:创造字典类型
train = dict((c, i) for i, c in enumerate(train_species))
# print(train)test = dict((c, i) for i, c in enumerate(test_species))
# print(test)hand = dict((c, i) for i, c in enumerate(hand_species))
print(hand)# 创建训练用标签列表
train_labels = []
for img in trainPath:  # 文件夹里每有一张图片,则向列表添加一个对应标签for i, c in enumerate(train_species):if c in img:train_labels.append(i)# 测试用,同上
test_labels = []
for img in testPath:for i, c in enumerate(test_species):if c in img:test_labels.append(i)# 手写集,同上
hand_labels = []
for img in handPath:for i, c in enumerate(hand_species):if c in img:hand_labels.append(i)# 所有标签,二合一
all_labels = []
for img in allNumberPath:# 区分出每个img,应该属于什么类别for i, c in enumerate(train_species):if c in img:all_labels.append(i)for i, c in enumerate(test_species):if c in img:all_labels.append(i)
# print(all_labels)#%%# ----------------------------------------
"""创建训练用与测试用数据集"""train_dataset = MyDataset(trainPath, train_labels, transform)
# print(len(train_dataset))
test_dataset = MyDataset(testPath, test_labels, transform)
# print(len(test_dataset))
hand_dataset = MyDataset(handPath, hand_labels, transform)
print(len(hand_dataset))#%%# -----------------------------------------
"""创造dataloader"""BATCH_SIZE = 4  # 样本一共分成多少批    batch:批
train_dataloader = data.DataLoader(train_dataset,  # 哪个训练集batch_size=BATCH_SIZE,  # 一次加载多少个shuffle=True  # 是否打乱顺序
)test_dataloader = data.DataLoader(test_dataset,batch_size=BATCH_SIZE,shuffle=True
)hand_dataloader = data.DataLoader(hand_dataset,batch_size=1,shuffle=True
)
imgs_train, labels_train = next(iter(train_dataloader))
train_dataloader_size = len(train_dataloader)
print(imgs_train.shape)
print(labels_train)
print(train_dataloader_size)imgs_test, labels_test = next(iter(test_dataloader))
test_dataloader_size = len(test_dataloader)
print(test_dataloader_size)imgs_hand, labels_hand = next(iter(hand_dataloader))
hand_dataloader_size = len(hand_dataloader)#%%# train net-------------------------------
'''创造神经网络'''class Net(nn.Module):def __init__(self):super(Net, self).__init__()# 构建简单的序贯模型self.model = nn.Sequential(nn.Conv2d(in_channels=1, out_channels=32,  # 进入通道为1,输出通道为32kernel_size=3, stride=1, padding=1),  # 输入:1*30*30,输出维度32*30*30;卷积核大小:3*3nn.ReLU(),  # 激活函数不会修改数据的形状nn.MaxPool2d(kernel_size=2, stride=2),  # 输入:32*30*30,输出:32*15*15nn.Conv2d(in_channels=32, out_channels=64, kernel_size=3, stride=1, padding=1),  # 输入32*15*15,输出64*15*15nn.ReLU(),nn.MaxPool2d(kernel_size=2, stride=2),  # 输入:64*15*15,输出:64*7.5*7.5nn.Flatten(),nn.Linear(in_features=3136, out_features=128),# 第一个全连接层的输出形状:输入:64*14*14,输出batch_size*128,这里的128是个人设定的,你也可以设置为别的,nn.Linear(in_features=128, out_features=10),  # 第二个全连接层的输出形状:[batch_size,10],因为手写数字有10个类别)def forward(self, x):return self.model(x)if gpu:net = Net().cuda()
else:net = Net()#%%# -----------------------------------------------
"""绘制sigmoid函数"""# nums = np.arange(-10, 10, step=1)  # 生成一个numpy数组
# fig, ax = plt.subplots(figsize=(12, 4))  # 绘制子图
# ax.plot(nums, 1.0 / (1 + np.exp(-nums)), 'r')  # 绘制sigmoid的函数图像
# plt.show()#%%# -----------------------------------------------
"""创建损失函数"""
if gpu:loss_fn = nn.CrossEntropyLoss().cuda()
else:loss_fn = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=learning_rate, momentum=0.9)#%%# -------------------------------------------------
"""创建summaryWriter"""
writer = SummaryWriter(log_dir='logs/{}'.format(time.strftime('%Y%m%d-%H%M%S')))#%%# -------------------------------------------------
"""对train_dataloader进行训练"""
total_train_step = 0def train(epoch):  # epoch:训练轮数global total_train_steptotal_train_step = 0for data in train_dataloader:  # 遍历train_loaderimgs, targets = dataif gpu:imgs, targets = imgs.cuda(), targets.cuda()optimizer.zero_grad()  # 梯度置为0outputs = net(imgs)  # 进行向前计算loss = loss_fn(outputs, targets)  # 带权损失loss.backward()  # 进行反向传播,计算梯度optimizer.step()  # 参数更新if total_train_step % 50 == 0:  # 每一次训练50个print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(epoch, total_train_step, train_dataloader_size,100. * total_train_step / train_dataloader_size, loss.item()))writer.add_scalar('loss', loss.item(), total_train_step)total_train_step += 1#%%# -----------------------------------------------
"""对test_dataloader进行测试"""def test(test_dataloader):correct = 0total = 0with torch.no_grad():  # 不需要计算梯度for data in test_dataloader:imgs, targets = dataif gpu:imgs, targets = imgs.cuda(), targets.cuda()outputs = net(imgs)  # 进行向前计算_, predicted = torch.max(outputs.data, 1)  # 获取最大值的位置,[batch_size,1]total += targets.size(0)correct += (predicted == targets).sum().item()print('Test Accuracy: {}/{} ({:.0f}%)'.format(correct, total, 100. * correct / total))return correct / total#%%# -----------------------------------------------------
"""对训练和测试的结果进行展示"""
Test_Accuracy = {}      # 用于存储网络模型及其准确率
for i in range(1, epoch + 1):print("-----------------Epoch: {}-----------------".format(i))train(i)    # 训练test(test_dataloader)   # 测试writer.add_scalar('test_accuracy', test(test_dataloader), total_train_step)Test_Accuracy.update({test(test_dataloader): net})      # 保存print(Test_Accuracy.items())
highest_accuracy = max(Test_Accuracy.keys())    # 查找最高准确率
best_net = Test_Accuracy[highest_accuracy]      # 找到那个准确率最高的net模型
torch.save(best_net, 'model/mnist_model.pth')  # 将训练模型保存到如左所示路径
print('Saved the best model')writer.close()#%%model = torch.load("./model/mnist_model.pth")
model.eval()
print(model)#%%fig = plt.figure(figsize=(20, 20))
for i in range(20):# random numberindex = random.randint(0, test_dataloader_size)data = test_dataloader.dataset[index]if gpu:img = data[0].cuda()else:img = data[0]img = torch.reshape(img, (1, 1, 30, 30))with torch.no_grad():output = model(img)# plot the image and the predicted numberfig.add_subplot(4, 5, i + 1)plt.title(argmax(output.data.cpu().numpy()), fontdict={"fontsize": 30})plt.imshow(data[0].numpy().squeeze(), cmap='gray')plt.show()#%%test(hand_dataloader)
writer.add_scalar('hand_accuracy', test(hand_dataloader), total_train_step)fig = plt.figure(figsize=(30, 30))
for i in range(hand_dataloader_size):data = hand_dataloader.dataset[i]if gpu:img = data[0].cuda()else:img = data[0]img = torch.reshape(img, (1, 1, 30, 30))with torch.no_grad():output = model(img)# plot the image and the predicted numberfig.add_subplot(4, 6, i + 1)plt.title(argmax(output.data.cpu().numpy()), fontdict={"fontsize": 30})plt.imshow(data[0].numpy().squeeze(), cmap='gray')plt.show()

至此,准备就绪,,一次点击两个.ipynb的运行按钮即可,按钮如图

或许会遇到一些问题。

这个问题,需要升级torchvision

其它问题上网搜索解决即可。

本代码识别图片的正确率并不能达到百分之百,相反正确率比较低。希望各位网友提出友好建议。

能成功运行出结果或者对你有所帮助的话,就给个赞吧

Pytorch CNN 手写数字识别 0-9相关推荐

  1. pytorch MNIST 手写数字识别 + 使用自己的测试集 + 数据增强后再训练

    文章目录 1. MNIST 手写数字识别 2. 聚焦数据集扩充后的模型训练 3. pytorch 手写数字识别基本实现 3.1完整代码及 MNIST 测试集测试结果 3.1.1代码 3.1.2 MNI ...

  2. 使用Pytorch实现手写数字识别

    使用Pytorch实现手写数字识别 1. 思路和流程分析 流程: 准备数据,这些需要准备DataLoader 构建模型,这里可以使用torch构造一个深层的神经网络 模型的训练 模型的保存,保存模型, ...

  3. 用PyTorch进行手写数字识别

    目录 数据准备 网络模型 完整实现 数据准备 torch.utils.data.Datasets是PyTorch用来表示数据集的类,它是用PyTorch进行手写数字识别的关键. 下面是加载mnist数 ...

  4. python手写多个字母识别_一个带界面的CNN手写数字识别,使用Python(tensorflow, kivy)实现...

    CNN_Handwritten_Digit_Recognizer (CNN手写数字识别) A CNN handwritten digit recognizer with graphical UI, i ...

  5. pytorch CNN手写字体识别

    ## """CNN手写字体识别"""import torch import torch.nn as nn from torch.autogr ...

  6. 卷积神经网络CNN 手写数字识别

    1. 知识点准备 在了解 CNN 网络神经之前有两个概念要理解,第一是二维图像上卷积的概念,第二是 pooling 的概念. a. 卷积 关于卷积的概念和细节可以参考这里,卷积运算有两个非常重要特性, ...

  7. CNN 手写数字识别

    1. 知识点准备 在了解 CNN 网络神经之前有两个概念要理解,第一是二维图像上卷积的概念,第二是 pooling 的概念. a. 卷积 关于卷积的概念和细节可以参考这里,卷积运算有两个非常重要特性, ...

  8. pytorch实现手写数字识别_送源码!人工智能实现:识别图片中的手写数字,值得收藏...

    作者|小林同学 关注<高手杰瑞>,每天有不一样的实用小教程发布哦! 哈喽,大家好我是杰瑞.今天我给大家带来一个用机器学习的方法来实现手写数字识别的教程,就像C语言中输出的那一行" ...

  9. 【图像识别】基于卷积神经网络CNN手写数字识别matlab代码

    1 简介 针对传统手写数字的随机性,无规律性等问题,为了提高手写数字识别的检测准确性,本文在研究手写数字区域特点的基础上,提出了一种新的手写数字识别检测方法.首先,对采集的手写数字图像进行预处理,由于 ...

最新文章

  1. 阿里巴巴测试环境稳定性提升实践
  2. matlab 左除和右除
  3. Apache Kafka之设计
  4. SpringBoot 2.0 + 阿里巴巴 Sentinel 动态限流实战
  5. ML:人工智能之机器学习ML解决实际应用问题的思路总过程(最全)
  6. 用阿里云的免费SSL 证书让网站从HTTP换成HTTPS
  7. PCA(主成分分析)思想及实现
  8. 计算机网络(十七)-局域网
  9. 猫眼java开发工资_Java硕士京东工作1年,跳槽后他期望薪资26K,大家感觉他可以吗...
  10. 烂泥:dnsmasq搭建简易DNS服务器
  11. 花式Finetune方法大汇总
  12. 几校联考——day1题解
  13. CentOS系统查看本机IP地址
  14. 为什么泛型类的类型不能是基本数据类型
  15. RK 7.1 OTA升级提示Not enough free space on /cache to apply patches
  16. antd select 等组件可搜索问题
  17. 【NPM】ubuntu20.04安装npm
  18. 同态加密:分圆多项式简介
  19. c语言实现天气预报步骤,天气预报的制作流程
  20. 达观数据基于Deep Learning的中文分词尝试

热门文章

  1. matlab图像边缘宽度调整
  2. 基于Java的XXX管理系统的设计与实现——毕业设计题目
  3. wiring的运行(使用open source产品组装你的web应用架构)
  4. 会声会影2023旗舰版中文版永久功能使用技巧说明
  5. 西安电子科技大学计算机研一水课答案整理
  6. Ubuntu20.04 VSCode 配置C++环境及GTK+配置【纯个人总结用】
  7. 基于JAVA老鹳窝旅游网计算机毕业设计源码+数据库+lw文档+系统+部署
  8. 用TL494实现单回路控制器
  9. 【浅墨Unity3D Shader编程】之中的一个 夏威夷篇:游戏场景的创建 amp; 第一个Shader的书写...
  10. 项目:基于ffmpeg的Gif表情包生成器