這裡我們将介紹如何實作常見的卷積層和池化層
這裡我們以二維資料為例進行介紹
第1步:引入相應的庫并建立計算圖會話
import tensorflow as tf
import numpy as np
#建立計算圖會話
sess = tf.Session()
第2步:建立資料并初始化占位符,這裡輸入資料shape = [10,10]
#準備資料
data_size = [10,10]
data_2d = np.random.normal(size=data_size)
#占位符
x_input_2d = tf.placeholder(tf.float32,shape=data_size)
第3步:聲明卷積層函數,這裡采用TensorFlow内建函數tf.nn.conv2d(),由于該函數需要輸入4維資料(批量大小,寬度,高度,顔色通道),是以首先需要對輸入資料進行擴維。tf.expand.dims函數為擴維函數,其作用是在給定位置增加一維。例如輸入資料shape = [10,10],則tf.expand_dims(input_2d,0)的shape為[1,10,10]。
其次配置相應的濾波器,步長stride以及padding
濾波器選用外部輸入濾波器參數myfilter,步長為兩個方向為2,padding為VALID。
最後采用tf.squeeze函數将卷積後的資料shape轉換為2維資料
#聲明卷積層
#由于conv2d()函數為4維資料設計,包括[batch_size,width,height,channels],是以需要4維資料
def conv_layer_2d(input_2d , myfilter):
#将資料轉化為4維
input_3d = tf.expand_dims(input_2d,0) #shape = [1,10,10]
input_4d = tf.expand_dims(input_3d,3) #shape = [1,10,10,1]
#卷積操作
#這裡設定兩個方向上的補償,padding選擇no padding,myfileter采用2*2,是以10*10 ==>5*5
conv_out = tf.nn.conv2d(input=input_4d,filter=myfilter,strides=[1,2,2,1],padding='VALID')
#次元還原
conv_out_2d = tf.squeeze(conv_out) #shape = [5,5]
return conv_out_2d
這裡定義濾波器大小為2X2,經過上述建立的卷積層後,輸出資料shape為[5,5]
myfilter = tf.Variable(tf.random_normal(shape=[2,2,1,1]))
my_convolution_output = conv_layer_2d(x_input_2d,myfilter)
第4步:聲明激勵函數,激勵函數是針對逐個元素的,建立激勵函數并初始化後将上述卷積層後得到的資料通過激勵函數。
#激勵函數
#這裡選擇ReLu作為激活函數
def activation(input_2d):
return tf.nn.relu(input_2d)
my_activation_output = activation(my_convolution_output)
第5步:池化層
輸入為經激活函數後的資料,shape=[5,5]
池化層仍采用TensorFlow内建函數,其處理方式與卷積層類似,仍然先擴維,然後通過池化函數tf.nn.max_pool,最後降維得到輸出資料,這裡池化層步長為1,寬和高為2X2,shape變為[4,4]
def max_pool(input_2d,width,height):
#先将資料擴充為4維
input_3d = tf.expand_dims(input_2d,0) #shape = [1,5,5]
input_4d = tf.expand_dims(input_3d,3) #shape = [1,5,5,1]
#池化操作
pool_output = tf.nn.max_pool(input_4d,ksize=[1,height,width,1],strides=[1,1,1,1],padding='VALID')
#降維
pool_output_2d = tf.squeeze(pool_output)#shape = [4,4]
return pool_output_2d
my_maxpool_output = max_pool(my_activation_output,width=2,height=2)
第6步:全連接配接層
輸入為經池化層後的資料,shape = [4,4]以及需要連接配接的神經元個數num_outputs = 5
這裡為保證所有資料均能夠與神經元相連接配接,首先将資料轉化為一維向量,并計算y=wx+b中w和b的shape
輸入資料的shape變為[16],我們通過tf.shape得到該shape,然後通過tf.stack将輸入shape與神經元個數連接配接得到shape為[[16],[5]],最後通過tf.squeeze得到w的shape為[16,5],b的shape為5
最後由于y=wx+b為矩陣運算,需要将資料擴維至2維資料,經計算後再通過降維還原回一維資料,這裡輸出為5個神經元的值
#全連接配接層
def fully_connected(input_layer,num_outputs):
#首先将資料轉化為一維向量,以實作每項連接配接到每個輸出
flat_input = tf.reshape(input_layer,[-1])
#建立w和b
#确定w和b的shape
#tf.shape得到資料的大小例如4*4的資料變為向量,則shape=16,
#tf.stack為矩陣拼接,設num_outputs = 5,則其結果為[[16],[5]]
#tf.squeeze降維,使其結果為[16,5]滿足shape輸入格式要求
weight_shape = tf.squeeze(tf.stack([tf.shape(flat_input),[num_outputs]]))
weight = tf.random_normal(shape=weight_shape,stddev=0.1)
bias = tf.random_normal(shape=[num_outputs])
#将資料轉化為2維以完成矩陣乘法
input_2d = tf.expand_dims(flat_input,0)
#進行計算y=wx+b
fully_output = tf.add(tf.matmul(input_2d,weight),bias)
#降維
fully_output_result = tf.squeeze(fully_output)
return fully_output_result
my_full_output = fully_connected(my_maxpool_output,num_outputs=5)
第7步:初始化變量并寫入計算圖中,然後列印出來
#初始化變量
init = tf.initialize_all_variables()
sess.run(init)
feed_dict = {x_input_2d:data_2d}
#列印各層
#卷積層
print('Input = [10 10] array')
print('Convolution [2,2],stride size = [2,2], results in the [5,5] array:')
print(sess.run(my_convolution_output,feed_dict=feed_dict))
#激活函數輸出
print('Input = the above [5,5] array ')
print('ReLU element wise returns the [5,5] array ')
print(sess.run(my_activation_output,feed_dict=feed_dict))
#池化層輸出
print('Input = the above [5,5] array ')
print('Maxpool,stride size = [1,1], results in the [4,4] array ')
print(sess.run(my_maxpool_output,feed_dict=feed_dict))
#全連接配接層輸出
print('Input = the above [4,4] array ')
print('Fully connected layer on all four rows with five outputs:')
print(sess.run(my_full_output,feed_dict=feed_dict))
下面是列印結果:
Input = [10 10] array
Convolution [2,2],stride size = [2,2], results in the [5,5] array:
[[ 1.32886136 -1.47333026 -1.44128537 -0.95050871 -1.80972886]
[-2.82501674 -0.35346282 -0.06931959 1.9739815 -0.84173405]
[ 0.5519557 -1.66942024 0.56509626 -2.68546128 0.71953934]
[-3.13675737 -1.81401241 1.47897935 -0.1665355 0.05618015]
[ 2.81271505 -4.40996552 -1.39324057 1.17697966 -2.26855183]]
Input = the above [5,5] array
ReLU element wise returns the [5,5] array
[[ 1.32886136 0. 0. 0. 0. ]
[ 0. 0. 0. 1.9739815 0. ]
[ 0.5519557 0. 0.56509626 0. 0.71953934]
[ 0. 0. 1.47897935 0. 0.05618015]
[ 2.81271505 0. 0. 1.17697966 0. ]]
Input = the above [5,5] array
Maxpool,stride size = [1,1], results in the [4,4] array
[[ 1.32886136 0. 1.9739815 1.9739815 ]
[ 0.5519557 0.56509626 1.9739815 1.9739815 ]
[ 0.5519557 1.47897935 1.47897935 0.71953934]
[ 2.81271505 1.47897935 1.47897935 1.17697966]]
Input = the above [4,4] array
Fully connected layer on all four rows with five outputs:
[-1.14044487 0.18718313 2.26356006 -0.60274446 0.6560365 ]