1. 程式人生 > >基於tensorflow的MNIST手寫數字識別(二)--入門篇

基於tensorflow的MNIST手寫數字識別(二)--入門篇

一、本文的意義

      因為谷歌官方其實已經寫了MNIST入門和深入兩篇教程了,那我寫這些文章又是為什麼呢,只是抄襲?那倒並不是,更準確的說應該是筆記吧,然後用更通俗的語言來解釋,並且補充更多,官方文章中沒有詳細展開的一些知識點,不過建議與官方文章結合著閱讀。        另外是程式碼部分的改動,官方的demo只提供了驗證精確度,我將它改造成了能輸入並預測輸出結果的程式碼也就是說是一個從準備待測圖片到最終是別的一個完整demo  中文版本:MNIST機器學習入門 http://wiki.jikexueyuan.com/project/tensorflow-zh/tutorials/mnist_beginners.html
需要識別的圖片放到test_num裡,然後執行mnist_softmax.py就好了
demo截圖如下,會將放進去的圖片預測,然後輸出結果,程式碼說明請看github的readme(最底下)


二、MNIST簡介

<span style="font-family:Microsoft YaHei;">官網:http://yann.lecun.com/exdb/mnist/</span>

這個MNIST資料庫是一個手寫數字的資料庫,它提供了六萬的訓練集和一萬的測試集。
它的圖片是被規範處理過的,是一張被放在中間部位的28px*28px的灰度圖

總共4個檔案:

train-images-idx3-ubyte: training set images

 
train-labels-idx1-ubyte: training set labels 
t10k-images-idx3-ubyte:  test set images 
t10k-labels-idx1-ubyte:  test set labels

圖片都被轉成二進位制放到了檔案裡面, 所以,每一個檔案頭部幾個位元組都記錄著這些圖片的資訊,然後才是儲存的圖片資訊

TRAINING SET LABEL FILE (train-labels-idx1-ubyte):

[offset] [type]          [value]          [description]
0000     32 bit integer  0x00000801(2049) magic number (MSB first)

0004     32 bit integer  60000            number of items
0008     unsigned byte   ??               label
0009     unsigned byte   ??               label
........
xxxx     unsigned byte   ??               label

The labels values are 0 to 9.

TRAINING SET IMAGE FILE (train-images-idx3-ubyte):

[offset] [type]          [value]          [description]
0000     32 bit integer  0x00000803(2051) magic number
0004     32 bit integer  60000            number of images
0008     32 bit integer  28               number of rows
0012     32 bit integer  28               number of columns
0016     unsigned byte   ??               pixel
0017     unsigned byte   ??               pixel
........
xxxx     unsigned byte   ??               pixel

每個畫素被轉成了0-255,0代表著白色,255代表著黑色。

TEST SET LABEL FILE (t10k-labels-idx1-ubyte):

[offset] [type]          [value]          [description]
0000     32 bit integer  0x00000801(2049) magic number (MSB first)
0004     32 bit integer  10000            number of items
0008     unsigned byte   ??               label
0009     unsigned byte   ??               label
........
xxxx     unsigned byte   ??               label

The labels values are 0 to 9.

TEST SET IMAGE FILE (t10k-images-idx3-ubyte):

[offset] [type]          [value]          [description]
0000     32 bit integer  0x00000803(2051) magic number
0004     32 bit integer  10000            number of images
0008     32 bit integer  28               number of rows
0012     32 bit integer  28               number of columns
0016     unsigned byte   ??               pixel
0017     unsigned byte   ??               pixel
........
xxxx     unsigned byte   ??               pixel

每個畫素被轉成了0-255,0代表著白色,255代表著黑色。

三、tensorflow手寫數字識別的大致步驟

1、將要識別的圖片轉為灰度圖,並且轉化為28*28矩陣(單通道,每個畫素範圍0-255,0為黑色,255為白色,這一點與MNIST中的正好相反) 2、將28*28的矩陣轉換成1維矩陣(也就是把第2,3,4,5....行矩陣紛紛接入到第一行的後面) 3、用一個1*10的向量代表標籤,也就是這個數字到底是幾,舉個例子e數字1對應的矩陣就是[0,1,0,0,0,0,0,0,0,0] 4、softmax迴歸預測圖片是哪個數字的概率 5、用交叉熵和梯度下降法訓練引數

四、過程講解

4.1 準備要識別的圖片

這個部分其實是比較重要的,因為如果處理不得當可能並不一定會有很好的結果,所以按照mnist的標準規範需要將待測圖片轉為28×28且文字居中的灰度圖(其實彩色的也可以,不過就是最後程式碼需要改一下),目前介紹兩種獲得待測圖片的方法: 1、自己用ps或者真的手寫一些數字 2、將MNIST資料庫中的二進位制轉化成圖片,然後用來做測試

4.2 將待測圖片轉換為矩陣

     如圖所示,根據黑色部分的濃淡將其轉化成微一個浮點數的陣列,(白色0,黑色1)            看到這裡,如果你跟我一樣不熟悉python,是不是開始方了,沒事,其實python很厲害,自帶的PIL圖片庫一句話就可以搞定
<span style="font-family:Microsoft YaHei;">img=array(Image.open(filename))         //開啟然後就被numpy轉化了</span>
如果是彩色的圖片,則需要先將它這樣子轉換一下(我當初並不知道可以轉化,傻不垃圾地自己寫了一個轉化,所以python還是好好學習啊)
<span style="font-family:Microsoft YaHei;"> im=Image.open("test_num3/8_3.png")
Lim  = img=array(im.convert("L")) </span>

