原文作者: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,機器學習深度學習之類有關於基礎編程,圖像處理和機器視覺開發的知識

