永興的tensorflow筆記-15 卷積神經網絡實踐

在這裏插入圖片描述

一、什麼是卷積神經網絡?

卷積神經網路(Convolutional Neural Network, CNN)是一種前饋神經網絡,它的人工神經元可以響應一部分覆蓋範圍內的周圍單元,對於大型圖像處理有出色表現。卷積神經網路由一個或多個卷積層和頂端的全連通層(對應經典的神經網路)組成,同時也包括關聯權重和池化層(pooling layer)。這一結構使得卷積神經網路能夠利用輸入數據的二維結構。與其他深度學習結構相比,卷積神經網路在圖像和語音識別方面能夠給出更好的結果。這一模型也可以使用反向傳播算法進行訓練。相比較其他深度、前饋神經網路,卷積神經網路需要考量的參數更少,使之成爲一種頗具吸引力的深度學習結構。 卷積網絡是一種專門用於處理具有已知的、網格狀拓撲的數據的神經網絡。
在這裏插入圖片描述

二、實踐卷積神經網絡。

在這裏插入圖片描述

  1. 在MNIST上只有91%正確率,實在太糟糕。在這個小節裏,我們用一個稍微複雜的模型:卷積神經網絡來改善效果。這會達到大概99.2%的準確率。雖然不是最高,但是還是比較讓人滿意。
    權重初始化:
    爲了創建這個模型,我們需要創建大量的權重和偏置項。這個模型中的權重在初始化時應該加入少量的噪聲來打破對稱性以及避免0梯度。由於我們使用的是ReLU神經元,因此比較好的做法是用一個較小的正數來初始化偏置項,以避免神經元節點輸出恆爲0的問題(dead neurons)。爲了不在建立模型的時候反覆做初始化操作,我們定義兩個函數用於初始化。
#權重初始化
def weight_variable(shape):
    inital = tf.truncated_normal(shape,stddev=0.1)
    return tf.Variable(inital)
def bias_variable(shape):
    inital = tf.constant(0.1,shape)
    return tf.Variable(inital)
  1. 卷積和池化
    TensorFlow在卷積和池化上有很強的靈活性。我們怎麼處理邊界?步長應該設多大?在這個實例裏,我們會一直使用vanilla版本。我們的卷積使用1步長(stride size),0邊距(padding size)的模板,保證輸出和輸入是同一個大小。我們的池化用簡單傳統的2x2大小的模板做max pooling。爲了代碼更簡潔,我們把這部分抽象成一個函數。
#卷積和池化
def conv2d(x,w):
    return tf.nn.conv2d(x,w,strides=[1,1,1,1],padding="SAME")
def max_pool_2x2(x):
    return tf.nn.max_pool(x,
                          ksize=[1,2,2,1],
                          strides=[1,2,2,1],
                          padding="SAME")
  1. 第一層卷積
    現在我們可以開始實現第一層了。它由一個卷積接一個max pooling完成。卷積在每個5x5的patch中算出32個特徵。卷積的權重張量形狀是[5, 5, 1, 32],前兩個維度是patch的大小,接着是輸入的通道數目,最後是輸出的通道數目。 而對於每一個輸出通道都有一個對應的偏置量。
W_conv1 = weight_variable([5, 5, 1, 32])
b_conv1 = bias_variable([32])
  1. 爲了用這一層,我們把x變成一個4d向量,其第2、第3維對應圖片的寬、高,最後一維代表圖片的顏色通道數(因爲是灰度圖所以這裏的通道數爲1,如果是rgb彩色圖,則爲3)。
#改變形狀
x_image = tf.reshape(x, [-1,28,28,1])
  1. 我們把x_image和權值向量進行卷積,加上偏置項,然後應用ReLU激活函數,最後進行max pooling。
#第一次卷積
h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)
h_pool1 = max_pool_2x2(h_conv1)
  1. 第二層卷積
    爲了構建一個更深的網絡,我們會把幾個類似的層堆疊起來。第二層中,每個5x5的patch會得到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)
  1. 全連接層
    現在,圖片尺寸減小到7x7,我們加入一個有1024個神經元的全連接層,用於處理整個圖片。我們把池化層輸出的張量reshape成一些向量,乘上權重矩陣,加上偏置,然後對其使用ReLU。
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)
  1. Dropout層
    爲了減少過擬合,我們在輸出層之前加入dropout。我們用一個placeholder來代表一個神經元的輸出在dropout中保持不變的概率。這樣我們可以在訓練過程中啓用dropout,在測試過程中關閉dropout。 TensorFlow的tf.nn.dropout操作除了可以屏蔽神經元的輸出外,還會自動處理神經元輸出值的scale。所以用dropout的時候可以不用考慮scale。
keep_prob = tf.placeholder("float")
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)
  1. 輸出層
    最後,我們添加一個softmax層,就像前面的單層softmax regression一樣
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)
  1. 訓練和評估模型
    這個模型的效果如何呢?
    爲了進行訓練和評估,我們使用與之前簡單的單層SoftMax神經網絡模型幾乎相同的一套代碼,只是我們會用更加複雜的ADAM優化器來做梯度最速下降,在feed_dict中加入額外的參數keep_prob來控制dropout比例。然後每100次迭代輸出一次日誌。
with tf.Session as sess:
    cross_entropy = -tf.reduce_sum(y_*tf.log(y_conv))
    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, "float"))
    sess.run(tf.initialize_all_variables())
    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}))

三、完整代碼展示:

import tensorflow as tf
import numpy as np

sess = tf.InteractiveSession() #交互式

from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets('MNIST_data', one_hot=True)

#權重初始化
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)
#卷積和池化
def conv2d(x,w):
    return tf.nn.conv2d(x,w,strides=[1,1,1,1],padding="SAME")
def max_pool_2x2(x):
    return tf.nn.max_pool(x,
                          ksize=[1,2,2,1],
                          strides=[1,2,2,1],
                          padding="SAME")
#定義佔位符
x = tf.placeholder("float", shape=[None, 784])
y_ = tf.placeholder("float", shape=[None, 10])
#初始化權重
W_conv1 = weight_variable([5, 5, 1, 32])
b_conv1 = bias_variable([32])
#改變形狀
x_image = tf.reshape(x, [-1,28,28,1])
#第一次卷積
h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)
h_pool1 = max_pool_2x2(h_conv1)
#第二層卷積
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)
#全連接層
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層
keep_prob = tf.placeholder("float")
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)
#輸出層
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)

cross_entropy = -tf.reduce_sum(y_*tf.log(y_conv))
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, "float"))
sess.run(tf.initialize_all_variables())
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}))


#eval() 其實就是tf.Tensor的Session.run() 的另外一種寫法

實踐任務:
自行設計一個卷積神經網絡必須包含 卷積、池化、全連接、Dropout 層,也需要使用 正則化、移動平均、指數衰減學習率 ,在MNIST數據集上的準確率在 百分之99以上。
評論出你的答案:

發佈了48 篇原創文章 · 獲贊 28 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章