手写数字识别问题(1)——关于MNIST数据集

1.MNIST数据集介绍

MNIST数据集是机器学习领域非常经典的一个数据集。MNIST数据集来自美国国家标准与技术研所,National Institute of Standard and Technology(NIST)。训练集(training set)由来自250个不同人手写的数字构成,其中50%是高中学生,50%来自人口普查局的工作人员。测试集(test set)也是同样比例的手写数字数据。它有60000个训练样本集和10000个测试样本集,可以被用来训练和测试关于手写数字识别的模型。
地址:http://yann.lecun.com/exdb/mnist/
MNIST数据集中所有的图片都是28*28像素的灰度手写数字图片,每张图片都是一个数字。

2.mnist手写体的未处理原始格式

它包含四个部分:
- train-images-idx3-ubyte.gz:训练集图像(9912422字节)
训练集图像,共60000张图像
- train-labels-idx1-ubyte.gz:训练集标签(28881 字节)
训练标签集
- t10k-images-idx3-ubyte.gz:测试集图像(1648877字节)
测试集图像,共10000张图像
- t10k-labels-idx1-ubyte.gz:测试集标签(4542字节)
测试标签集

下载完成后解压如图:
在这里插入图片描述
注:但是这些个文件怎么用呢,参照网站上的说明,他们都是二进制文件,格式分别如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
idx3代表数据是三维数据,ubyte代表数据储存格式为二进制格式。

2.mnist数据集的理解

MNIST 数据集中含有数字0-9的训练数据集和数字0-9测试数据集两种图片,每张图片都是灰度图,位深度为8。
首先该数据是以二进制存储的,我们读取的时候要以’rb’方式读取,其次,真正的数据只有[value]这一项,其他的[type]等只是来描述的,并不真正在数据文件里面,这样写只是在向我们解释文件的结构。

3.利用MATLAB将MNIST数据集转换为.bmp图片和txt文档

train_image代码如下:

clear all;
clc;
%读取训练图片数据文件
[FileName,PathName] = uigetfile('*.*','选择训练图片数据文件train-images.idx3-ubyte');
TrainFile = fullfile(PathName,FileName);
fid = fopen(TrainFile,'r');
a = fread(fid,16,'uint8');
MagicNum = ((a(1)*256+a(2))*256+a(3))*256+a(4);
ImageNum = ((a(5)*256+a(6))*256+a(7))*256+a(8);
ImageRow = ((a(9)*256+a(10))*256+a(11))*256+a(12);
ImageCol = ((a(13)*256+a(14))*256+a(15))*256+a(16);
if ((MagicNum~=2051)||(ImageNum~=60000))
    error('不是 MNIST train-images.idx3-ubyte 文件!');
    fclose(fid);    
    return;    
end
savedirectory = uigetdir('','选择保存训练图片路径:');
h_w = waitbar(0,'请稍候,处理中>>');
for i=1:ImageNum
    b = fread(fid,ImageRow*ImageCol,'uint8');   
    c = reshape(b,[ImageRow ImageCol]);
    d = c';
    e = 255-d;
    e = uint8(e);
    savepath = fullfile(savedirectory,['TrainImage_' num2str(i,'%05d') '.bmp']);
    imwrite(e,savepath,'bmp');
    waitbar(i/ImageNum);
end
fclose(fid);
close(h_w);
disp(['保存完毕']);

重点解释一下:

a = fread(fid,16,'uint8');
MagicNum = ((a(1)*256+a(2))*256+a(3))*256+a(4);
ImageNum = ((a(5)*256+a(6))*256+a(7))*256+a(8);
ImageRow = ((a(9)*256+a(10))*256+a(11))*256+a(12);
ImageCol = ((a(13)*256+a(14))*256+a(15))*256+a(16);

这里,由于matlab只能读取8位无符号数,而MNIST中存储的是32位无符号数,因此调用fread读取后出来的是16个8位无符号数,×256表示将4个8位无符号数转成1个32位无符号数。
在这里插入图片描述

如有需要,可以下载:https://download.csdn.net/download/didi_ya/12267896

4.拓展:利用python将MNIST数据集转换为.bmp图片和txt文档

train_image代码如下:

# -*- coding: utf-8 -*-
import struct
import numpy as np
import  matplotlib.pyplot as plt
from PIL import Image
#二进制的形式读入
filename='E:/My Graduation project/mnist/train-images.idx3-ubyte'
binfile=open(filename,'rb')
buf=binfile.read()

index=0
magic,numImages,numRows,numColumns=struct.unpack_from('>IIII',buf,index)
index+=struct.calcsize('>IIII')
#将每张图片按照格式存储到对应位置
for image in range(0,numImages):
    im=struct.unpack_from('>784B',buf,index)
    index+=struct.calcsize('>784B')
   #这里注意 Image对象的dtype是uint8,需要转换
    im=np.array(im,dtype='uint8')
    im=im.reshape(28,28)
    im=Image.fromarray(im)
    im.save('E:/My Graduation project/mnist/trainIMG/train_%s.bmp'%image,'bmp')#保存

