小白也能懂的手寫體識別


手寫體識別與Tensorflow

如同所有語言的hello world一樣,手寫體識別就相當於深度學習里的hello world。

TensorFlow是當前最流行的機器學習框架,有了它,開發人工智能程序就像Java編程一樣簡單。

MNIST

MNIST 數據集已經是一個被”嚼爛”了的數據集, 很多教程都會對它”下手”, 幾乎成為一個 “典范”. 不過有些人可能對它還不是很了解, 下面來介紹一下.

MNIST 數據集可在 http://yann.lecun.com/exdb/mnist/ 獲取, 它包含了四個部分:

   Training set images: train-images-idx3-ubyte.gz (9.9 MB, 解壓后 47 MB, 包含 60,000 個樣本) 
       Training set labels: train-labels-idx1-ubyte.gz (29 KB, 解壓后 60 KB, 包含 60,000 個標簽)
        Test set images: t10k-images-idx3-ubyte.gz (1.6 MB, 解壓后 7.8 MB, 包含 10,000 個樣本)
        Test set labels: t10k-labels-idx1-ubyte.gz (5KB, 解壓后 10 KB, 包含 10,000 個標簽)

MNIST 數據集來自美國國家標准與技術研究所, National Institute of Standards and Technology (NIST). 訓練集 (training set) 由來自 250 個不同人手寫的數字構成, 其中 50% 是高中學生, 50% 來自人口普查局 (the Census Bureau) 的工作人員. 測試集(test set) 也是同樣比例的手寫數字數據.

tensorflow提供一個input_data.py文件,專門用於下載mnist數據,我們直接調用就可以了,代碼如下:

import tensorflow.examples.tutorials.mnist.input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)

執行完成后,會在當前目錄下新建一個文件夾MNIST_data

input_data文件會調用一個maybe_download函數,確保數據下載成功。這個函數還會判斷數據是否已經下載,如果已經下載好了,就不再重復下載。

思路

把圖片當成一枚枚像素來看,下圖為手寫體數字1的圖片,它在計算機中的存儲其實是一個二維矩陣,每個元素都是0~1之間的數字,0代表白色,1代表黑色,小數代表某種程度的灰色。

image

現在,對於MNIST數據集中的圖片來說,我們只要把它當成長度為784的向量就可以了(忽略它的二維結構,28×28=784)。我們的任務就是讓這個向量經過一個函數后輸出一個類別。就是下邊這個函數,稱為Softmax分類器。

image

這個式子里的圖片向量的長度只有3,用x表示。乘上一個系數矩陣W,再加上一個列向量b,然后輸入softmax函數,輸出就是分類結果y。W是一個權重矩陣,W的每一行與整個圖片像素相乘的結果是一個分數score,分數越高表示圖片越接近該行代表的類別。因此,W x + b 的結果其實是一個列向量,每一行代表圖片屬於該類的評分。通常分類的結果並非評分,而是概率,表示有多大的概率屬於此類別。因此,Softmax函數的作用就是把評分轉換成概率,並使總的概率為1。

CNN

卷積神經網絡(Convolutional Neural Networks / CNNs / ConvNets)與普通神經網絡非常相似,它們都由具有可學習的權重和偏置常量(biases)的神經元組成。每個神經元都接收一些輸入,並做一些點積計算,輸出是每個分類的分數,普通神經網絡里的一些計算技巧到這里依舊適用。

卷積神經網絡利用輸入是圖片的特點,把神經元設計成三個維度 : width, height, depth(注意這個depth不是神經網絡的深度,而是用來描述神經元的) 。比如輸入的圖片大小是 32 × 32 × 3 (rgb),那么輸入神經元就也具有 32×32×3 的維度。下面是圖解:

這里寫圖片描述

一個卷積神經網絡由很多層組成,它們的輸入是三維的,輸出也是三維的,有的層有參數,有的層不需要參數。

卷積神經網絡通常包含以下幾種層:  

數據輸入層:

該層要做的處理主要是對原始圖像數據進行預處理,其中包括:
• 去均值:把輸入數據各個維度都中心化為0,如下圖所示,其目的就是把樣本的中心拉回到坐標系原點上。
• 歸一化:幅度歸一化到同樣的范圍,如下所示,即減少各維度數據取值范圍的差異而帶來的干擾,比如,我們有兩個維度的特征A和B,A范圍是0到10,而B范圍是0到10000,如果直接使用這兩個特征是有問題的,好的做法就是歸一化,即A和B的數據都變為0到1的范圍。
• PCA/白化:用PCA降維;白化是對數據各個特征軸上的幅度歸一化

卷積層

卷積神經網路中每層卷積層由若干卷積單元組成,每個卷積單元的參數都是通過反向傳播算法優化得到的。卷積運算的目的是提取輸入的不同特征,第一層卷積層可能只能提取一些低級的特征如邊緣、線條和角等層級,更多層的網絡能從低級特征中迭代提取更復雜的特征。 

