影象卷積的常見誤區與個人思考
theme: juejin
這是我參與2022首次更文挑戰的第2天,活動詳情檢視:2022首次更文挑戰
有一次我復現一個經典網路,為了保證程式碼的優美性,想省一個if-else
,因此想找一個特殊的模組,能將輸入原封不動地輸出。但是我也不知道什麼樣的模組具有這樣的功能,就在一個計算機交流群裡問了一下群友。
我:pytorch裡想讓輸入原封不動輸出應該用什麼模組呀
群友A:1*1的卷積核
我:萬一我輸入是多通道的呢
群友A:1*1*N唄
群友B:conv2d(input_ch, input_ch, 1),輸入輸出通道保持一致。但1*1有點類似全連線。
看到這裡,我已經開始笑了——看來大家跟我一樣,對這些基礎知識的理解並不是特別透徹。而除此之外,跟其他同學聊到卷積時,我也能感覺到卷積尤其是1*1
卷積是一個誤解的重災區。因此,今天打算把之前的思考整理下來,以便回顧。
卷積操作
卷積神經網路主要用於影象資料的處理,所以我們本次重點討論的是影象卷積。作為一個選修過訊號與系統課程的學生,我對卷積有著更原始、更初級,但也更準確的認識。對兩個函式的卷積操作可以理解為是對其中一個函式翻轉、移位,再測量它們之間的重疊。而在卷積神經網路中,卷積層嚴格來說是個錯誤的叫法,所謂卷積操作其實是互相關運算,而不是卷積,李沐老師在《動手學深度學習》中指出了這一點,本文暫且按下不表。
我們看下《動手學深度學習》中對二維卷積的定義:
在二維互相關運算中,卷積視窗從輸入張量的左上角開始,從左到右、從上到下滑動。 當卷積視窗滑動到新一個位置時,包含在該視窗中的部分張量與卷積核張量進行按元素相乘,得到的張量再求和得到一個單一的標量值,由此我們得出了這一位置的輸出張量值。
先從上面這個對話說起。
群友A最初的回覆1*1的卷積核
,乍一看是正確答案,因為對於一個單通道的輸入而言,1*1
的卷積核確實能保證不改變輸入。不過我很快反問多通道輸入的場景,群友的回覆是1*1*N
,另一位群友給出了程式碼和更準確的解釋,但這其實是不對的。
對於多通道的卷積,卷積核的層數要與輸入的層數一致,才能進行互相關運算,但是如果只有一個卷積核,那麼輸出的通道數就只會是1
,如果用1*1*N
的卷積核(濾波器),就相當於把輸入的N
個通道全部對應相加,最後得到了一個求和之後的單通道矩陣,而且這種損壞是不可逆的,我們也無法從中還原出輸入前的N
個通道各自的本來面貌。
卷積層與通道數的關係
進一步,按照群友所說的,輸入輸出通道數保持一致,這樣就需要多組卷積核。關於輸入通道與輸出通道,這其實是很多同學模糊不清的第一個地方。在卷積操作中,輸入通道數等於每個濾波器中卷積核的個數,輸出通道數等於濾波器的個數。
首先我們先看下卷積層的構成,如圖:
我們把中間核函式所對應的這部分稱為一個卷積層。在一個卷積層中包含單個或多個濾波器,而每個濾波器又有多層,所謂的卷積核個數,就是每個濾波器有多少層。在上圖中,每個濾波器中卷積核的個數為3
,濾波器的個數為2
,3
和2
也分別對應輸入通道數和輸出通道數。
回到群訊息,如果輸入輸出通道數保持一致,那麼則需要一個1*1*N*N
的濾波器,但問題在於,這N
個卷積核各自的值應該如何設定?如果全部設定成一樣的,那麼最終會把N
通道輸入變成N
個一模一樣的輸出,顯然是不正確的。不過我承認,如果N
個卷積核全部設定為不同值,只要濾波器中的值能構成一個N*N
的可逆矩陣,那麼是可以從輸出中將輸入反解出來的,但這樣就南轅北轍了。總之,想利用卷積操作將多通道的輸入原封不動地輸出是不可行的。
1*1卷積和全連線層有什麼關係
這又是一個容易誤解的地方,我見過不止一個人覺得1*1
卷積本質上就是全連線層。雖然是很基礎的問題,沒什麼意義,但既然都寫到這了,我還是順便把我的思考也記錄一下吧。
1*1
卷積和全連線層雖然沒什麼關係,但也有互通之處。全連線層可以用一種特殊的卷積層代替,假設輸入為7*7*512
,全連線層為長為4096
的向量,如果用卷積層來代替這個全連線層,則在該卷積層中:
- 有4096
個濾波器
- 每個濾波器有512
層(512
個卷積核)
- 每層的大小為7*7
這樣輸出的維度也是1*1*4096
,因此可以通過卷積層來實現該全連線運算。