1. 程式人生 > >卷積神經網路的tensorflow實現

卷積神經網路的tensorflow實現

版權宣告:本文為博主原創文章,未經博主允許不得轉載。    https://blog.csdn.net/happyhorizion/article/details/77894047 卷積神經網路概述 一般一個卷積神經網路由多個卷積層構成,在卷基層內部通常會有如下幾個操作: 1)影象通過多個卷積核濾波,新增偏置,提取區域性特徵每個卷積核會映射出一個新的2D影象。 2)卷積核的濾波結果輸出到啟用函式中,啟用函式通常選ReLU【書,參考37】 3)對啟用函式的結果進行池化操作,池化就是對影象分割成不同的小區域後取平均值或最大值。一般取最大值。 上述幾個步驟就構成了最常見的卷積層。在池化的後面還可以加上batch normalization等操作。 一個卷積層中可以有不同的卷積核,而每一個卷積核都對應一個濾波後映射出的新影象,同一個新影象的每一個畫素都來自完全相同的卷積核。這種卷積核的權值共享可以有效降低模型負責度,減輕過擬合,減少計算量。

tensorflow實現 卷積神經網路結構 建立卷積神經網路對手寫數字識別問題進行優化,構建由兩個卷積層(包含池化層),兩個全連線層構成的卷積神經網路。輸入影象是28×28的單通道資料,輸出是10×1的one_hot編碼的向量。 第一層:卷積核大小是[5,5],輸入通道1,輸出通道32,padding選擇SAME模式,啟用函式為relu。 第二層:池化層,池化核大小是[2,2],步長[2,2]。 第三層:卷積核大小是[5,5],輸入通道32,輸出通道64,padding選擇SAME模式,啟用函式為relu。 第四層:池化層,設定同上。 第五層:全連線層,首先將影象資料矩陣flatten化,變成1維向量,輸出維度是1024, 之後dropout掉一定的資料防止過擬合 第六層:全連線層,輸出維度10,啟用函式為softmax 損失函式:交叉熵

具體實現如下:

匯入包和資料 首先匯入需要的包和資料

import tensorflow as tf from tensorflow.examples.tutorials.mnist import input_data mnist = input_data.read_data_sets('MNIST_DATA/', one_hot=True) 1 2 定義卷積核 卷積核是指定維數的張量,卷積核的大小為:[filter_height, filter_width, in_channels, out_channels] 這裡用tf.Variable()定義卷積核,定義的時候會指定初始化的操作。

def weight_variable(shape):     initial = tf.truncated_normal(shape,stddev=0.1)     weight= tf.Variable(initial_value=initial) return weight 1 2 3 定義偏置 def bias_variable(shape):     initial = tf.constant(0.1,shape=shape)     bias = tf.Variable(initial_value=initial)     return bias 1 2 3 對輸入做卷積操作 def conv_op(in_tensor, kernel, strides=[1,1,1,1], padding=’SAME’, name=’conv’):     conv_out = tf.nn.conv2d(in_tensor,kernel,strides, padding,name=name) return conv_out 1 2 輸入的張量維度是[batch, in_height,in_width,in_channels] 在具體操作中,程式會將輸入張量展開為[batch, out_height, out_width, filter_hightfilter_widthin_channels] 並將卷積核展開為[filter_heightfilter_widthin_channels, out_channels ] 輸入張量展開後與卷積核的展開相乘,得到的結果的維度是:[batch, out_height, out_width, out_channels],和輸入張量的維度保持一致。也就是說,在tensorflow構建的圖中,張量始終都是以始終是:[batch, height,width,channels]的維度流動。 步長strides通常定義為strides=[1, dh, dw, 1], 也就是strides[0]=strides[3]=1. dh和dw分別是垂直和水平方向卷積核移動的步長。 padding就是是否要做邊界填充,如果要,padding=‘SAME’,如果不用,padding=‘VALID’

疊加上偏置並輸出到啟用函式 h_conv1 = tf.nn.relu(conv_op(x_image, W_conv1)+b_conv1) 之後輸入到啟用函式,直接呼叫tensorflow中的tf.nn.relu()函式就可以,啟用函式的輸出依然是:[batch, out_height, out_width, out_channels]

tf.nn.relu(features, name = None) 輸入引數:

features: 一個Tensor。資料型別必須是:float32,float64,int32,int64,uint8,int16,int8。 name: (可選)為這個操作取一個名字。 輸出引數:

一個Tensor,資料型別和features相同。 在tensorflow中,加法運算有好幾種,例如專門的偏置疊加tf.bias_add,還有tf.add,也可以直接用a+b,具體區別見後。

池化層 池化操作是:對輸入的張量進行區域掃描求最大值或者平均值。一般求最大值。tensorflow有tf.nn.max_pool()函式可以方便地實現池化操作。池化尺寸kh×kw, 步長是dh×dw,padding設定為‘SAME’。

def max_pool_2x2(in_tensor, ksize=[1,2,2,1], strides=[1,2,2,1],padding=’SAME’,name=’max_pooling’):     max_pool = tf.nn.max_pool(in_tensor, ksize, strides, padding, name=name) return max_pool 1 2 這裡ksize=[1,kh,kd,1], strides=[1,dh,dw,1]

目標函式:交叉熵  cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_*tf.log(y_conv),reduction_indices=[1])) 自此,就定義好了前向計算的所有操作。後向計算採用AdamOptimizer函式,學習率1e-4