4.3將矩陣轉化為一維矩陣,以及標籤的介紹

轉化為一維的矩陣其實並不難,用python的reshape就能搞定,還是要講一下標籤的表示方法,這個曾經令隊友疑惑不久,直到我把這個陣列打印出來

4.3.1標籤的來歷--有監督學習 和 無監督學習

 監督學習:利用一組已知類別的樣本調整分類器的引數,使其達到所要求效能的過程,也稱為監督訓練或有教師學習
  舉個例子,MNIST自帶了訓練圖片和訓練標籤,每張圖片都有一個對應的標籤,比如這張圖片是1,標籤也就是1,用他們訓練程式,之後程式也就能識別測試集中的圖片了,比如給定一張2的圖片,它能預測出他是2 無監督學習:其中很重要的一類叫聚類
  舉個例子,如果MNIST中只有訓練圖片,沒有標籤,我們的程式能夠根據圖片的不同特徵,將他們分類,但是並不知道他們具體是幾,這個其實就是“聚類”

4.3.2 標籤的表示

在這裡標籤的表示方式有些特殊,它也是使用了一個一維陣列,而不是單純的數字,上面也說了,他是一個一位陣列,0表示方法[1,0,0,0,0,0,0,0,0,0],1表示[0,1,0,0,0,0,0,0,0,0],........., 主要原因其實是這樣的,因為softmax迴歸處理後會生成一個1*10的陣列,陣列[0,0]的數字表示預測的這張圖片是0的概率,[0,1]則表示這張圖片表示是1的概率......以此類推,這個陣列表示的就是這張圖片是哪個數字的概率(已經歸一化),因此,實際上,概率最大的那個數字就是我們所預測的值。兩者對應來看,標準的標籤就是表示圖片對應數字的概率為100%,而表示其它數字的概率為0,舉個例子,0表示[1,0,0,0,0,0,0,0,0,0],可以理解為它表示0的概率為1,而表示別的數字的概率為0.

4.4 softmax迴歸

    這是一個分類器,可以認為是Logistic迴歸的擴充套件,Logistic大家應該都聽說過,就是生物學上的S型曲線,它只能分兩類,用0和1表示,這個用來表示答題對錯之類只有兩種狀態的問題時足夠了,但是像這裡的MNIST要把它分成10類,就必須用softmax來進行分類了。       P(y=0)=p0,P(y=1)=p1,p(y=2)=p2......P(y=9)=p9.這些表示預測為數字i的概率,(跟上面標籤的格式正好對應起來了),它們的和為1,即 ∑(pi)=1。     tensorflow實現了這個函式,我們直接呼叫這個softmax函式即可,對於原理,可以參考下面的引文,這裡只說一下我們這個MNIST demo要用softmax做什麼。   (注:每一個神經元都可以接收來自網路中其他神經元的一個或多個輸入訊號,神經元與神經元之間都對應著連線權值,所有的輸入加權和決定該神經元是處於啟用還是抑制狀態。感知器網路的輸出只能取值0或1,不具備可導性。而基於敏感度的訓練演算法要求其輸出函式必須處處可導,於是引入了常見的S型可導函式,即在每個神經元的輸出之前先經過S型啟用函式的處理。)

4.5 交叉熵

通俗一點就是,方差大家都知道吧,用它可以衡量預測值和實際值的相差程度,交叉熵其實也是一樣的作用,那為什麼不用方差呢,因為看sigmoid函式的影象就會發現,它的兩側幾乎就是平的,導致它的方差在大部分情況下很小,這樣在訓練引數的時候收斂地就會很慢,交叉熵就是用來解決這個問題的,它的公式是 ,其中,y 是我們預測的概率分佈, y' 是實際的分佈。

4.6 梯度下降

      上面那步也說了,有個交叉熵,根據大夥對方差的理解,值越小,自然就越好,因此我們也要訓練使得交叉熵最小的引數,這裡梯度下降法就派上用場了,這個解釋見上一篇系列文章吧,什麼叫訓練引數呢,可以想象一下,我們先用實際的值在二位座標上畫一條線,然後我們希望我們預測出來的那些值要儘可能地貼近這條線,我們假設生成我們這條線的公式ax+ax^2+bx^3+.....,我們需要生成這些係數,要求得這些係數,我們就需要各種點代入,然後才能求出,所以其實訓練引數跟求引數是個類似的過程。


4.7 預測

      訓練結束以後我們就可以用這個模型去預測新的圖片了,就像我們已經求出來了方程,以後只要隨意輸入一個x,就能求出對應的y。

5 程式碼

https://github.com/wlmnzf/tensorflow-train/tree/master/mnist

6 參考文章

<span style="font-family:Microsoft YaHei;font-size:18px;">http://blog.csdn.net/acdreamers/article/details/44663305   softmax迴歸</span>
<span style="font-family:Microsoft YaHei;font-size:18px;">http://wiki.jikexueyuan.com/project/tensorflow-zh/tutorials/mnist_beginners.html    MNIST學習入門
</span>
<span style="font-family:Microsoft YaHei;font-size:18px;">http://blog.csdn.net/u012162613/article/details/44239919   交叉熵代價函式</span>