TensorFlow基于minist数据集实现手写字识别实战的三个模型
手寫字識別
- model1:輸入層→全連接→輸出層softmax
- model2:輸入層→全連接→隱含層→全連接→輸出層softmax
- model3:輸入層→卷積層1→卷積層2→全連接→dropout層→全連接→輸出層softmax
model1:輸入層→全連接→輸出層softmax
model2:輸入層→全連接→隱含層→全連接→輸出層softmax
"""作者:Heart Sea功能:tessorflow實現多層感知機/多層神經網絡 Multi-Layer Perceptron, MLP加入:減輕過擬合的Dropout, 自適應學習速率的Adagrad, 可解決梯度彌散的激活函數ReLUModel:1個輸入層全連接1個隱含層, 激活ReLU, Dropout全連接1個輸出層, softmax版本:2.0日期:10/10/2019 """# 載入tensorflow加載數據集mnist from tensorflow.examples.tutorials.mnist import input_data import tensorflow as tf mnist = input_data.read_data_sets("MNIST_data/", one_hot=True) # 創建默認的InteractiveSession,后面各項操作無須指定session了 sess = tf.InteractiveSession()in_units = 784 # 輸入層節點數 h1_units = 300 # 隱含層節點數# W1,b1為隱含層的權重和偏置 # W2,b2為輸出層的權重和偏置,全部置為0,因為對于sigmoid,在0處最敏感,梯度最大 # 初始化參數W1為截斷的正態分布,標準差為0.1 # 由于使用ReLU,需要使用正態分布給參數加噪聲,來打破完全對稱并且避免0梯度 # 在其他的一些模型中,還需要給偏置賦值小的非零值來避免死亡神經元 W1 = tf.Variable(tf.truncated_normal([in_units, h1_units], stddev=0.1)) b1 = tf.Variable(tf.zeros([h1_units])) W2 = tf.Variable(tf.zeros([h1_units, 10])) b2 = tf.Variable(tf.zeros([10]))# 定義輸入x的placeholder,由于Dropout的比率keep_prob在測試和訓練時不一樣,訓練時小于1,預測時大于1 # keep_prob訓練時小于1,用以制造隨機性,防止過擬合;預測時大于1,即使用全部特征來預測樣本的類別 # 所以也把Dropout的比率keep_prob作為計算圖的輸入,并定義成一個placeholder x = tf.placeholder(tf.float32, [None, in_units]) keep_prob = tf.placeholder(tf.float32) # 保留節點的概率(保留數據而不置0的比例)# 建立隱藏層和輸出層,并且調用Dropout函數處理隱含層輸出數據 # ReLU的優點:單側抑制,相對寬闊的興奮邊界,稀疏激活性 # 隱含層的激活函數用ReLU可以提高訓練速度和模型準確率 hidden1 = tf.nn.relu(tf.matmul(x, W1) + b1) # 隱含層激活函數為ReLU hidden1_drop = tf.nn.dropout(hidden1, keep_prob) # 實現Dropout的功能,即隨機將一部分節點置為0 y = tf.nn.softmax(tf.matmul(hidden1_drop, W2) + b2) # 輸出層,shape和y_一樣,[None, 10]# 定義損失函數cross_entropy,并指定自適應優化器Adagrad優化損失函數 # y_和y是相同的維度[None, 10],兩者相乘,實質求內積,求和按照[1]列求和(一個樣本的所有類別求和),求和后為一維向量,平均后為1個數 y_ = tf.placeholder(tf.float32, [None, 10]) cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y), reduction_indices=[1])) train_step = tf.train.AdagradOptimizer(0.3).minimize(cross_entropy)tf.global_variables_initializer().run()# 由于加入隱含層,需要更多的訓練迭代來優化模型參數達到一個比較好的效果 # 進行訓練3000個batch,每個batch有100個樣本,一共30萬的樣本,相當于對全數據進行5輪迭代 for i in range(3000):batch_xs, batch_ys = mnist.train.next_batch(100)train_step.run({x: batch_xs, y_: batch_ys, keep_prob: 0.75})# 對模型進行準確性評測,其中加入了keep_prob=1 # tf.cast是將correct_prediction輸出的bool值轉換為float32 correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1)) accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32)) print(accuracy.eval({x: mnist.test.images, y_: mnist.test.labels, keep_prob: 1.0})) # 0.9778最終我們再測試集上可以達到98%的準確率,相比于Softmax,我們的誤差由8%降到了2%。
多層神經網絡依靠隱藏層,可以組合出高階特征,比如橫線、豎線、圓圈等,之后可以將這個高階特征再組合成數字,實現精確的匹配和分類。隱藏層輸出的高階特征經常是可以復用的,所以每一類的判別、概率輸出都共享這些高階特征,而不是各自連接獨立的高階特征。
我們也可以發現,新增一個隱藏層,并使用了Dropout、Adagrad和ReLU,而代碼并沒有增加很多,這就是TensorFlow的優勢。它的代碼非常簡潔,沒有太多冗余,可以方便的將有用的模塊拼裝在一起。
當然使用全連接的深度神經網絡也是有局限的,即使我們使用很深的網絡、很多隱藏節點、進行很多次迭代,也很難在MNIST數據集上獲得99%以上的準確率。這時就該卷積神經網絡(CNN)出場了。
model3:輸入層→卷積層1→卷積層2→全連接→dropout層→全連接→輸出層softmax
卷積神經網絡CNN
特點:
- 卷積的權值共享結構,可以大幅減少神經網絡的參數量,防止過擬合的同時又降低了神經網絡的復雜度。
- CNN訓練的模型對縮放,平移,旋轉等畸變具有不變性,泛化性強。
- 降低圖像預處理的要求,避免復雜的特征工程
- 首個可進行多層訓練的網絡結構(全連接不行,因為有參數過多,梯度彌散問題)
CNN一般由多個卷積層構成,卷積層操作:
- 圖像通過多個不同的卷積核的濾波,并加偏置(bias),提取局部特征,每個卷積核會映射出一個新的2D圖像。
- 將卷積核的輸出結果,進行非線性的激活函數(ReLU最常用)處理。
- 對激活函數的結果再進行池化操作,即降采樣,一般采用最大池化方法,保留最顯著的特征,并提升模型的畸變容錯能力。
權值共享解釋:
- 一個卷積核對應一個新圖像,新圖像的每個像素來自相同的卷積核,這就是權值共享
- 參數量只和卷積核大小有無,與多少隱含節點和圖片有多大無關。
CNN要點:
局部連接,權值共享,池化層的降采樣(賦予模型輕度形變的容忍性,提高了模型泛化能力)
代碼: 兩個卷積層加一個全連接層構建一個簡單但非常有代表性的卷積神經網絡。
"""作者:Heart Sea功能:基于minist, CNN實現識別手寫數字Model:輸入層, 1D轉換2D卷積層, 卷積, 激活relu, 最大池化卷積層, 卷積, 激活relu, 最大池化全連接, 2D轉換1D, 激活relu隱藏層(Dropout層)全連接, softmax輸出層版本:3.0日期:10/11/2019 """from tensorflow.examples.tutorials.mnist import input_data import tensorflow as tf mnist = input_data.read_data_sets("MNIST_data/", one_hot=True) sess = tf.InteractiveSession()# 由于使用ReLU # 需要使用正態分布給參數加噪聲(這里加入截斷的正態分布噪聲),來打破完全對稱并且避免0梯度 # 還需要給偏置賦值小的非零值來避免死亡神經元 def weight_variable(shape):initial = tf.truncated_normal(shape, stddev=0.1)return tf.Variable(initial)def bias_variable(shape):initial = tf.constant(0.1, shape=shape)return tf.Variable(initial)# 定義卷積層函數,strides代表卷積模板移動的步長,都是1表示劃過圖片每一個點 # padding表示邊界處理方式,SAME讓卷積的輸入和輸出保持同樣的尺寸 # x是輸入,w卷積的參數 def conv2d(x, W):return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')# 定義最大池化函數,ksize參數是濾波器大小,表示2*2的濾波器, # strides設為橫豎兩個方向以2為步長,步長如果為1,得到一個尺寸不變的圖片 def max_pool_2x2(x):return tf.nn.max_pool(x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')# CNN會利用到空間的結構信息,需要將1D轉換成2D # 利用tf.reshape函數對輸入的一維向量還原為28x28的結構,-1代表樣本數量不固定,最后1代表顏色通道數量 # x特征,y_真實的label x = tf.placeholder(tf.float32, [None, 784]) y_ = tf.placeholder(tf.float32, [None, 10]) x_image = tf.reshape(x, [-1, 28, 28, 1])# 定義第一個卷積層,[5, 5, 1, 32]代表 卷積核尺寸為5x5,1個通道,32個不同卷積核 # 對權重、偏置初始化,然后經卷積層和激活函數激活,最后池化操作 # h_pool1尺寸:14*14*32 W_conv1 = weight_variable([5, 5, 1, 32]) b_conv1 = bias_variable([32]) h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1) h_pool1 = max_pool_2x2(h_conv1)# 定義第二個卷積層,64是卷積核的數量,提取64種特征 # h_pool2尺寸:7*7*64(經過兩次池化) W_conv2 = weight_variable([5, 5, 32, 64]) b_conv2 = bias_variable([64]) h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2) h_pool2 = max_pool_2x2(h_conv2) # 經過兩層池化,邊長變為7*7,所以第二個卷積層輸出的tensor尺寸為7*7*64# 全連接層處理 # h_fc1尺寸:1*1024 W_fc1 = weight_variable([7 * 7 * 64, 1024]) b_fc1 = bias_variable([1024]) h_pool2_flat = tf.reshape(h_pool2, [-1, 7*7*64]) h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)# 減輕過擬合,使用Dropout層 # h_fc1尺寸:1*1024 keep_prob = tf.placeholder(tf.float32) h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)# 建立Softmax層與Dropout層連接,最后輸出概率 # y_conv尺寸:1*10 W_fc2 = weight_variable([1024, 10]) b_fc2 = bias_variable([10]) y_conv = tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2)# 定義損失函數,指定Adam優化器優化 cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y_conv), reduction_indices=[1])) train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)# 計算分類準確率 correct_prediction = tf.equal(tf.argmax(y_conv, 1), tf.argmax(y_, 1)) accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))tf.global_variables_initializer().run()# 開始訓練,訓練2萬次,mini_batch為50,每100次顯示分類精度 # 評測時,keep_prob設為1,用以實時監測模型性能 for i in range(20000):batch = mnist.train.next_batch(50)if i % 100 == 0:train_accuracy = accuracy.eval(feed_dict={x: batch[0], y_: batch[1], keep_prob: 1.0})print("step %d, training accuracy %g" % (i, train_accuracy))train_step.run(feed_dict={x: batch[0], y_: batch[1], keep_prob: 0.5})# 對測試集上進行測試 print("test accuracy %g" % accuracy.eval(feed_dict={x: mnist.test.images, y_: mnist.test.labels, keep_prob: 1.0})) # 99.2%step 0, training accuracy 0.1
step 100, training accuracy 0.88
。
。
。
這個簡單的卷積神經網絡模型的準確率大約為99.2%,基本可以滿足對手寫數字識別準確率的要求。相比之前的深度神經網絡2%的錯誤率,CNN的錯誤率下降了60%。這其中主要的性能提升都來自更優秀的網絡模型設計,充分說明卷積網絡對圖像特征的提取和抽象能力。依靠卷積核的權值共享,CNN的參數數量并沒有爆炸,降低計算量的同時也減輕了過擬合,整個模型的性能有著較大的提升。
總結
以上是生活随笔為你收集整理的TensorFlow基于minist数据集实现手写字识别实战的三个模型的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python之pandas,series
- 下一篇: TensorFlow基于cifar10数