機器學習與Tensorflow(4)——卷積神經網絡與tensorflow實現


1.標准卷積神經網絡

標准的卷積神經網絡由輸入層、卷積層(convolutional layer)、下采樣層(downsampling layer)、全連接層(fully—connected layer)和輸出層構成。

  • 卷積層也稱為檢測層
  • 下采樣層也稱為池化層(pooling layer)

2.卷積神經網絡的優勢:

第一個特點和優勢就是:局部感知

  • 在傳統神經網絡中每個神經元都要與圖片上每個像素相連接,
  • 這樣的話就會造成權重的數量巨大造成網絡難以訓練。
  • 而在含有卷積層的神經網絡中每個神經元的權重個數都時卷積核的大小,
  • 這樣就相當於神經元只與對應圖片部分的像素相連接。
  • 這樣就極大的減少了權重的數量。同時我們可以設置卷積操作的步長,
  • 但是步長的設置並無定值需要使用者自己嘗試


第二個特點和優勢就是:參數共享

  • 卷積核的權重是經過學習得到的,並且在卷積過程中卷積核的權重是不會改變的,這就是參數共享的思想。
  • 通過一個卷積核的操作提取了原圖的不同位置的同樣特征。
  • 簡單來說就是在一幅圖片中的不同位置的相同目標,它們的特征是基本相同的

第三個特點和優勢就是:多卷積核

  • 我們用一個卷積核操作只能得到一部分特征可能獲取不到全部特征,
  • 所以為了能夠得到圖像更多的特征信息我們引入了多核卷積。
  • 用多個卷積核來學習圖像更多的不同的特征(每個卷積核學習到不同的權重)。
  • 主要注意的是在多核卷積的過程中每一層的多個卷積核的大小應該是相同的。


3.關於卷積

先了解卷積運算:內卷積和外卷積(具體如下圖)

內卷積:

外卷積:

 

卷積層的作用:

  • 卷積層的每一個卷積濾波器作用於整個感受野中,對輸入圖像進行卷積,
  • 卷積的結果構成了輸入圖像的特征圖,從而經過卷積層后就提取出了圖像的局部特征。
  • 所以卷積層的主要作用就是可以利用不同的卷積核(也叫濾波器)來提取圖像不同的特征。
  • 它是識別圖像最核心的部分。

 

4.關於池化

池化方式:(最大池化、平均池化)

  • 池化層的具體操作與卷基層的操作基本相同,只不過池化層的卷積核為只取對應位置的最大值或平均值(最大池化、平均池化),
  • 並且不會隨着反向傳播發生變化。一般池化層的filter取2*2,最大取3*3,stride取2,特征信息壓縮為原來的1/4。

最大池化方式(每個小塊中的最大值):

 

平均池化方式(每個小塊中的平均值):

 


池化層的作用:

  • 池化層可對提取到的特征信息進行降維,
  • 一方面使特征圖變小,簡化網絡計算復雜度並在一定程度上避免過擬合的出現;一方面進行特征壓縮,提取主要特征。
  • 最大池采樣在計算機視覺中的價值體現在兩個方面:(1)、它減小了來自上層隱藏層的計算復雜度;(2)、這些池化單元具有平移不變性,即使圖像有小的位移,提取到的特征依然會保持不變。由於增強了對位移的魯棒性,這樣可以忽略目標的傾斜、旋轉之類的相對位置的變化,以此提高精度,最大池采樣方法是一個高效的降低數據維度的采樣方法。
  • 需要注意的是:這里的pooling操作是特征圖縮小,有可能影響網絡的准確度。


5.Tensorflow實現

def conv2d(input, filter, strides, padding, use_cudnn_on_gpu=None,data_format=None, name=None)

除去name參數用以指定該操作的name,與方法有關的一共五個參數:

第一個參數input:

  • 指需要做卷積的輸入圖像,它要求是一個Tensor,具有[batch, in_height, in_width, in_channels]這樣的shape,
  • 具體含義是[訓練時一個batch的圖片數量, 圖片高度, 圖片寬度, 圖像通道數],
  • 注意這是一個4維的Tensor,要求類型為float32和float64其中之一

第二個參數filter:

  • 相當於CNN中的卷積核,它要求是一個Tensor,具有[filter_height, filter_width, in_channels, out_channels]這樣的shape,
  • 具體含義是[卷積核的高度,卷積核的寬度,圖像通道數,卷積核個數],
  • 要求類型與參數input相同,
  • 有一個地方需要注意,第三維in_channels,就是參數input的第四維

第三個參數strides:

  • 卷積時在圖像每一維的步長,這是一個一維的向量,長度4
  • strides[0] = strides[3] = 1
  • strides[1]代表x方向的步長,strides[2]代表y方向的步長


第四個參數padding:

  • string類型的量,只能是"SAME","VALID"其中之一,這個值決定了不同的卷積方式
  • 對於卷積操作:
    • SAME PADDING代表給平面外部補0,卷積窗口采樣后得到一個跟原來平面大小相同的平面
    • VALID PADDING代表不會超出平面外部,卷積窗口采樣后得到比原來平面小的平面。
  • 對於池化操作:
    • SAME PADDING代表可能會給平面外部補0
    • VALID PADDING代表不會超出平面外部

舉例理解:
假如有一個28*28的平面,用2*2並且步長為2的窗口對其進行pooling操作

使用SAME PADDING的方式,得到14*14的平面
使用VALID PADDING的方式,得到14*14的平面


假如有一個2*3的平面,用2*2並且步長為2的窗口對其進行pooling操作

使用SAME PADDING的方式,得到1*2的平面
使用VALID PADDING的方式,得到1*1的平面

 



