1. 程式人生 > >輕鬆理解轉置卷積(transposed convolution)/反捲積(deconvolution)

輕鬆理解轉置卷積(transposed convolution)/反捲積(deconvolution)

原文地址:Up-sampling with Transposed Convolution


在CNN中,轉置卷積是一種上取樣(up-sampling)的方法.如果你對轉置卷積感到困惑,那麼就來讀讀這篇文章吧.

本文的notebook程式碼在Github.

上取樣的需要

在我們使用神經網路的過程中,我們經常需要上取樣(up-sampling)來提高低解析度圖片的解析度.

這裡寫圖片描述

上取樣有諸多方法,舉例如下.

  • 最近鄰插值(Nearest neighbor interpolation)
  • 雙線性插值(Bi-linear interpolation)
  • 雙立方插值(Bi-cubic interpolation)

但是, 上述的方法都需要插值操作, 而這些插值的操作都充滿了人為設計和特徵工程的氣息, 而且也沒有網路進行學習的餘地.

為何需要轉置卷積

如果我們想要網路去學出一種最優的上取樣方法,我們可以使用轉置卷積.它與基於插值的方法不同,它有可以學習的引數.

若是想理解轉置卷積這個概念, 可以看看它是如何運用於在一些有名的論文和專案中的.

  • DCGAN的生成器(generator)接受一些隨機取樣的值作為輸入來生成出完整的圖片. 它的語義分割(semantic segmentation)就使用了卷積層來提取編碼器(encoder)中的特徵, 接著,它把原圖儲存在解碼器(decoder)中以確定原圖中的每個畫素的類別歸屬.

  • FYI.

轉置卷積也被稱作: “分數步長卷積(Fractionally-strided convolution)”和”反捲積(Deconvolution)”.
我們在這篇文章裡面只使用轉置卷積這個名字,其他文章可能會用到其他名字. 這些名字指的都是同樣的東西.

卷積操作

我們先通過一個簡單的例子來看看卷積是怎麼工作的.

假設我們有一個4x4的input矩陣, 並對它使用核(kernel)為3x3,沒有填充(padding),步長(stride)為1的卷積操作. 結果是一個2x2的矩陣,如下圖所示.

這裡寫圖片描述

(譯者注: stride,kernel,padding等詞以下記為英文)

卷積操作的本質其實就是在input矩陣和kernel矩陣之間做逐元素(element-wise)的乘法然後求和. 因為我們的stride為1,不使用padding,所以我們只能在4個位置上進行操作.

這裡寫圖片描述

要點:卷積操作其實就是input值和output值的位置性關係(positional connectivity).

例如,在input矩陣的左上角的值會影響output矩陣的左上角的值.

更進一步,3x3的核建立了input矩陣中的9個值和output矩陣中的1個值的關係.

“卷積操作建立了多對一的關係”. 在閱讀下文時,請讀者務必時刻牢記這個概念.

卷積的逆向操作

現在,考慮一下我們如何換一個計算方向. 也就是說,我們想要建立在一個矩陣中的1個值和另外一個矩陣中的9個值的關係.這就是像在進行卷積的逆向操作,這就是轉置卷積的核心思想.

(譯者注:從資訊理論的角度看,卷積是不可逆的.所以這裡說的並不是從output矩陣和kernel矩陣計算出原始的input矩陣.而是計算出一個保持了位置性關係的矩陣.)

這裡寫圖片描述

但是,我們如何進行這種逆向操作呢?

為了討論這種操作,我們先要定義一下卷積矩陣和卷積矩陣的轉置.

卷積矩陣

我們可以將卷積操作寫成一個矩陣. 其實這就是重新排列一下kernel矩陣, 使得我們通過一次矩陣乘法就能計算出卷積操作後的矩陣.

這裡寫圖片描述

我們將3x3的kernel重排為4x16的矩陣,如下:

這裡寫圖片描述

這就是卷積矩陣. 每一行都定義了一次卷積操作. 如果你還看不透這一點, 可以看看下面的圖. 卷積矩陣的每一行都相當於經過了重排的kernel矩陣,只是在不同的位置上有zero padding罷了.