下面的動態圖形象地展示了卷積層的計算過程:


    線性整流層(Rectified Linear Units layer, ReLU layer),這一層神經的活性化函數(Activation function)使用線性整流(Rectified Linear Units, ReLU)f(x)=max(0,x)

把卷積層輸出結果做非線性映射。


     池化層(Pooling layer),通常在卷積層之后會得到維度很大的特征,將特征切成幾個區域,取其最大值或平均值,得到新的、維度較小的特征。

池化層的具體作用。

1.特征不變性,也就是我們在圖像處理中經常提到的特征的尺度不變性,池化操作就是圖像的resize,平時一張狗的圖像被縮小了一倍我們還能認出這是一張狗的照片,這說明這張圖像中仍保留着狗最重要的特征,我們一看就能判斷圖像中畫的是一只狗,圖像壓縮時去掉的信息只是一些無關緊要的信息,而留下的信息則是具有尺度不變性的特征,是最能表達圖像的特征。

2.特征降維,我們知道一幅圖像含有的信息是很大的,特征也很多,但是有些信息對於我們做圖像任務時沒有太多用途或者有重復,我們可以把這類冗余信息去除,把最重要的特征抽取出來,這也是池化操作的一大作用。

3.在一定程度上防止過擬合,更方便優化。


    池化層用的方法有Max pooling 和 average pooling,而實際用的較多的是Max pooling。
     全連接層( Fully-Connected layer), 把所有局部特征結合變成全局特征,用來計算最后每一類的得分。

CNN的常用框架

Caffe
• 源於Berkeley的主流CV工具包,支持C++,python,matlab
• Model Zoo中有大量預訓練好的模型供使用
    Torch
• Facebook用的卷積神經網絡工具包
• 通過時域卷積的本地接口,使用非常直觀
• 定義新網絡層簡單
    TensorFlow
• Google的深度學習框架
• TensorBoard可視化很方便
• 數據和模型並行化好,速度快

實現代碼

代碼如下:

# -*- coding: utf-8 -*-
"""
Spyder Editor

This is a temporary script file.
"""
# -*- coding:utf-8 -*-  
import tensorflow as tf  
from tensorflow.examples.tutorials.mnist import input_data  
#number from 0 to 9:  
mnist=input_data.read_data_sets('MNIST_data/',one_hot=True)  
  
def add_layer(inputs,in_size,out_size,activation_function=None):  
    Weights=tf.Variable(tf.random_normal([in_size,out_size]))  
    bises=tf.Variable(tf.zeros([1,out_size])+0.1)  
    Wx_plus_b=tf.matmul(inputs,Weights)+bises  
  
    if activation_function is None:  
        outputs=Wx_plus_b  
    else:  
        outputs=activation_function(Wx_plus_b)  
  
    return outputs  
  
#計算准確度  
def compute_accuracy(x,y):  
    global prediction  
    y_pre=sess.run(prediction,feed_dict={xs:x})  
    correct_prediction=tf.equal(tf.argmax(y_pre,1),tf.argmax(y,1))  
    accuracy=tf.reduce_mean(tf.cast(correct_prediction,tf.float32))  
    result=sess.run(accuracy,feed_dict={xs:x,ys:y})  
    return result  
  
#def placeholder for inputs  
xs=tf.placeholder(tf.float32,[None,784])  #28*28  
ys=tf.placeholder(tf.float32,[None,10])  #10個輸出  
  
#add output layer  
prediction=add_layer(xs,784,10,tf.nn.softmax)  #softmax常用於分類  
  
cross_entropy=tf.reduce_mean(-tf.reduce_sum(ys*tf.log(prediction),reduction_indices=[1]))  
train=tf.train.GradientDescentOptimizer(0.3).minimize(cross_entropy)  
  
sess=tf.Session()  
sess.run(tf.initialize_all_variables())  
  
for i in range(2000):  
    batch_xs,batch_ys=mnist.train.next_batch(100)  
    sess.run(train,feed_dict={xs:batch_xs,ys:batch_ys})  
    if i%100==0:  
        print(compute_accuracy(mnist.test.images,mnist.test.labels))

執行看輸出,准確度為:

Extracting MNIST_data/train-images-idx3-ubyte.gz
Extracting MNIST_data/train-labels-idx1-ubyte.gz
Extracting MNIST_data/t10k-images-idx3-ubyte.gz
Extracting MNIST_data/t10k-labels-idx1-ubyte.gz
0.1007
0.6668
0.7603
0.7946
0.8198
0.8324
0.8416
0.8473
0.8544
0.8565
0.8634
0.8661
0.8654
0.8692
0.8725
0.8727
0.8748
0.8753
0.8771
0.8781

准確率為87%。

總結

上面的例子使用的是TensorFlow提供的數據集,我們可以自己手寫一個數字,然后通過opencv對數字進行剪裁,然后輸入模型看識別的結果。

深度學習和nlp的可以加微信群交流,目前,我們正在參加nlp方面的比賽。

webwxgetmsgimg


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM