影象卷積的常見誤區與個人思考

語言: CN / TW / HK

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卷積是一個誤解的重災區。因此,今天打算把之前的思考整理下來,以便回顧。

卷積操作

卷積神經網路主要用於影象資料的處理,所以我們本次重點討論的是影象卷積。作為一個選修過訊號與系統課程的學生,我對卷積有著更原始、更初級,但也更準確的認識。對兩個函式的卷積操作可以理解為是對其中一個函式翻轉、移位,再測量它們之間的重疊。而在卷積神經網路中,卷積層嚴格來說是個錯誤的叫法,所謂卷積操作其實是互相關運算,而不是卷積,李沐老師在《動手學深度學習》中指出了這一點,本文暫且按下不表。

我們看下《動手學深度學習》中對二維卷積的定義:

在二維互相關運算中,卷積視窗從輸入張量的左上角開始,從左到右、從上到下滑動。 當卷積視窗滑動到新一個位置時,包含在該視窗中的部分張量與卷積核張量進行按元素相乘,得到的張量再求和得到一個單一的標量值,由此我們得出了這一位置的輸出張量值。

Untitled.png

先從上面這個對話說起。

群友A最初的回覆1*1的卷積核,乍一看是正確答案,因為對於一個單通道的輸入而言,1*1的卷積核確實能保證不改變輸入。不過我很快反問多通道輸入的場景,群友的回覆是1*1*N,另一位群友給出了程式碼和更準確的解釋,但這其實是不對的。

對於多通道的卷積,卷積核的層數要與輸入的層數一致,才能進行互相關運算,但是如果只有一個卷積核,那麼輸出的通道數就只會是1,如果用1*1*N的卷積核(濾波器),就相當於把輸入的N個通道全部對應相加,最後得到了一個求和之後的單通道矩陣,而且這種損壞是不可逆的,我們也無法從中還原出輸入前的N個通道各自的本來面貌。

Untitled1.png

卷積層與通道數的關係

進一步,按照群友所說的,輸入輸出通道數保持一致,這樣就需要多組卷積核。關於輸入通道與輸出通道,這其實是很多同學模糊不清的第一個地方。在卷積操作中,輸入通道數等於每個濾波器中卷積核的個數,輸出通道數等於濾波器的個數。

首先我們先看下卷積層的構成,如圖:

Untitled2.png

我們把中間核函式所對應的這部分稱為一個卷積層。在一個卷積層中包含單個或多個濾波器,而每個濾波器又有多層,所謂的卷積核個數,就是每個濾波器有多少層。在上圖中,每個濾波器中卷積核的個數為3,濾波器的個數為232也分別對應輸入通道數和輸出通道數。

回到群訊息,如果輸入輸出通道數保持一致,那麼則需要一個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,因此可以通過卷積層來實現該全連線運算。