一般用外部api進行卷積的時候,會面臨mode選擇。html
本文清晰展現三種模式的不一樣之處,其實這三種不一樣模式是對卷積核移動範圍的不一樣限制。api
設 image的大小是7x7,filter的大小是3x3網絡
1,full modeide
橙色部分爲image, 藍色部分爲filter。full模式的意思是,從filter和image剛相交開始作卷積,白色部分爲填0。filter的運動範圍如圖所示。函數
2,same mode學習
當filter的中心(K)與image的邊角重合時,開始作卷積運算,可見filter的運動範圍比full模式小了一圈。注意:這裏的same還有一個意思,卷積以後輸出的feature map尺寸保持不變(相對於輸入圖片)。固然,same模式不表明徹底輸入輸出尺寸同樣,也跟卷積核的步長有關係。same模式也是最多見的模式,由於這種模式能夠在前向傳播的過程當中讓特徵圖的大小保持不變,調參師不須要精準計算其尺寸變化(由於尺寸根本就沒變化)。spa
3.valid.net
當filter所有在image裏面的時候,進行卷積運算,可見filter的移動範圍較same更小了。
---------------------
做者:木盞
來源:CSDN
原文:https://blog.csdn.net/leviopku/article/details/80327478
版權聲明:本文爲博主原創文章,轉載請附上博文連接!3d
在深度學習的圖像識別領域中,咱們常常使用卷積神經網絡CNN來對圖像進行特徵提取,當咱們使用TensorFlow搭建本身的CNN時,通常會使用TensorFlow中的卷積函數和池化函數來對圖像進行卷積和池化操做,而這兩種函數中都存在參數padding,該參數的設置很容易引發錯誤,因此在此總結下。code
在弄懂padding規則前得先了解擁有padding參數的函數,在TensorFlow中,主要使用tf.nn.conv2d()進行(二維數據)卷積操做,tf.nn.max_pool()、tf.nn.avg_pool來分別實現最大池化和平均池化,經過查閱官方文檔咱們知道其須要的參數以下:
tf.nn.conv2d(input, filter, strides, padding, use_cudnn_on_gpu=None,name=None) tf.nn.max_pool_with_argmax(input, ksize, strides, padding, Targmax=None, name=None) tf.nn.max_pool(value, ksize, strides, padding, name=None)
這三個函數中都含有padding參數,咱們在使用它們的時候須要傳入所需的值,padding的值爲字符串,可選值爲'SAME' 和 'VALID' ;
padding參數的做用是決定在進行卷積或池化操做時,是否對輸入的圖像矩陣邊緣補0,'SAME' 爲補零,'VALID' 則不補,其緣由是由於在這些操做過程當中過濾器可能不能將某個方向上的數據恰好處理完,以下所示:
當步長爲5,卷積核尺寸爲6×6時,當padding爲VALID時,則可能形成數據丟失(如左圖),當padding爲SAME時,則對其進行補零(如右圖),
首先,定義變量:
輸入圖片的寬和高:i_w 和 i_h
輸出特徵圖的寬和高:o_w 和 o_h
過濾器的寬和高:f_w 和 f_h
寬和高方向的步長:s_w 和 s_h
寬和高方向總的補零個數:pad_w 和 pad_h
頂部和底部的補零個數:pad_top 和 pad_bottom
左部和右部的補零個數:pad_left 和 pad_right
1.VALID模式
輸出的寬和高爲
o_w = (i_w - f_w + 1)/ s_w #(結果向上取整) o_h = (i_h - f_h + 1)/ s_h #(結果向上取整)
2. SAME模式
輸出的寬和高爲
o_w = i_w / s_w#(結果向上取整) o_h = i_h / s_h#(結果向上取整)
各個方向的補零個數爲:max()爲取較大值,
pad_h = max(( o_h -1 ) × s_h + f_h - i_h , 0) pad_top = pad_h / 2 # 注意此處向下取整 pad_bottom = pad_h - pad_top pad_w = max(( o_w -1 ) × s_w + f_w - i_w , 0) pad_left = pad_w / 2 # 注意此處向下取整 pad_right = pad_w - pad_left
接下來咱們經過在TensorFlow中使用卷積和池化函數來分析padding參數在實際中的應用,代碼以下:
# -*- coding: utf-8 -*- import tensorflow as tf # 首先,模擬輸入一個圖像矩陣,大小爲5*5 # 輸入圖像矩陣的shape爲[批次大小,圖像的高度,圖像的寬度,圖像的通道數] input = tf.Variable(tf.constant(1.0, shape=[1, 5, 5, 1])) # 定義卷積核,大小爲2*2,輸入和輸出都是單通道 # 卷積核的shape爲[卷積核的高度,卷積核的寬度,圖像通道數,卷積核的個數] filter1 = tf.Variable(tf.constant([-1.0, 0, 0, -1], shape=[2, 2, 1, 1])) # 卷積操做 strides爲[批次大小,高度方向的移動步長,寬度方向的移動步長,通道數] # SAME op1_conv_same = tf.nn.conv2d(input, filter1, strides=[1,2,2,1],padding='SAME') # VALID op2_conv_valid = tf.nn.conv2d(input, filter1, strides=[1,2,2,1],padding='VALID') init = tf.global_variables_initializer() with tf.Session() as sess: sess.run(init) print("op1_conv_same:\n", sess.run(op1_conv_same)) print("op2_conv_valid:\n", sess.run(op2_conv_valid))
VALID模式的分析:
SAME模式分析:
o_w = i_w / s_w = 5/2 = 3 o_h = i_h / s_h = 5/2 = 3 pad_w = max ( (o_w - 1 ) × s_w + f_w - i_w , 0 ) = max ( (3 - 1 ) × 2 + 2 - 5 , 0 ) = 1 pad_left = 1 / 2 =0 pad_right = 1 - 0 =0 # 同理 pad_top = 0 pad_bottom = 1
運行代碼後的結果以下:
這裏主要分析最大池化和平均池化兩個函數,函數中padding參數設置和矩陣形狀計算都與卷積同樣,但須要注意的是:
1. 當padding='SAME',計算avg_pool時,每次的計算是除以圖像被filter框出的非零元素的個數,而不是filter元素的個數,以下圖,第一行第三列咱們計算出的結果是除以2而非4,第三行第三列計算出的結果是除以1而非4;
2. 當計算全局池化時,即與圖像矩陣形狀相同的過濾器進行一次池化,此狀況下無padding,即在邊緣沒有補0,咱們直接除以整個矩陣的元素個數,而不是除以非零元素個數(注意與第一點進行區分)
池化函數的代碼示例以下:
# -*- coding: utf-8 -*- import tensorflow as tf # 首先,模擬輸入一個特徵圖,大小爲5*5 # 輸入圖像矩陣的shape爲[批次大小,圖像的高度,圖像的寬度,圖像的通道數] input = tf.Variable(tf.constant(1.0, shape=[1, 5, 5, 1])) # 最大池化操做 strides爲[批次大小,高度方向的移動步長,寬度方向的移動步長,通道數] # ksize爲[1, 池化窗口的高,池化窗口的寬度,1] # SAME op1_max_pooling_same = tf.nn.max_pool(input, [1,2,2,1], strides=[1,2,2,1],padding='SAME') # VALID op2_max_pooling_valid = tf.nn.max_pool(input, [1,2,2,1], strides=[1,2,2,1],padding='VALID') # 平均池化 op3_avg_pooling_same = tf.nn.avg_pool(input, [1,2,2,1], strides=[1,2,2,1],padding='SAME') # 全局池化,filter是一個與輸入矩陣同樣大的過濾器 op4_global_pooling_same = tf.nn.avg_pool(input, [1,5,5,1], strides=[1,5,5,1],padding='SAME') init = tf.global_variables_initializer() with tf.Session() as sess: sess.run(init) print("op1_max_pooling_same:\n", sess.run(op1_max_pooling_same)) print("op2_max_pooling_valid:\n", sess.run(op2_max_pooling_valid)) print("op3_max_pooling_same:\n", sess.run(op3_avg_pooling_same)) print("op4_global_pooling_same:\n", sess.run(op4_global_pooling_same))
運行結果以下:
在搭建CNN時,咱們輸入的圖像矩陣在網絡中須要通過多層卷積和池化操做,在這個過程當中,feature map的形狀會不斷變化,若是不清楚padding參數引發的這些變化,程序在運行過程當中會發生錯誤,固然在實際寫代碼時,能夠將每一層feature map的形狀打印出來,瞭解每一層Tensor的變化。
轉載請註明出處:https://www.cnblogs.com/White-xzx/p/9497029.html