第五個參數:use_cudnn_on_gpu:bool類型,是否使用cudnn加速,默認為true

結果返回一個Tensor,這個輸出,就是我們常說的feature map

 

6.卷積神經網絡對MNIST手寫數據集識別優化

實現代碼:

  1 import os
  2 os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
  3 import tensorflow as tf
  4 from tensorflow.examples.tutorials.mnist import input_data
  5 
  6 #載入數據集
  7 mnist = input_data.read_data_sets('MNIST_data', one_hot=True)
  8 
  9 #每個批次的大小
 10 batch_size = 100
 11 
 12 #計算一個有多少個批次
 13 n_batch = mnist.train.num_examples // batch_size
 14 
 15 #初始化權值
 16 def weight_variable(shape):
 17     initial = tf.truncated_normal(shape, stddev=0.1)#生成一個截斷的正態分布
 18     return tf.Variable(initial)
 19 
 20 #初始化偏置
 21 def bias_variable(shape):
 22     initial = tf.constant(0.1, shape=shape)
 23     return tf.Variable(initial)
 24 
 25 #卷積層
 26 def conv2d(x,W):
 27     # x input tensor of shape `[batch, in_height, in_width, in_channels]`
 28     # W filter / kernel tensor of shape [filter_height, filter_width, in_channels, out_channels]
 29     # `strides[0] = strides[3] = 1`. strides[1]代表x方向的步長,strides[2]代表y方向的步長
 30     # padding: A `string` from: `"SAME", "VALID"`
 31     return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')
 32 
 33 #池化層
 34 def max_pool_2x2(x):
 35     # ksize [1,x,y,1]
 36     return tf.nn.max_pool(x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
 37 
 38 #定義兩個placeholder
 39 x = tf.placeholder(tf.float32, [None, 784]) #28*28
 40 y = tf.placeholder(tf.float32, [None,10])
 41 
 42 #改變x的格式轉為4D的向量[batch,in_height,in_width,in_channels]
 43 x_image = tf.reshape(x, [-1, 28, 28, 1])
 44 
 45 #初始化第一個卷積層的權值和偏置
 46 W_conv1 = weight_variable([5, 5, 1, 32])  #5*5的采樣窗口,32個卷積核從1個平面抽取特征
 47 b_conv1 = bias_variable([32]) #每一個卷積核一個偏置值
 48 
 49 #把x_image和權值向量進行卷積,再加上偏置值,然后應用於relu激活函數
 50 h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)
 51 h_pool1 = max_pool_2x2(h_conv1)
 52 
 53 #初始第二個卷積層的權值和偏置值
 54 W_conv2 = weight_variable([5, 5, 32, 64])#5*5的采樣窗口,64個卷積核從32個平面抽取特征
 55 b_conv2 = bias_variable([64])
 56 
 57 #把h_pool1和權值向量進行卷積,再加上偏置值,然后應用於relu激活函數
 58 h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)
 59 h_pool2 = max_pool_2x2(h_conv2)
 60 
 61 #28*28的圖片第一次卷積后還是28*28,第一次池化后變成14*14
 62 #第二次卷積為14*14,第二次池化后變成可7*7
 63 #經過上面的操作后得到64張7*7的平面
 64 
 65 #初始化第一個全連接層的權值
 66 W_fc1 = weight_variable([7*7*64, 1024])#上一層有7*7*64個神經元,全連接層有1024個神經元
 67 b_fc1 = bias_variable([1024])#1024個節點
 68 
 69 #把池化層2的輸出扁平化為1維
 70 h_pool2_flat = tf.reshape(h_pool2, [-1, 7*7*64])
 71 
 72 #求第一個全連接層的輸出
 73 h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)
 74 
 75 #keep_prob用來表示神經元的輸出概率
 76 keep_prob = tf.placeholder(tf.float32)
 77 h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)
 78 
 79 #初始化第二個全連接層
 80 W_fc2 = weight_variable([1024, 10])
 81 b_fc2 = bias_variable([10])
 82 
 83 #計算輸出
 84 prediction = tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2)
 85 
 86 #交叉熵代價函數
 87 cross_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y, logits=prediction))
 88 
 89 #使用AdmaOptimizer進行優化
 90 train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)
 91 
 92 #結果存放在一個布爾列表中
 93 correct_prediction = tf.equal(tf.argmax(prediction, 1), tf.argmax(y, 1))
 94 
 95 #求准確率
 96 accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
 97 
 98 #變量初始化
 99 init = tf.global_variables_initializer()
100 
101 with tf.Session() as sess:
102     sess.run(init)
103     for epoch in range(21):
104         for batch in range(n_batch):
105             batch_xs, batch_ys = mnist.train.next_batch(batch_size)
106             sess.run(train_step, feed_dict={x: batch_xs, y: batch_ys, keep_prob: 0.7})
107         acc = sess.run(accuracy, feed_dict={x: mnist.test.images[:5000], y: mnist.test.labels[:5000], keep_prob: 1.0})
108         print('Iter : ' + str(epoch) + ',Testing Accuracy = ' + str(acc))
View Code

#寫在后面:

好久沒有做學習總結

最近一直在給老師處理軸承數據,然后用深度學習做分類

每天就是忙忙忙

然后還要去健身

昨天是自己的生日,吃了一個超級可愛的小蛋糕

感覺自己還像個孩子

永遠18歲

最近煩心事有點多

很多時候不必向別人解釋自己

懂你的人自然而然就會懂

不懂得人解釋也不懂

加油吧!小伙郭

加油,每一個為了生活而努力向前的人!

 


免責聲明!

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



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