深度學習(五)基於tensorflow實現簡單卷積神經網絡Lenet5


 

原文作者:aircraft

原文地址:https://www.cnblogs.com/DOMLX/p/8954892.html

 

 

深度學習教程目錄如下,還在繼續更新完善中

深度學習系列教程目錄

 

 

參考博客:https://blog.csdn.net/u012871279/article/details/78037984

https://blog.csdn.net/u014380165/article/details/77284921

目前人工智能神經網絡已經成為非常火的一門技術,今天就用tensorflow來實現神經網絡的第一塊敲門磚。

首先先分模塊解釋代碼。

1.先導入模塊,若沒有tensorflow還需去網上下載,這里使用mnist訓練集來訓練,進行手寫數字的識別。

from tensorflow.examples.tutorials.mnist import input_data
import tensorflow as tf 

#導入數據,創建一個session對象 ,之后的運算都會跑在這個session里
mnist = input_data.read_data_sets("MNIST/",one_hot=True)
sess = tf.InteractiveSession()

2.為了方便,定義后來要反復用到函數

#定義一個函數,用於初始化所有的權值 W,這里我們給權重添加了一個截斷的正態分布噪聲 標准差為0.1
def weight_variable(shape):
    initial = tf.truncated_normal(shape,stddev=0.1)
    return tf.Variable(initial)

#定義一個函數,用於初始化所有的偏置項 b,這里給偏置加了一個正值0.1來避免死亡節點
def bias_variable(shape):
    inital = tf.constant(0.1,shape=shape)
    return tf.Variable(inital)

#定義一個函數,用於構建卷積層,這里strides都是1 代表不遺漏的划過圖像的每一個點
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')

 

主要的函數說明:

卷積層:
tf.nn.conv2d(input, filter, strides, padding, use_cudnn_on_gpu=None, data_format=None, name=None)

參數說明:
  • data_format:表示輸入的格式,有兩種分別為:“NHWC”和“NCHW”,默認為“NHWC”

  • input:輸入是一個4維格式的(圖像)數據,數據的 shape 由 data_format 決定:當 data_format 為“NHWC”輸入數據的shape表示為[batch, in_height, in_width, in_channels],分別表示訓練時一個batch的圖片數量、圖片高度、 圖片寬度、 圖像通道數。當 data_format 為“NHWC”輸入數據的shape表示為[batch, in_channels, in_height, in_width]

  • filter:卷積核是一個4維格式的數據:shape表示為:[height,width,in_channels, out_channels],分別表示卷積核的高、寬、深度(與輸入的in_channels應相同)、輸出 feature map的個數(即卷積核的個數)。

  • strides:表示步長:一個長度為4的一維列表,每個元素跟data_format互相對應,表示在data_format每一維上的移動步長。當輸入的默認格式為:“NHWC”,則 strides = [batch , in_height , in_width, in_channels]。其中 batch 和 in_channels 要求一定為1,即只能在一個樣本的一個通道上的特征圖上進行移動,in_height , in_width表示卷積核在特征圖的高度和寬度上移動的布長,即 。

  • padding:表示填充方式:“SAME”表示采用填充的方式,簡單地理解為以0填充邊緣,當stride為1時,輸入和輸出的維度相同;“VALID”表示采用不填充的方式,多余地進行丟棄。具體公式:

    “SAME”:

    “VALID”:

池化層:
tf.nn.max_pool( value, ksize,strides,padding,data_format=’NHWC’,name=None)
或者
tf.nn.avg_pool(…)

參數說明:
  • value:表示池化的輸入:一個4維格式的數據,數據的 shape 由 data_format 決定,默認情況下shape 為[batch, height, width, channels]

  • 其他參數與 tf.nn.cov2d 類型

  • ksize:表示池化窗口的大小:一個長度為4的一維列表,一般為[1, height, width, 1],因不想在batch和channels上做池化,則將其值設為1。

 

 

#placceholder 基本都是用於占位符 后面用到先定義
x = tf.placeholder(tf.float32,[None,784])
y_ = tf.placeholder(tf.float32,[None,10])
x_image = tf.reshape(x,[-1,28,28,1])                                #將數據reshape成適合的維度來進行后續的計算

#第一個卷積層的定義
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)                #激活函數為relu
h_pool1 = max_pool_2x2(h_conv1)                                        #2x2 的max pooling 

#第二個卷積層的定義
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(tf.float32)
h_fc1_drop = tf.nn.dropout(h_fc1,keep_prob)

#第二個全連接層 分為十類數據 softmax后輸出概率最大的數字
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)

 

上面用到了softmax函數來計算loss。

那softmax loss是什么意思呢?如下:

這里寫圖片描述

首先L是損失。Sj是softmax的輸出向量S的第j個值,前面已經介紹過了,表示的是這個樣本屬於第j個類別的概率。yj前面有個求和符號,j的范圍也是1到類別數T,因此y是一個1*T的向量,里面的T個值,而且只有1個值是1,其他T-1個值都是0。那么哪個位置的值是1呢?答案是真實標簽對應的位置的那個值是1,其他都是0。所以這個公式其實有一個更簡單的形式:

這里寫圖片描述

當然此時要限定j是指向當前樣本的真實標簽。

