天天看點

TensorFlow實作卷積層和池化層

這裡我們将介紹如何實作常見的卷積層和池化層

這裡我們以二維資料為例進行介紹

第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 ]

繼續閱讀