卷積神經網路的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 版權宣告:本文為博主原創文章,轉載請附上博文連結!