來舉個例子吧。假設一個5分類問題,然后一個樣本I的標簽y=[0,0,0,1,0],也就是說樣本I的真實標簽是4,假設模型預測的結果概率(softmax的輸出)p=[0.1,0.15,0.05,0.6,0.1],可以看出這個預測是對的,那么對應的損失L=-log(0.6),也就是當這個樣本經過這樣的網絡參數產生這樣的預測p時,它的損失是-log(0.6)。那么假設p=[0.15,0.2,0.4,0.1,0.15],這個預測結果就很離譜了,因為真實標簽是4,而你覺得這個樣本是4的概率只有0.1(遠不如其他概率高,如果是在測試階段,那么模型就會預測該樣本屬於類別3),對應損失L=-log(0.1)。那么假設p=[0.05,0.15,0.4,0.3,0.1],這個預測結果雖然也錯了,但是沒有前面那個那么離譜,對應的損失L=-log(0.3)。我們知道log函數在輸入小於1的時候是個負數,而且log函數是遞增函數,所以-log(0.6) < -log(0.3) < -log(0.1)。簡單講就是你預測錯比預測對的損失要大,預測錯得離譜比預測錯得輕微的損失要大。

———————————–華麗的分割線———————————–

理清了softmax loss,就可以來看看cross entropy了。
corss entropy是交叉熵的意思,它的公式如下:

這里寫圖片描述

 

 

tf.nn.dropout(x, keep_prob, noise_shape=None, seed=None,name=None) 

上面方法中常用的是前兩個參數:

第一個參數x:指輸入 

第二個參數keep_prob: 設置神經元被選中的概率,在初始化時keep_prob是一個占位符,  keep_prob = tf.placeholder(tf.float32) 。tensorflow在run時設置keep_prob具體的值,例如keep_prob: 0.5

第五個參數name:指定該操作的名字。

 

 

 

correct_predition 進行的是 分別取得預測數據和真實數據中概率最大的來比對是否一樣

tf.cast()為類型轉換函數 轉換成float32類型
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)                                #這里用Adam優化器 優化 也可以使用隨機梯度下降

correct_predition = tf.equal(tf.argmax(y_conv,1),tf.argmax(y_,1))                   
accuracy = tf.reduce_mean(tf.cast(correct_predition,tf.float32))                                #准確率

tf.initialize_all_variables().run()                                                                #使用全局參數初始化器 並調用run方法 來進行參數初始化

 

tf.initialize_all_variables() 接口是老的接口 也許你們的tensorflow 已經用不了     現在tf.initialize_all_variables()已經被tf.global_variables_initializer()函數代替

 

 

下面是使用大小為50的mini-batch 來進行迭代訓練  每一百次 勘察一下准確率   訓練完畢     就可以直接進行數據的測試了

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})                            #batch[0]   [1] 分別指數據維度 和標記維度 將數據傳入定義好的優化器進行訓練


print "test accuracy %g"%accuracy.eval(feed_dict={x:mnist.test.images,y_:mnist.test.labels,keep_prob:1.0})    #開始測試數據 

 

 

同學們大概應該直到這個過程了,如果不理解神經網絡Lenet 建議先百度看看他的原理

下面是完整代碼。

# -*- coding: utf-8 -*-
"""
Created on XU JING HUI  4-26-2018

@author: root
"""
from tensorflow.examples.tutorials.mnist import input_data
import tensorflow as tf 

#導入數據,創建一個session對象 ,之后的運算都會跑在這個session里
mnist = input_data.read_data_sets("MNIST/",one_hot=True)
sess = tf.InteractiveSession()

#定義一個函數,用於初始化所有的權值 W,這里我們給權重添加了一個截斷的正態分布噪聲 標准差為0.1
def weight_variable(shape):
    initial = tf.truncated_normal(shape,stddev=0.1)
    return tf.Variable(initial)

#定義一個函數,用於初始化所有的偏置項 b,這里給偏置加了一個正值0.1來避免死亡節點
def bias_variable(shape):
    inital = tf.constant(0.1,shape=shape)
    return tf.Variable(inital)

#定義一個函數,用於構建卷積層,這里strides都是1 代表不遺漏的划過圖像的每一個點
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')


#placceholder 基本都是用於占位符 后面用到先定義
x = tf.placeholder(tf.float32,[None,784])
y_ = tf.placeholder(tf.float32,[None,10])
x_image = tf.reshape(x,[-1,28,28,1])                                #將數據reshape成適合的維度來進行后續的計算

#第一個卷積層的定義
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)                #激活函數為relu
h_pool1 = max_pool_2x2(h_conv1)                                        #2x2 的max pooling 

#第二個卷積層的定義
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(tf.float32)
h_fc1_drop = tf.nn.dropout(h_fc1,keep_prob)

#第二個全連接層 分為十類數據 softmax后輸出概率最大的數字
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_mean(-tf.reduce_sum(y_ * tf.log(y_conv),reduction_indices=[1]))        #交叉熵
train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)                                #這里用Adam優化器 優化 也可以使用隨機梯度下降

correct_predition = tf.equal(tf.argmax(y_conv,1),tf.argmax(y_,1))
accuracy = tf.reduce_mean(tf.cast(correct_predition,tf.float32))                                #准確率

tf.initialize_all_variables().run()                                                                #使用全局參數初始化器 並調用run方法 來進行參數初始化

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})                            #batch[0]   [1] 分別指數據維度 和標記維度 將數據傳入定義好的優化器進行訓練


print "test accuracy %g"%accuracy.eval(feed_dict={x:mnist.test.images,y_:mnist.test.labels,keep_prob:1.0})    #開始測試數據 

 

若有興趣交流分享技術,可關注本人公眾號,里面會不定期的分享各種編程教程,和共享源碼,諸如研究分享關於c/c++,python,前端,后端,opencv,halcon,opengl,機器學習深度學習之類有關於基礎編程,圖像處理和機器視覺開發的知識


免責聲明!

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



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