关于模式识别作业——利用分类器实现手写数字识别
数据库:MNIST http://yann.lecun.com/exdb/mnist/
编写分类器程序,要求:
1)选用课上讲述过的分类器
2)使用交叉验证法生成训练集及测试集,并以此为基础评价模型的泛化误差。
3)总结影响分类器算法结果的因素。
第一步:利用matlab对MNIST数据进行读取。
————————————————————-*****************************************************—————————————————————————
插入:关于测试集和训练集
训练集、验证集和测试集这三个名词在机器学习领域极其常见
训练集
作用:估计模型
学习样本数据集,通过匹配一些参数来建立一个分类器。建立一种分类的方式,主要是用来训练模型的。
测试集
作用:检验最终选择最优的模型的性能如何
主要是测试训练好的模型的分辨能力(识别率等)
为何需要划分
简而言之,为了防止过度拟合。如果我们把所有数据都用来训练模型的话,建立的模型自然是最契合这些数据的,测试表现也好。但换了其它数据集测试这个模型效果可能就没那么好了。总而言之训练集和测试集相同的话,模型评估结果可能比实际要好。
总结
显然,training set是用来训练模型或确定模型参数的,如ANN中权值等; validation set是用来做模型选择(model selection),即做模型的最终优化及确定的,如ANN的结构;而 test set则纯粹是为了测试已经训练好的模型的推广能力。当然,test set这并不能保证模型的正确性,他只是说相似的数据用此模型会得出相似的结果。但实际应用中,一般只将数据集分成两类,即training set 和test set,大多数文章并不涉及validation set。
一个典型的划分是训练集占总样本的50%,而其它各占25%,三部分都是从样本中随机抽取。
———————————————————————————-********************************************************———————————————————————
mnist数据集原网站下载下来的格式无法直接打开,需要对mnist数据集下载之后解压,
在 Windows 平台下解压这些文件时,操作系统会自动修改这些文件的文件名,比如会将倒数第二个短线-修改为.,也即 train-images-idx3-ubyte.gz 解压为train-images.idx3-ubyte(文件类型就自作主张地变成了idx3-ubyte)。.matlab要想对这些数据进行使用,就需要编写程序对数据进行读取。由网上查询matlab读取mnist数据集的程序如下:
clear variables
close all
clc
train_x_file=char(\’train-images.idx3-ubyte\’);%得到vector形式
test_x_file=char(\’t10k-images.idx3-ubyte\’);%得到vector形式
train_y_file=char(\’train-labels.idx1-ubyte\’);%得到vector形式
test_y_file=char(\’t10k-labels.idx1-ubyte\’);%得到vector形式
train_x=decodefile(train_x_file,\’image\’);
test_x=decodefile(test_x_file,\’image\’);
train_labels=decodefile(train_y_file,\’label\’);
test_labels=decodefile(test_y_file,\’label\’);
其中,decodefile.m函数为:
%MNIST源文件下载地址http://yann.lecun.com/exdb/mnist/index.html
%功能:将下载得到的二进制文件转换为10进制数据,提取像素数据和标签数据
%适用:仅适用于MNIST数据集,修改后可适用于其他
function output=decodefile(filename,type)
%数据介绍如下,参考网址http://yann.lecun.com/exdb/mnist/index.html
、fio=fopen(filename,\’r\’);%原始文件中数据是以2进制存储的。
a = fread(fio,\’uint8\’);%以8进制方式读取源文件。虽然前几项是32bit的,但是图像像素数据是8bit的,所以此处用8bit处理。
if strcmp(type,\’image\’)
output=a(17:end);%提取像素数据
else if strcmp(type,\’label\’)
output=a(9:end);
end
end
第二步:分类器分类
按照北京理工大学高琪老师等讲授的《人工智能之模式识别》,一般分类器的实现分为三个步骤:分类器模型的建立、模型的训练、以及模板分类结果的预测。分别利用templateSVM、 fitcecoc、predict函数实现功能。
补充:
关于交叉验证法,此处采用折十交叉验证法,对训练集数据再次进行划分,分为十份,每次留一份作为验证集,其余九份为训练集,十次循环训练模型。最后用训练后的模型再次对测试集数据进行验证。
完整程序如下所示:
% svm.m
clear variables
close all
clc
train_x_file=char(\’train-images.idx3-ubyte\’);%得到vector形式
test_x_file=char(\’t10k-images.idx3-ubyte\’);%得到vector形式
train_y_file=char(\’train-labels.idx1-ubyte\’);%得到vector形式
test_y_file=char(\’t10k-labels.idx1-ubyte\’);%得到vector形式
train_x=decodefile(train_x_file,\’image\’);
test_x=decodefile(test_x_file,\’image\’);
train_labels=decodefile(train_y_file,\’label\’);
test_labels=decodefile(test_y_file,\’label\’);
% 如果想检验转化是否正确,可执行以下代码。
train_images=reshape(train_x,28,28,60000);%reshape后的图像是放倒的
train_images=permute(train_images,[2 1 3]);%对每张图像进行行列的转置处理
test_images=reshape(test_x,28,28,10000);%reshape后的图像是放倒的
test_images=permute(test_images,[2 1 3]);%对每张图像进行行列的转置处理
train_labels=train_labels\’;
test_labels=test_labels\’;
%选取部分数据进行训练
train_num = 500;
test_num = 200;
data_train = mat2vector(train_images(:,:,1:train_num),train_num);%图像转向量
data_test = mat2vector(test_images(:,:,1:test_num),test_num);%mnist数据集图像为28*28
train_labels=train_labels(:,1:train_num)\’;
test_labels=test_labels(:,1:test_num)\’;
%定义SVM分类器模板,采用线性核函数, 这里选用最简单的线性模型做演示;
t = templateSVM(\’KernelFunction\’,\’linear\’);
%交叉验证法
[m,n] = size(data_train);
indices = crossvalind(\’Kfold\’, m, 10);
for i = 1 : 10
% 获取第i份测试数据的索引逻辑值
test = (indices == i);
% 取反,获取第i份训练数据的索引逻辑值
train = ~test;
%1份测试,9份训练
test_data = data_train(test,:);
test_label = train_labels(test,:);
train_data = data_train(train, :);
train_label = train_labels(train, :);
% 使用数据的代码
svm_model = fitcecoc(train_data,train_label,\’Learners\’,t);%训练模型,由于是多分类,不能直接调用fitcsvm
end
%不使用交叉验证法时训练模型
% svm_model = fitcecoc(data_train,train_labels(1:train_num),\’Learners\’,t);
%利用测试集数据测试结果
result = predict(svm_model,data_test);
result = result.\’;
fprintf(\’预测结果:\’);
result(1:20)%取20个打印出来对比
fprintf(\’真实分布:\’);
test_labels(1:20)\’
acc = 0.;
for i = 1:test_num
if result(i)==test_labels(i)
acc = acc+1;
end
end
fprintf(\’精确度为:%5.2f%%\n\’,(acc/test_num)*100);
% mat2vector.m
% 输入:图片数据(矩阵),样本个数
% 函数作用:将图片组转化为行向量的组合,每个行向量作为一张图片的特征
% 输出:样本数*图片像素数量大小的矩阵
function [data_]= mat2vector(data,num)
[row,col,~] = size(data);
data_ = zeros(num,row*col);
for page = 1:num
for rows = 1:row
for cols = 1:col
data_(page,((rows-1)*col+cols)) = im2double(data(rows,cols,page));
end
end
end
end
未使用交叉验证法时:
使用交叉验证法时: