本文已参与「新人创作礼」活动,一起开启掘金创作之路。
1. 问题描述:
手写数字识别是一个多分类问题,有10个分类,每个手写数字图像的类别是0-9中的一个数。本文将使用sklearn来训练一个简单的全连接神经网络,对数据集DBRHD进行识别
2. 基本介绍:
DBRHD数据集介绍:
- 已经归一化为手写数字为中心的 规格的图片。
- 去掉了图片颜色等复杂因素,将手写体数字图片转化为训练数据为大小 的文本矩阵。
- 空白区于使用0代表,字迹区域使用1表示。
神经网络参数设置: 设置1层隐藏层,该隐藏层含100个神经元。初始学习率为0.0001,迭代2000次。使用logistic激活函数和adam优化方法。
MLP:多层感知机识别,也可以叫做人工神经网络(ANN)。主要由输入层、输出层以及隐藏层构成,其中隐藏层(hidden layer)可以有多层。
如下图所示,是一个输入为4个,输出为3个,隐藏层有5个节点的多层感知机模型。从图中可以看出,多层感知机模型其实在单层神经网络的基础上引入了一到多个隐藏层。另外,多层感知机中的隐藏层和输出层都是全连接层。
注: 文末附有本文数据集文件,分享给大家一起学习
3. 程序实现
import numpy as np
from os import listdir #用于访问本地文件
from sklearn.neural_network import MLPClassifier
import time
start = time.perf_counter()
## 定义img2vector函数,将加载的32*32的图片矩阵展开成一列向量
def img2vector(fileName):
retMat = np.zeros([1024],int) #定义返回的矩阵,大小为1*1024,整数形式
fr = open(fileName) #打开包含32*32大小的数字文件
lines = fr.readlines() #读取文件的所有行,#readlines()从文件中一行一行地读数据,返回一个列表
for i in range(32): #遍历文件所有行
for j in range(32): #并将0-1数字存放在retMat中
retMat[i*32+j]=lines[i][j]
return retMat
## 定义加载训练数据的函数readDataSet,并将样本标签转化为one-hot向量
def readDataSet(path):
fileList = listdir(path) #获取文件夹下的所有文件
numFiles = len(fileList) #统计需要读取的文件的数目
dataSet = np.zeros([numFiles,1024],int) #用于存放所有的数字文件
hwLabels = np.zeros([numFiles,10]) #用于存放对应的one-hot标签
for i in range(numFiles): #遍历所有的文件
filePath = fileList[i] #获取文件名称/路径
digit = int(filePath.split('_')[0]) #通过文件名获取标签
hwLabels[i][digit] = 1.0 #将对应的one-hot标签置1
dataSet[i] = img2vector(path +'/'+filePath) #读取文件内容
return dataSet,hwLabels
## 调用readDataSet和img2vector函数加载数据,将训练的图片存放在train_dataSet中,对应的标签则存在train_hwLabels中
train_dataSet, train_hwLabels = readDataSet('trainingDigits')
## 构建神经网络:设置网络的隐藏层数、各隐藏层神经元个数、激活函数、学习率、优化方法、最大迭代次数
clf = MLPClassifier(hidden_layer_sizes=(100,), #1层隐藏层,设置含100个神经元的隐藏层,hidden_layer_sizes存放的是一个元组,表示第i层隐藏层里神经元的个数
activation='logistic', solver='adam', #使用logistic激活函数和adam优化方法
learning_rate_init = 0.0001, max_iter=2000) #令初始学习率为0.0001,迭代2000次
## 训练神经网络
print(clf) #fit函数能够根据训练集及对应标签集自动设置多层感知机的输入与输出层的神经元个数
clf.fit(train_dataSet, train_hwLabels)
## 测试集评价
dataSet,hwLabels = readDataSet('testDigits')
res = clf.predict(dataSet) #对测试集进行预测
error_num = 0 #统计预测错误的数目
num = len(dataSet) #测试集的数目
for i in range(num): #遍历预测结果
#比较长度为10的数组,返回包含01的数组,0为不同,1为相同
#若预测结果与真实结果相同,则10个数字全为1,否则不全为1
if np.sum(res[i] == hwLabels[i]) < 10:
error_num += 1
print("Total num:",num," Wrong num:", error_num," WrongRate:",error_num / float(num))
end = time.perf_counter()
t = end-start
print("所用时间为:", t)
4. 运行结果:
模型训练结果如下图所示:
本案例中使用的数据集文件分享给大家:
链接:百度网盘 请输入提取码
提取码:ZiDa
将其中的训练手写图像文件夹命名为trainingDigits
将其中的测试手写图像文件夹命名为testDigits
保存到相应的工作区,运行本文代码即可
感谢阅读,欢迎大家一起交流分享!