卷積神經網絡(cnn) 手寫數字識別
1. 知識點準備</h3>
1. 知識點準備</h3>
在了解 CNN 網絡神經之前有兩個概念要理解,第一是二維圖像上卷積的概念,第二是 pooling 的概念。
a. 卷積
關于卷積的概念和細節可以參考這里,卷積運算有兩個非常重要特性,以下面這個一維的卷積為例子:
第一個特性是稀疏連接。可以看到, layer m 上的每一個節點都只與 layer m-1 對應區域的三個節點相連接。這個局部范圍也叫感受野。第二個特性是相同顏色的線條代表了相同的權重,即權重共享。這樣做有什么好處呢?一方面權重共享可以 極大減小參數的數目,學習起來更加有效,另一方面,相同的權重可以讓過濾器不受圖像位置的影響來檢測圖像的特性,從而使 CNN 具有更強的泛化能力。
b. 池化
理論上,我們將圖像利用不同的過濾器通過卷積之后得到了多個卷積之后的圖像,然后直接利用這些圖像進行分類,但是這樣計算量太大了。利用池化操作可以將數據量減小,同時在一定程度上保留原有的圖像特征。關于 pooling, 概念更加簡單了,詳情可以參考這里。池化又可以分為平均池化和最大池化,這里我們將采用最大池化。注意到,池化的區域是不重疊的,卷積的感受野是重疊的。
2. 卷積神經網絡的搭建
下圖是手寫數字識別中采用的 lenet-5 簡單的卷積神經網絡模型:
- 原圖是 28 × 28 的手寫數字圖片,通過第一次 20 個 5 × 5 的卷積核之后,得到 20 張卷積圖片。卷積核的權重是取一定范圍內的隨機值,這樣,一張 28 × 28 的圖片就變為 20 張 (28-5+1)× (28-5+1)=24×24 的圖片了。
- 將 24×24 的圖片進行 2 × 2 的最大池化,得到 20 張 12 × 12 的圖片。該圖片的像素還需要進行 tanh 函數的變換才能作為下一個卷積層的輸入。
- 將 tanh 變化之后的 12 × 12 大小的圖片同樣進行 20 × 50 個 5 × 5 的卷積操作之后得到 50 張 (12-5+1)× (12-5+1) = 8 × 8 的圖片。
- 將 8×8 的圖片進行 2×2 的最大池化,得到 50 張 4×4 的圖片,再經過 tanh 函數進行歸一化處理,就可以作為 MLP 的 800 個輸入了。
- 余下來就是 MLP 的訓練工作了。
3. LR, MLP,CNN 識別代碼
已經訓練好的模型系數的下載地址1。
三種方法識別手寫數字的代碼:
import cPickle import numpy import theano import theano.tensor as T from theano.tensor.signal import downsample from theano.tensor.nnet import conv ######################################## # define the classifer constructs ######################################## class LogisticRegression(object): def __init__(self, input, W=None, b=None): if W is None: fle = open("../model_param/lr_sgd_best.pkl") W, b = cPickle.load(fle) fle.close() self.W = W self.b = b self.outputs = T.nnet.softmax(T.dot(input, self.W) + b) self.pred = T.argmax(self.outputs, axis=1) class MLP(object): def __init__(self, input, params=None): if params is None: fle = open("../model_param/mlp_best.pkl") params = cPickle.load(fle) fle.close() self.hidden_W, self.hidden_b, self.lr_W, self.lr_b = params self.hiddenlayer = T.tanh(T.dot(input, self.hidden_W) + self.hidden_b) self.outputs = T.nnet.softmax(T.dot(self.hiddenlayer, self.lr_W) \ + self.lr_b) self.pred = T.argmax(self.outputs, axis=1) class CNN(object): def __init__(self, input, params=None): if params is None: fle = open("../model_param/cnn_best.pkl") params = cPickle.load(fle) fle.close() ################ self.layer3_W, self.layer3_b, self.layer2_W, self.layer2_b, \ self.layer1_W, self.layer1_b, self.layer0_W, self.layer0_b = params # compute layer0 self.conv_out0 = conv.conv2d(input=input, filters=self.layer0_W) # filter_shape=(20, 1, 5, 5), image_shape=(1, 1, \ # 28, 28)) self.pooled_out0 = downsample.max_pool_2d(input=self.conv_out0, \ ds=(2, 2), ignore_border=True) self.layer0_output = T.tanh(self.pooled_out0 + \ self.layer0_b.dimshuffle('x', 0, 'x', 'x')) # compute layer1 self.conv_out1 = conv.conv2d(input=self.layer0_output, filters=self.layer1_W) # filter_shape=(50, 20, 5, 5), image_shape=(1, 20, \ # 12, 12)) self.pooled_out1 = downsample.max_pool_2d(input=self.conv_out1, \ ds=(2, 2), ignore_border=True) self.layer1_output = T.tanh(self.pooled_out1 + \ self.layer1_b.dimshuffle('x', 0, 'x', 'x')) # compute layer2 self.layer2_input = self.layer1_output.flatten(2) self.layer2_output = T.tanh(T.dot(self.layer2_input, self.layer2_W) + \ self.layer2_b) # compute layer3 self.outputs = T.nnet.softmax(T.dot(self.layer2_output, self.layer3_W)\ + self.layer3_b) self.pred = T.argmax(self.outputs, axis=1) ######################################## # build classifier ######################################## def lr(input): input.shape = 1, -1 x = T.fmatrix('x') classifer = LogisticRegression(input=x) get_p_y = theano.function(inputs=[x], outputs=classifer.outputs) pred_y = theano.function(inputs=[x], outputs=classifer.pred) return (get_p_y(input), pred_y(input)) def mlp(input): input.shape = 1, -1 x = T.fmatrix('x') classifer = MLP(input=x) get_p_y = theano.function(inputs=[x], outputs=classifer.outputs) pred_y = theano.function(inputs=[x], outputs=classifer.pred) return (get_p_y(input), pred_y(input)) def cnn(input): input.shape = (1, 1, 28, 28) x = T.dtensor4('x') classifer = CNN(input=x) get_p_y = theano.function(inputs=[x], outputs=classifer.outputs) pred_y = theano.function(inputs=[x], outputs=classifer.pred) return (get_p_y(input), pred_y(input))
本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!