歡迎大家前往騰訊雲+社群,獲取更多騰訊海量技術實踐乾貨哦~
本文由forrestlin發表於雲+社群專欄
導語:轉置卷積層(Transpose Convolution Layer)又稱反摺積層或分數卷積層,在最近提出的卷積神經網路中越來越常見了,特別是在對抗生成神經網路(GAN)中,生成器網路中上取樣部分就出現了轉置卷積層,用於恢復減少的維數。那麼,轉置卷積層和正卷積層的關係和區別是什麼呢,轉置卷積層實現過程又是什麼樣的呢,筆者根據最近的預研專案總結出本文。
1. 卷積層和全連線層
在CNN提出之前,我們所提到的人工神經網路應該多數情況下都是前饋神經網路,兩者區別主要在於CNN使用了卷積層,而前饋神經網路用的都是全連線層,而這兩個layer的區別又在於全連線層認為上一層的所有節點下一層都是需要的,通過與權重矩陣相乘層層傳遞,而卷積層則認為上一層的有些節點下一層其實是不需要的,所以提出了卷積核矩陣的概念,如果卷積核的大小是nm,那麼意味著該卷積核認為上一層節點每次對映到下一層節點都只有nm個節點是有意義的,具體的對映方式下一節會講到。到這裡,有些初學者會認為全連線層也可以做到,只要讓權重矩陣某些權重賦值為0就可以實現了,例如假設在計算當前層第2個節點時認為上一層的第1個節點我不需要,那麼設定w01=0就可以了。其實沒錯,卷積層是可以看做全連線層的一種特例,卷積核矩陣是可以展開為一個稀疏的包含很多0的全連線層的權重矩陣,下圖就是一個由44圖片經過33卷積核生成一個大小為2*2output時,卷積核所展開的全連線層的權重矩陣。
卷積核對應的全連線層權重矩陣
可以看到,上面的矩陣大小為416,比卷積核33大了不少,因此使用卷積層而不用全連線層第一個原因就是可以極大的減少引數的個數,第二個原因就是卷積核關注的是某幾個相鄰的節點之間的關係,學習了圖片的區域性特徵,可以說是帶有目的性的學習,例如33的卷積核學習的就是相互距離為2的節點之間的關係。這與全連線層無區別的對待所有節點進行學習有極大的差別,這樣一來就解決了前饋神經網路不能學習位移不變性的缺點。舉個例子,當我們在前饋神經網路中學習一個44的圖片中是否有橫折圖案時,使用下圖中4個訓練資料進行訓練,那麼最終只會對5,6,9,a這四個節點的權重有所調節,然後如果出現如下圖最後一張圖片作為測試時,就會導致網路無法識別,而由於卷積核在不同節點間權重是共享的,所以就自然而然克服了這個問題。
卷積克服平移不變性
2. 卷積層的運算過程
2.1 最簡單的卷積
卷積層的運算其實就是將多個卷積核作用於輸入上,如下圖所示,是最簡單的一個卷積核所做的運算,no padding,no stride,底下藍色方塊看做是輸入的圖片,陰影部分就是33的卷積核(一般卷積核是個正方形,且邊長為奇數),卷積核掃過時便與輸入相乘再相加,最終得到22的輸出,對應青色區域。
no padding, no stride的卷積
通常一層卷積層會包含多個卷積核,代表著卷積層的輸出深度,例如下圖就是我們經常在論文中看到的深度網路的架構,其中第一層就是卷積層+最大池化層,先不管最大池化層,至少我們可以明確卷積核的大小是55,卷積核個數是16,該層輸出的size是1818。
論文常見的卷積層
2.2 帶padding的卷積
從最簡單的卷積動圖中我們可以看到,經過卷積操作,輸出會比輸入要小,但是有時候我們希望輸出的size要與輸入保持一致,而padding就是為了這個而引入的,而這種為了讓輸入和輸出size保持一樣的padding,我們會稱之為”same padding”,可參考下面的動圖,卷積核大小是3*3,padding是1,padding實際的表現就是在輸入的四周補0,padding是多少就補多少層,且上限是卷積核大小-1,正如下圖中虛線區域,一般來說,論文中是不會給出padding的大小,需要我們自己推導,推導公式可見下文。
padding=1的卷積
根據padding大小不同,我們可以分為三種padding:
- same padding: 為了讓輸出和輸入的size一樣而補上的padding,例如33的核,same padding = 1,55的核,same padding = 2。
- full padding: padding = kernel size – 1
- valid padding: padding = 0
2.3 stride大於1的卷積
stride就是步長,表示卷積核兩次卷積操作的距離,預設是1,上述講的兩個例子步長都是1,而下面兩個動圖展示的是stride為2的情況,分別是無padding和有padding的情況。通常stride大於1時我們稱為等距下采樣,因為這樣輸出肯定會丟失資訊,size比輸入的小。
no padding, stride=2的卷積
padding=1, stride=2的卷積
2.4 卷積核輸入輸出size與卷積核的關係
上文中我們提到padding通常需要我們自己算出來,那麼我們該怎麼算呢,其實就是根據輸入輸出size和卷積核大小的關係算出來的,上面提到的幾種卷積,其實就是卷積操作的三個引數,核大小(F)、padding(P)和stride(S),如果細心的讀者在看動圖時就會發現輸出size是可以根據輸入size和那三個引數計算出來的,公式如下,這裡只給出寬度的計算,高度也是一樣的。
W2=(W1−F+2P)÷S+1
這裡我們注意到上面的公式是有除法的,所以就會存在除不盡的情況,這時候我們需要向下取整,這種情況我們稱為odd卷積,其過程可參考下面動圖。
odd卷積
3. 轉置卷積層
講完卷積層後,我們來看CNN中另一個進行卷積操作的層次轉置卷積層,有時我們也會稱做反摺積層,因為他的過程就是正常卷積的逆向,但是也只是size上的逆向,內容上不一定,所以有些人會拒絕將兩者混為一談。轉置卷積層最大的用途就是上取樣了,剛剛我們說到在正常卷積中stride大於1時我們進行的是等距下采樣,會讓輸出的size比輸入小,而轉置卷積層我們就會用stride小於1的卷積進行上取樣,使輸出的size變大,所以轉置卷積層還有個別稱就是分數卷積層。上取樣最常見的場景可以說就是GAN中的生成器網路,如下圖所示,雖然論文作者使用的是conv,但由於它的步長為1/2,所以代表的就是轉置卷積層。
轉置卷積例子
為了理解轉置卷積層,我們需要明白什麼叫做正常卷積的逆向,這通常也是新手難以理解的地方,下面筆者通過兩個圖來更好的解釋,第一個圖是正常卷積的過程,第二個圖就是其對應的轉置卷積,在第一個圖中,大的正方形中數字1只參與小正方形中數字1的計算,那麼在轉置卷積中,大正方形的1也只能由小正方形的1生成,這就是逆向的過程。
no padding, no stride的卷積
轉置卷積.png
和講述正常卷積的過程一樣,筆者下面也會一一給出相對應的轉置卷積。
3.1 no padding no stride的卷積對應的轉置卷積
上面用作解釋轉置卷積的逆向過程時用到的圖其實就是最簡單(no padding, no stride)卷積以及其對應的轉置卷積,這裡給出它的動圖。
no padding, no stride的卷積轉置
3.2 帶padding的卷積的轉置卷積
在正卷積中如果是有padding,那麼在轉置卷積中不一定會有padding,其計算公式下文會給出,這裡先給出2.2對應的轉置卷積動圖。
padding為1的卷積轉置
3.3 stride大於1的卷積的轉置卷積
在本節一開始就講到,stride大於1的卷積是下采樣,那麼其對應的轉置卷積便是stride小於1的上取樣,但是不管是在pyTorch還是TensorFlow中,convTranspose函式的引數都是整數,不可能將stride設定為小於1的浮點數,那麼我們會依然給convTranspose函式傳入正卷積的stride,而convTranspose是怎麼做的呢,可見下面的動圖,它是2.3中無padding卷積對應的轉置卷積,我們先不看轉置卷積中的轉置padding,也就是動圖中外部的虛線區域,然後會發現每兩個藍色塊之間都插入了白色塊,也就是0,這樣一來,卷積核每移動一步不就相當於是隻移動了1/2步嘛,所以我們可以得出每兩個藍色塊之間需要插入stride -1個0。
stride為2的卷積轉置
3.4 正卷積和轉置卷積的換算關係
3.4.1 轉置卷積的padding
從上面3個例子的轉置卷積中我們可以發現,如果用正卷積實現轉置卷積時,卷積核的大小是保持不變的,而stride是為正卷積stride的倒數(只是我們插入0來模擬分數移動),最後,轉置卷積的padding要怎麼算呢,雖然如果我們呼叫pyTorch或TensorFlow時不需要管,傳入正卷積的padding即可,但是理解convTranspose是怎麼做的也有助於我們理解轉置卷積。說了這麼多,其實在我們為了讓轉置卷積保證是正卷積的逆向時,我們就不得不補充轉置padding,我們用PT表示,其計算公式為:PT=F−P−1,其中F為正卷積的核大小,P為正卷積的padding。
3.4.2 轉置卷積的輸出size
這個其實很好算,因為我們都說轉置卷積的逆向,所以我們只需在2.4給出公式中轉換下求出W1即可,公式如下:
W1=(W2−1)×S−2P+F
其中S是正卷積的stride,P是正卷積的padding,F是正卷積的核邊長。
3.4.3 odd卷積的轉置卷積
這個可以說是轉置卷積中最難理解的一種情況,在2.4中我們提到在除以stride時可能會除不盡要向下取整,那麼我們在求W1時就會有不確定性,舉個例子,還是第3節一開始給出的圖,我們是希望將W/4的圖放大到W/2的程度,這是一個轉置卷積的過程,我們先算一遍正卷積,從W/2下采樣到W/4,k代表核邊長為3,s是stride為1/2的倒數,即2,padding根據2.4的公式推導為1,所以正卷積的計算公式是:(W2−3+2)÷2+1=W4+12,然後向下取整就是W4,和圖上顯示的是一樣,但是如果我們通過3.4.2的公式反過來計算,就是(W4−1)×2−2+3=W2−1,這就是odd轉置卷積的不確定性,我們再回頭看2.4給出的動圖,會發現右邊和下邊的填充區域我們並沒有進行卷積運算,因為向下取整而忽略了,所以我們在轉置卷積時需要將這部分加回來,因此,在PyTorch中convTranspose函式還有一個引數output_padding就是負責處理這個的,TensorFlow應該也有相應的引數,筆者不太熟悉,下面就是PyTorch對該引數的描述,和我們遇到的情形一模一樣。
PyTorch中轉置卷積的output_padding引數
至於output_padding的值,應該為(W1−F+2P)%S,在上面提到的例子中就應該是1。
4. 總結
本文先是介紹了卷積神經網路和傳統的前饋神經網路的聯絡和區別,然後再通過不同引數的卷積過程闡述卷積運算,最後再介紹剛入門深度學習時晦澀難懂的轉置卷積,給出不同引數下正卷積所對應的轉置卷積,最後總結出在卷積運算中所用到的公式。希望筆者上述的分析和解釋能對剛入門CNN的同學有所幫助,而且筆者是從事iOS開發的,對於CNN和深度學習也是剛剛入門,希望各位AI大牛們不吝指教。
5. 參考文件
- 知乎上對CNN的直觀解釋,平移不變性筆者是從這裡瞭解到的
- 《A guide to convolution arithmetic for deep learning》的github,本文的動圖都來自於此
- 關於轉置卷積和卷積的聯絡和區別
此文已由作者授權騰訊雲+社群釋出,更多原文請點選
搜尋關注公眾號「雲加社群」,第一時間獲取技術乾貨,關注後回覆1024 送你一份技術課程大禮包!
海量技術實踐經驗,盡在雲加社群!