這裡寫圖片描述

為了實現矩陣乘法,我們需要將尺寸為4x4的input矩陣壓扁(flatten)成一個尺寸為16x1的列向量(column vector).

這裡寫圖片描述

然後,我們對4x16的卷積矩陣和1x16的input矩陣(就是16維的列向量,只是看成一個矩陣)進行矩陣乘法.
這裡寫圖片描述
尺寸為4x1的output矩陣可以重排為2x2的矩陣.這正和我們之前得到的結果一致.

這裡寫圖片描述

一句話,一個卷積矩陣其實就是kernel權重的重排,一個卷積操作可以被寫成一個卷積矩陣.

即便這樣又如何呢?

我想說的是: 使用這個卷積矩陣,你可以把16(4x4的矩陣)個值對映為4(2x2的矩陣)個值. 反過來做這個操作,你就可以把4(2x2的矩陣)個值對映為16(4x4的矩陣)辣.

蒙了?

繼續讀.

轉置過後的卷積矩陣

我們想把4(2x2的矩陣)個值對映為16(4x4的矩陣)個值. 但是,還有一件事! 我們需要維護1對9的關係.

假設我們轉置一下卷積矩陣C(4x16),得到C.T(16x4). 我們可以將C.T(16x4)和一個列向量(4x1)以矩陣乘法相乘,得到尺寸為16x1的output矩陣. 轉置之後的矩陣建立了1個值對9個值的關係.

這裡寫圖片描述

output矩陣可以被重排為4x4的.
這裡寫圖片描述
我們已經上取樣了一個小矩陣(2x2),得到了一個大矩陣(4x4). 轉置卷積依然維護著1對9的關係: 因為權重就是這麼排的.

注意:用來進行轉置卷積的權重矩陣不一定來自於(come from)原卷積矩陣. 重點是權重矩陣的形狀和轉置後的卷積矩陣相同.

總結

轉置卷積和普通卷積有相同的本質: 建立了一些值之間的關係. 只不過,轉置卷積所建立的這個關係與普通卷積所建立的關係,方向相反.

我們可以使用轉置卷積來進行上取樣. 並且,轉置卷積中的權重是可以被學習的. 因此,我們沒有必要搞什麼插值方法來做上取樣.

儘管它被稱作轉置卷積, 但是這並不意味著我們是拿一個已有的卷積矩陣的轉置來作為權重矩陣的來進行轉置卷積操作的. 和普通卷積相比,intput和output的關係被反向處理(轉置卷積是1對多,而不是普通的多對1),才是轉置卷積的本質.

正因如此,嚴格來說轉置卷積其實並不算卷積.但是我們可以把input矩陣中的某些位置填上0並進行普通卷積來獲得和轉置卷積相同的output矩陣. 你可以發現有一大把文章說明如何使用這種方法實現轉置卷積. 然而, 因為需要在卷積操作之前,往input中填上許多的0,這種方法其實有點效率問題.

警告:轉置卷積會在生成的影象中造成棋盤效應(checkerboard artifacts).本文推薦在使用轉置卷積進行上取樣操作之後再過一個普通的卷積來減輕此類問題.如果你主要關心如何生成沒有棋盤效應的影象,需要讀一讀paper.

References

[1] A guide to convolution arithmetic for deep learning
Vincent Dumoulin, Francesco Visin

https://arxiv.org/abs/1603.07285

[2] Unsupervised Representation Learning with Deep Convolutional Generative Adversarial Networks
Alec Radford, Luke Metz, Soumith Chintala

https://arxiv.org/pdf/1511.06434v2.pdf

[3] Fully Convolutional Networks for Semantic Segmentation
Jonathan Long, Evan Shelhamer, Trevor Darrell

https://people.eecs.berkeley.edu/~jonlong/long_shelhamer_fcn.pdf

[4] Deconvolution and Checkerboard Artifacts
Augustus Odena, Vincent Dumoulin, Chris Olah

https://distill.pub/2016/deconv-checkerboard/