前言
机器学习应用博客中,将核心介绍三大类学习,即:无监督学习、监督学习、强化学习。
本篇将简要介绍监督学习的“手写数字识别”实例
运用MNIST数据集和DBRHD数据集,使用神经网络实现和KNN实现识别功能
一、实例介绍
1.图像识别(lmage Recognition)
(1)定义是指利用计算机对图像进行处理、分析和理解,以识别各种不同模式的目标和对像的技术。 (2)图像识别的发展经历了三个阶段:文字识别、数字图像处理与识别、物体识别。(机器学习领域一般将此类识别问题转化为分类问题。)
2.手写识别
(1)手写识别是常见的图像识别任务。 (2)计算机通过手写体图片来识别出图片中的字,与印刷字体不同的是,不同人的手写体风格迥异,大小不一,造成了计算机对手写识别任务的一些困难。 (3)数字手写体识别由于其有限的类别(0~9共10个数字)成为了相对简单的手写识别任务。DBRHD和MNIST是常用的两个数字手写识别数据集。
3.MNIST数据集
(1)下载链接:http://yann.lecun.com/exdb/mnist/ (2)MNIST是一个包含数字0~9的手写体图片数据集,图片已归一化为以手写数字为中心的28*28规格的图片。 (3)MNIST由训练集与测试集两个部分组成,各部分规模如下: 1)训练集:60,000个手写体图片及对应标签 2)测试集:10,000个手写体图片及对应标签 (4)手写数字样例
1)MNIST数据集中的每一个图片由28*28个像素点组成。 2)每个像素点的值区间为0~255,0表示白色,255表示黑色。
4.DBRHD数据集
(1)下载链接:https://archive.ics.uci.edu/ml/datasets/Pen-Based+Recognition+of+Handwritten+Digits (2)DBRHD (Pen-Based Recognition of HandwrittenDigits Data Set)是UCI的机器学习中心提供的数字手写体数据库
(3)DBRHD数据集包含大量的数字0~9的手写体图片,这些图片来源于44位不同的人的手写数字,图片已归一化为以手写数字为中心的32*32规格的图片。
(4)DBRHD的训练集与测试集组成如下: 1)训练集:7,494个手写体图片及对应标签,来源于40位手写者。 2)测试集:3,498个手写体图片及对应标签,来源于14位手写者。
(5)数据集特点 1)去掉了图片颜色等复杂因素,将手写体数字图片转化为训练数据为大小32*32的文本矩阵。 2)空白区域使用0代表,字迹区域使用1表示。
5.手写识别实例
(1)已有许多模型在MNIST或DBRHD数据集上进行了实验,有些模型对数据集进行了偏斜矫正,甚至在数据集上进行了人为的扭曲、偏移、缩放及失真等操作以获取更加多样性的样本,使得模型更具有泛化性。
(2)常用于数字手写体的分类器: 1)线性分类器 2)K最近邻分类器 3)非线性分类器 4)SVM 5)MLP多层感知器 6)卷积神经网络 (3)后续任务:利用全连接的神经网络实现手写识别的任务
二、神经网络实现手写识别
1.任务介绍
(1)手写数字识别是一个多分类问题,共有10个分类,每个手写数字图像的类别标签是0~9中的其中一个数。例如下片的标签分别是0,1,2。
(2)任务:利用sklearn来训练一个简单的全连接神经网络,即多层感知机(Multilayer perceptron,MLP)用于识别数据集DBRHD的手写数字。
2.MLP的输入
(1)DBRHD数据集的每个图片是一个由0或1组成的3232的文本矩阵; (2)多层感知机的输入为图片矩阵展开的11024个神经元。
3.MLP的输出(one-hot vectors)
(1)一个one-hot向量除了某一位的数字是1以外其余各维度数字都是0。 (2)图片标签将表示成一个只有在第n维度(从0开始)数字为1的10维向量。 (3)比如,标签0将表示成[1,0,0,0,0,0,0,0,0,0]o即,MLP输出层具有10个神经元。
4.MLP结构
(1)MLP的输入与输出层,中间隐藏层的层数和神经元的个数设置都将影响该MLP模型的准确率。 (2)然而目前的隐藏层只能通过经验性的手动设置 (3)在本实例中,我们只设置一层隐藏层,在后续实验中比较该隐藏层神经元个数为50、100、200时的MLP效果。
5.MLP手写识别实例构建
(1)建立工程并导人sklearn包 (2)加载训练数据 1)定义img2vector函数,将加载的32*32的图片矩阵展开成—列向量 2)定义加载训练数据的函数readDataSet ,并将样本标签转化为one-hot向量 3)调用readDataSet和img2vector函数加载数据,将训练的图片存放在train_dataSet中,对应的标签则存在train_hwLabels中
(3)训练神经网络 1)在sklearnBP .py文件中,构建神经网络∶设置网络的隐藏层数、各隐藏层神经元个数、激活函数、学习率、优化方法、最大迭代次数。 2)使用训练数据训练构建好的神经网络
(4)测试集评价 1)加载测试集 2)使用训练好的MLP对测试集进行测试,并计算错误率
import numpy as np
from os import listdir
from sklearn.neural_network import MLPClassifier
def img2vector(fileName):
retMat = np.zeros([1024],int)
fr = open(fileName)
lines = fr.readline()
for i in range(32):
for j in range(32):
retMat[i*32+j] = lines[i][j]
return retMat
def readDataSet(path):
fileList = listdir(path)
numFiles = len(fileList)
dataSet = np.zeros([numFiles,1024],int)
hwLables = np.zeros([numFiles,10])
for i in range(numFiles):
filePath = fileList[i]
digit = int(filePath.split('_')[0])
hwLables[i][digit] = 1.0
dataSet[i] = img2vector(path+'/'+filePath)
return dataSet,hwLables
tarin_dataSet,train_hwLables = readDataSet('trainingDigits')
clf = MLPClassifier(hidden_layer_sizes=(100,),
activation='logistic',solver='adam',
learning_rate=0.0001,max_iter=2000)
clf.fit(tarin_dataSet,train_hwLables)
dataSet,hwLables = readDataSet('testDigits')
res = clf.predict(dataSet)
error_num = 0
num = len(dataSet)
for i in range(num):
if np.sum(res[i]==hwLables[i])<10:
error_num +=1
print("Total num:",num,"Wrong num:",\
error_num,"WrongRate:",error_num/float(num))
6.实验效果
(1)隐藏层神经元个数影响: 运行隐藏层神经元个数为50、100、200的多层感知机,对比实验效果:
1)随着隐藏层神经元个数的增加,MLP的正确率持上升趋势; 2)大量的隐藏层神经元带来的计算负担与对结果的提升并不对等,因此,如何选取合适的隐藏神经元个数是一个值得探讨的问题。
(2)迭代次数影响分析: 设隐藏层神经元个数为100,初始学习率为0.0001,最大迭代次数分别为500、1000、1500、2000,结果如下:
1)过小的迭代次数可能使得MLP早停,造成较低的正确率。 2)当最大迭代次数>1000时,正确率基本保持不变,这说明MLP在第1000迭代时已收敛,剩余的迭代次数不再进行。 3)—般设置较大的最大迭代次数来保证多层感知机能够收敛,达到较高的正确率。
(3)学习率影响分析: 改用随机梯度下降优化算法即将MLPclassifer的参数( solver=‘sgd’,),设隐藏层神经元个数为100,最大迭代次数为2000,学习率分别为:0.1、0.01、0.001、0.0001。
1)较小的学习率带来了更低的正确率,这是因为较小学习率无法在2000次迭代内完成收敛 2)而步长较大的学习率使得MLP在2000次迭代内快速收敛到最优解 3)因此,较小的学习率一般要配备较大的迭代次数以保证其收敛。
三、KNN实现手写识别
1.任务介绍
(1)本实例利用sklearn来训练一个K最近邻(k-NearestNeighbor,KNN)分类器,用于识别数据集DBRHD的手写数字。 (2)比较KNN的识别效果与多层感知机的识别效果。
2.KNN的输入
(1)DBRHD数据集的每个图片是一个由0或1组成的32*32的文本矩阵; (2)KNN的输入为图片矩阵展开的一个1024维的向量。
3.KNN手写识别实体构建
(1)建立工程并导入sklearn包 (2)加载训练数据 1)定义img2vector函数,将加载的32*32的图片矩阵展开成—列向量 2)定义加载训练数据的函数readDataSet 3)调用readDataSet和img2vector函数加载数据,将训练的图片存放在train_dataSet中
(3)构建KNN分类器 1)设置查找算法以及邻居点数量(k)值 2)KNN是一种懒得学习法,没有学习过程,只在预测时去查找最近邻的点,数据集的输入就是构建KNN分类器的过程 3)构建KNN时调用fit函数
(4)测试集评价 1)加载测试集 2)使用训练好的KNN对测试集进行测试,并计算错误率
import numpy as np
from os import listdir
from sklearn import neighbors
def img2vector(fileName):
retMat = np.zeros([1024],int)
fr = open(fileName)
lines = fr.readline()
for i in range(32):
for j in range(32):
retMat[i*32+j] = lines[i][j]
return retMat
def readDataSet(path):
fileList = listdir(path)
numFiles = len(fileList)
dataSet = np.zeros([numFiles,1024],int)
hwLables = np.zeros([numFiles])
for i in range(numFiles):
filePath = fileList[i]
digit = int(filePath.split('_')[0])
hwLables[i] = digit
dataSet[i] = img2vector(path+'/'+filePath)
return dataSet,hwLables
tarin_dataSet,train_hwLables = readDataSet('trainingDigits')
knn = neighbors.KNeighborsClassifier(algorithm='kd_tree',n_neighbors=3)
knn.fit(tarin_dataSet,train_hwLables)
dataSet,hwLables = readDataSet('testDigits')
res = knn.predict(dataSet)
error_num = np.sum(res!=hwLables)
num = len(dataSet)
print("Total num:",num,"Wrong num:",\
error_num,"WrongRate:",error_num/float(num))
4.实验效果
(1)邻居数量K影响分析:设置K为1、3、5、7的KNN分类器,对比他们的实验效果。
1)K=3时正确率最高,当K>3时正确率开始下降 2)这是由于当样本为稀疏数据集时(本实例只有946个样本),其第k个邻居点可能与测试点距离较远,因此投出了错误的一票进而影响了最终预测结果。
(2)对比实验(KNN分类器vs.多层感知机) 我们取在上节对不同的隐藏层神经元个数、最大迭代次数、学习率进行的各个对比实验中准确率最高(H)与最差(L)的MLP分类器来进行对比。
(3)结论 1)KNN的准确率远高于MLP分类器,这是由于MLP在小数据集上容易过拟合的原因。 2)MLP对于参数的调整比较敏感,若参数设置不合理,容易得到较差的分类效果,因此参数的设置对于MLP至关重要。
总结
关于监督学习,比较核心的就是分类和回归问题,在此仅用此实例说明两大典型方法,其余便不多做赘述。关于代码之中的一些改进问题,由于用到库中的其他方法,且本人能力有限,大家感兴趣可自行查阅官网API。
关于分类,k近邻分类器、决策树、朴素贝叶斯,SVM需熟练掌握 关于回归,比较常用的为线性回归,至于多元非线性拟合及岭回归,根据数据特征不同可适用于不同场所
两点问题: (1)代码运行需要基础数据支撑,py的自带库中有些内含所需数据,有些则没有,本篇并未放上数据txt文件,只是为了展示无监督学习的体系流程以作演示 (2)在库的包导入若发生问题,看看版本更新问题,以及部分包在近年来命名和函数有所调整,各位客官可面向百度
代码非原创,内容乃网课课件整理所得。 如有问题,欢迎指正!
下一篇将介绍深度学习。
|