最後,給出卷積操作的實現程式碼:

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Created on Sun Jul  9 12:16:52 2017 mnist by simple cnn @author:  """   import tensorflow as tf from tensorflow.examples.tutorials.mnist import input_data   mnist = input_data.read_data_sets('MNIST_DATA/', one_hot=True)   sess = tf.InteractiveSession()   # ======================================================== # #                       SIMPLE CNN # ======================================================== #   # define conv kernel def weight_variable(shape):     initial = tf.truncated_normal(shape,stddev=0.1)     weight = tf.Variable(initial_value=initial)     return weight   # define conv bias def bias_variable(shape):     initial = tf.constant(0.1,shape=shape)     bias = tf.Variable(initial_value=initial)     return bias   # define a simple conv operation  def conv_op(in_tensor, kernel, strides=[1,1,1,1], padding='SAME'):     conv_out = tf.nn.conv2d(in_tensor, kernel, strides=strides, padding=padding)     return conv_out   # define max pooling operation def max_pool_2x2(in_tensor,ksize=[1,2,2,1],strides=[1,2,2,1],padding='SAME'):     max_pool = tf.nn.max_pool(in_tensor, ksize, strides, padding)     return max_pool   def simple_cnn():     x = tf.placeholder(tf.float32, [None, 784])     y_ = tf.placeholder(tf.float32, [None, 10])     x_image = tf.reshape(x,[-1, 28, 28, 1]) # 28*28 pic of 1 channel       # cnn structure     w1 = [5,5,1,32]     b1 = [32]     w2 = [5,5,32,64]     b2 = [64]     wfc1 = [7*7*64,1024]     bfc1 = [1024]     wfc2 = [1024,10]     bfc2 = [10]       # 1st layer     W_conv1 = weight_variable(w1)     b_conv1 = bias_variable(b1)     h_conv1 = tf.nn.relu(conv_op(x_image, W_conv1)+b_conv1)     h_pool1 = max_pool_2x2(h_conv1)     # 2nd layer     W_conv2 = weight_variable(w2)     b_conv2 = bias_variable(b2)     h_conv2 = tf.nn.relu(conv_op(h_pool1, W_conv2)+b_conv2)     h_pool2 = max_pool_2x2(h_conv2)     # fc1     h_pool2_flat = tf.reshape(h_pool2,[-1,7*7*64])     W_fc1 = weight_variable(wfc1)     b_fc1 = bias_variable(bfc1)     h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1)+b_fc1)     # drop out     keep_prob = tf.placeholder(tf.float32)     h_fc1_drop = tf.nn.dropout(h_fc1,keep_prob)     # fc2     W_fc2 = weight_variable(wfc2)     b_fc2 = bias_variable(bfc2)     y_conv = tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2)+b_fc2)     # loss function     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)       # estimate accuarcy     correct_prediction = tf.equal(tf.arg_max(y_conv,1), tf.arg_max(y_,1))     accuarcy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))           tf.global_variables_initializer().run()     for i in range(20000):         batch = mnist.train.next_batch(50)         if i%100 == 0:             train_accuracy = accuarcy.eval(feed_dict={x:batch[0],y_:batch[1],keep_prob:1.0}) # testify, or prediction             print('step %d, training accuarcy %g'%(i, train_accuracy))         train_step.run(feed_dict={x:batch[0],y_:batch[1],keep_prob:0.5})       print("test accuracy %g"%accuarcy.eval(feed_dict={x:mnist.test.images,y_:mnist.test.labels,keep_prob:1.0}))     return   if __name__ == '__main__':     simple_cnn() tensorflow的一些細節點: padding padding的選項:

valid就是指卷積核是以整個卷積核為基礎從邊沿對齊影象的邊沿開始,任何邊沿到達影象另一邊時就停止卷積運算; same則是以卷積核的中間點為基礎,中間點掃過真個影象才結束。自然,same的模式下,卷積後的輸出和原輸入的維度是一致的。 tf.cast 估計模型的準確度時,用到了函式tf.cast tf.cast(x, dtype, name=None)資料型別轉換,將x或者x.values轉換為dtype a=tf.constant(value=[1.1,2.3],dtype=tf.float32) b=tf.cast(a,dtype=tf.int32) sess = tf.Session() print(sess.run(a)) #輸出[ 1.10000002 2.29999995] print(sess.run(b)) #輸出[1 2]

tf.add(a,b)、tf.bias_add(a,b)和 a+b 1) tf.add(a, b) 與 a+b 在神經網路前向傳播的過程中,經常可見如下兩種形式的程式碼: tf.add(tf.matmul(x, w), b) tf.matmul(x, w) + b 簡而言之,就是 tf.add(a, b) 與 a + b二者的區別,類似的也有,tf.assign 與 =(賦值運算子)的差異。 在計算精度上,二者並沒有差別。運算子過載的形式a+b,會在內部轉換為,a.add(b),而a.add(b)會再一次地對映為tf.add。

2. tf.nn.bias_add 與 tf.add tf.nn.bias_add 是 tf.add 的一個特例,也即 tf.add 支援的操作比 tf.nn.bias_add 更多。二者均支援 broadcasting(廣播機制),也即兩個運算元最後一個維度保持一致。 除了支援最後一個維度保持一致的兩個運算元相加外,tf.add 還支援第二個運算元是一維的情況。 參考: 《tensorflow實戰》 http://blog.csdn.net/wangjian1204/article/details/53291619 In tensorflow what is the difference between tf.add and operator (+)?(https://stackoverflow.com/questions/37900780/in-tensorflow-what-is-the-difference-between-tf-add-and-operator) ---------------------  作者:lxy_Alex  來源:CSDN  原文:https://blog.csdn.net/happyhorizion/article/details/77894047?utm_source=copy  版權宣告:本文為博主原創文章,轉載請附上博文連結!