1. 程式人生 > >個人總結:關於tf.nn.conv2d(卷積)與tf.nn.conv2d_transpose(反捲積)的區別

個人總結:關於tf.nn.conv2d(卷積)與tf.nn.conv2d_transpose(反捲積)的區別

官網中對於卷積tf.nn.conv2d的描述

tf.nn.conv2d(
    input,
    filter,
    strides,
    padding,
    use_cudnn_on_gpu=True,
    data_format='NHWC',
    dilations=[1, 1, 1, 1],
    name=None
)

對於反捲積tf.nn.conv2d_transpose的描述

tf.nn.conv2d_transpose(
    value,
    filter,
    output_shape,
    strides,
    padding='SAME',
    data_format='NHWC',
    name=None
)

注意要點:

關於tf.nn.conv2d:

  1. tf.nn.conv2d的input的shape,假設為[A, B, C, D]。那filter的shape一定為[K, K, D, E],其中A為batch_size, D為輸入的channel,K為感受野大小,E為輸出的channel。
  2. strides如果為[1, 1, 1, 1]。(strides如果改變的話只能改中間兩個數,例如改為[1, 2, 2, 1]此時strides為2)。同時padding為same的時候輸出的大小不發生改變。(padding為same指的是在輸入維度不夠的情況下進行補0,若為valid的話在輸入維度不夠的情況下將未卷積的部分直接捨棄。
    更詳細的內容請翻看其他部落格,這裡不再贅述。)
  3. dilation指的是空洞卷積,預設為1。關於空洞卷積可以檢視知乎上大佬的https://www.zhihu.com/question/54149221/answer/192025860 我認為還是比較容易理解。

關於tf.nn.conv2d_transpose:

  1. 這也是想寫這篇博文的原因。提醒自己不要再犯相同的錯誤。conv2d_transpose顧名思義其實本質上是轉置卷積,所以它和卷積一定有一些細微的差別。在tensorflow中,若value為[A, B, C, D],D為輸入的channel。則它的filter為[A, F, E, D],其中D為輸入channel,此時與前面conv2d就有了差別,這個地方就體現了所謂的transpose。
    E為output_shape所決定的輸出的channel,F與strides有關。
  2. 為什麼一定要有output_channel呢。這是因為假如卷積之前我的兩個輸入的維度分別為[batch_size, 10, 10, 3], [batch_size, 9, 9, 3], 我採用padding=same, strides = [1, 2, 2, 1]的方式, 卷積後得到的維度竟然是相同的[batch_size, 5, 5, output_channels]!這時你就明白為什麼我們在反捲積的時候需要輸入我們想要得到的維度output_shape了吧。
  3. 一定要區分清楚卷積tf.nn.conv2d與反捲積tf.nn.conv2d_transpose的strides,它和卷積的strides是相反的,怎麼理解呢?可以這麼說,卷積的strides是在前向傳播時使用,而反捲積的strides在反向傳播時使用。假設A[batch_size, 32, 32, chan_1]通過stride[1, 2, 2, 1], padding = SAME, 卷積的結果變為了B[batch_size, 16, 16, chan_2]. 這個時候前向傳播,卷積的stride為2. 當使用反捲積時,若A[batch_size, 32, 32, chan_1],stride[1, 2, 2, 1],則反捲積的結果變成了C[batch_size, 64, 64, chan_2],這是因為這個時候我們要從反向傳播的角度去看,從C[batch_size, 64, 64, chan_2]採用stride[1, 2, 2, 1]卷積為了A[batch_size, 32, 32, chan_1]!

PS:寫在最後,這些個人總結估計沒有親身去體驗過的人,初學者很難看明白,不過算是一些小tip吧,因為在tensorflow中稍不留神一個引數錯了就可能需要找很久的bug,還是希望閱讀到的人能看明白少走點彎路吧,如果有問題的話可以評論,我一定會回覆的。