手寫數字識別問題(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')

通過證明,發現兩種方法基本正確,無任何問題。
完成√

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