有的时候需要用python处理二进制数据,比如存取文件等。这时候,可以使用python的struct模块来完成。也可以用 struct来处理c语言中的结构体。

struct模块中最重要的三个函数是pack(), unpack(), calcsize():
struct.pack(fmt,v1,v2,…):将v1,v2等参数的值进行一层包装,包装的方法由fmt指定。被包装的参数必须严格符合fmt。最后返回一个包装后的字符串。
struct.unpack(fmt,string):解包。返回一个由解包数据(string)得到的一个元组(tuple), 即使仅有一个数据也会被解包成元组。其中len(string) 必须等于 calcsize(fmt),这里面涉及到了一个calcsize函数。
calcsize(fmt) :计算给定的格式(fmt)占用多少字节的内存

如有需要,可以下载:https://download.csdn.net/download/didi_ya/12268945

5.将MNIST数据集转化为.mat格式文件

%% I.清空环境变量
close all;
clear all;
clc;
% 训练与测试文件名
TrainImagesName='train-images.idx3-ubyte';
TrainLabelsName='train-labels.idx1-ubyte';
TestImagesName='t10k-images.idx3-ubyte';
TestLabelsName='t10k-labels.idx1-ubyte';
%读取训练图片数据文件
PathName = 'E:\My Graduation project\mnist';
TrainImagesFile = fullfile(PathName, TrainImagesName);
TrainLabelsFile = fullfile(PathName, TrainLabelsName);
TestImagesFile = fullfile(PathName, TestImagesName);
TestLabelsFile = fullfile(PathName, TestLabelsName);

%% II.处理训练图片
fid = fopen(TrainImagesFile,'r'); 
a = fread(fid,16,'uint8'); 
%MagicNum = ((a(1)*256+a(2))*256+a(3))*256+a(4);
ImageNum = ((a(5)*256+a(6))*256+a(7))*256+a(8);
ImageRow = ((a(9)*256+a(10))*256+a(11))*256+a(12);
ImageCol = ((a(13)*256+a(14))*256+a(15))*256+a(16);
trainImages=zeros(ImageRow,ImageCol,ImageNum,'uint8');
for i=1:ImageNum
    b = fread(fid,ImageRow*ImageCol,'uint8');   
    c = reshape(b,[ImageRow ImageCol]); 
    trainImages(:,:,i)=uint8(c');
    disp(['正在处理训练图片,处理进度 (' , num2str(i) , '/' , num2str(ImageNum) ,')']);
end
fclose(fid);

%% III.处理测试图片
fid = fopen(TestImagesFile,'r'); 
a = fread(fid,16,'uint8'); 
%MagicNum = ((a(1)*256+a(2))*256+a(3))*256+a(4);
ImageNum = ((a(5)*256+a(6))*256+a(7))*256+a(8);
ImageRow = ((a(9)*256+a(10))*256+a(11))*256+a(12);
ImageCol = ((a(13)*256+a(14))*256+a(15))*256+a(16);
testImages=zeros(ImageRow,ImageCol,ImageNum,'uint8');
for i=1:ImageNum
    b = fread(fid,ImageRow*ImageCol,'uint8');   
    c = reshape(b,[ImageRow ImageCol]); 
    testImages(:,:,i)=uint8(c');
    disp(['正在处理测试图片,处理进度 (' , num2str(i) , '/' , num2str(ImageNum) ,')']);
end
fclose(fid);

%% IV.处理训练标签
fid = fopen(TrainLabelsFile,'r'); 
a = fread(fid,8,'uint8'); 
%MagicNum = ((a(1)*256+a(2))*256+a(3))*256+a(4);
ImageNum = ((a(5)*256+a(6))*256+a(7))*256+a(8);
%trainLabels=zeros(ImageNum,1);
b = fread(fid,ImageNum,'uint8');   
trainLabels=uint8(b);
disp('训练标签处理完成');
fclose(fid);

%% V.处理测试标签
fid = fopen(TestLabelsFile,'r'); 
a = fread(fid,8,'uint8'); 
%MagicNum = ((a(1)*256+a(2))*256+a(3))*256+a(4);
ImageNum = ((a(5)*256+a(6))*256+a(7))*256+a(8);
%testLabels=zeros(ImageNum,1);
b = fread(fid,ImageNum,'uint8');
testLabels=uint8(b);
disp('测试标签处理完成' );
fclose(fid);
% 保存提取的数据
save('mnist.mat','trainImages','trainLabels','testImages','testLabels')

通过证明,发现两种方法基本正确,无任何问题。
完成√

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章