你的 ResNet 是時候更新了
作者簡介
CW,廣東深圳人,畢業於中山大學(SYSU)資料科學與計算機學院,畢業後就業於騰訊計算機系統有限公司技術工程與事業群(TEG)從事Devops工作,期間在AI LAB實習過,實操過道路交通元素與醫療病例影像分割、視訊實時人臉檢測與表情識別、OCR等專案。
目前也有在一些自媒體平臺上參與外包專案的研發工作,專案專注於CV領域(傳統影像處理與深度學習方向均有)。
前言
趕在4月末,終於有時間寫文了,最近工作上需求比較急,抽不出時間來更文,但我心早已狂熱!在我敲上這行字的過程中,真的很開心,因為真心很享受這種靜靜地碼字向別人分享知識的時光(雖然不知道有沒有人看..)。如今就為大家奉上這個新鮮出爐的新品 —— ResNeSt!
文末可獲取相關Paper&原始碼連結
你沒看錯,是 ResNeSt 而不是 ResNet 喲!這是張航、李沐等大佬創造的 ResNet 改進版,在引數量沒有顯著增加的情況下顯著提升了效能,並且可以很方便地如 ResNet 般整合到現有演算法框架中。通過本文,我們就一起來看看它有多香吧!
Outline
I. 主要思想
II. 分組的通道注意力機制:Split-Attention
III. 從程式碼出發,知行合一
1
基本思想
ResNeSt 很好懂,不復雜,簡單來說就是結合了 ResNeXt 的分組卷積和 SE-Net 的通道注意力機制,將通道進行分組,對每組運用注意力機制,同時保留了 ResNet 的殘差結構。
2
分組的通道注意力機制:Split-Attention
SplAtConv2d
這部分我們來詳談分組的通道注意力是怎樣一種操作,作者論述到可能的實現方式有多種,這裡我先談談其中一種。
瞭解 ResNeXt 的朋友們都知道,其引入了 Cardinality 的概念,代表分組的組數,為方便敘述,這裡記為 K;ResNeSt 則在此基礎上進一步分組,稱為 split 操作,同時引入一個超參 Radix,代表將 K 個組中的每一個進一步劃分的組數,這裡記為 R。這裡的分組都是在通道這個維度上進行,由此看來,就是將輸入在通道這個維度劃分為 KxR 個組。
分組完畢後,對每個組實施不同的特徵變換(Conv+Bn+Relu 等),然後將它們分成 R 份,這樣每份就包含原來的 K 個組,對每一份應用投票機制形成注意力(Softmax or Sigmoid),接著將這 R 份注意力與特徵圖對應相乘(element-wise multiply),最後將這 R 份結果加起來(element-wise sum)形成輸出,輸出相當於對應了原來的 K 個組。
梳理下,可以知道注意力在是分了 K 個組後再分R個組上執行的,記 R 中的每一份為 r,K 中的每一份為k,那麼每個 r 上得到的注意力是不同的,即每個 k split 下的每個 r 上的注意力不同,而同一個 r 下對應的不同 k 的注意力是一致的。
很奇妙,對於分得的K個組,每個組內切分R份分配不同的注意力,但不同組依次對應的這R份注意力卻分別是一致的,是謂同又不盡全同!
3
從程式碼出發,知行合一
看過 paper 和原始碼的朋友們可能會一頭霧水,paper 中展示的結構圖和程式碼實現的有出入,一開始 CW 也是如此,看了幾篇文但總感覺自己理解得依舊不那麼清晰,於是乎親自把程式碼手擼一遍,並結合畫圖理解,最終眼前的迷霧也就散開了。
我國古代優秀大佬王陽明推崇知行合一,雖然凡事不一定硬要知行結合,但是吾以為有了認知才有“行”的方向,“行”了才能加深認知或者說真正認知,這是一個迴圈,最終達到合二為一的高手境界。
接下來進入正題~
作者在原始碼中對於 split attention 的實現有兩種方式,分別對應兩個類,其中一個類為 SplAtConv2d,對應於上一部分展示的圖中結構;另一個類為 RadixMajorNaiveImp,對應下圖中的結構。
RadixMajorNaiveImp
RadixMajorNaiveImp
結合上圖和程式碼,先來看看 RadixMajorNaiveImp 具體如何實現。
首先將輸入分為 KxR 個組,然後依次對K中的每個 k 執行注意力機制,具體做法是取出同一個 k 下的所有 r,然後把它們加起來,輸入全域性平均池化層和兩層全連線層。
RadixMajorNaiveImp (i)
接著令通道這個維度等於 R,在這個維度上生成注意力權重,同時,將同一 k 下的所有 r 在通道這個維度上拼接起來,與注意力權重相乘,相乘後的結果分為 R 份,將這 R 份結果加起來形成這一個 k 的輸出,最終將K組中所有 k 的結果在通道數這個維度上拼接起來。
RadixMajorNaiveImp (ii)
總的來說,這種方式就是依次對 K 組中的每份 k 進行處理,每份 k 進一步 split 成 R 份,其中每份 r 生成不同的注意力,K 組中的每份 k 都結合完注意力後,再將它們的結果在通道上拼接起來。
SplAtConv2d
接下來看看 SplAtConv2d 的實現方式。
SplAtConv2d
仔細觀察上圖,我們可以發現,這種實現方式是將輸入分為 R 份,其中的每份 r 包含了 K 個組,每份 r 生成的注意力不同(對應上圖中的虛線框),上一節便說到了,同一 k 下 不同的 split r 上形成的注意力不一致,但不同的 k 對應相同的 r 上形成的注意力卻是一致的。
再回顧下 RadixMajorNaiveImp 的實現方式,同一 k 下 不同的 split r 上形成的注意力也是不一致,但不同 k 的注意力是獨立生成的,它們之間並沒有聯絡,這就是兩種實現方式的最大差別了。
一起來瞄瞄程式碼~
SplAtConv2d (i)
這裡提醒大家注意下,訓練過程中在測試這個模組時,記住把 batch size 設定大於1,由於使用了 global average pooling,輸出特徵的大小變為1x1,因此其後接 bn 的話(上圖中 self.bn1)就要求每個通道上多於一個元素,而如果 batch size 為1的話就會報錯了:
ValueError: Expected more than 1 value per channel when training
bn 是在每個通道上(channel-wise)做歸一化的,如果通道上只有1個元素,那麼歸一化就無意義了,所以在訓練過程中, bn 要求每個通道上必須多於1個元素。
SplAtConv2d (ii)
另外,SplAtConv2d 這種實現方式不需要依次對 K 組中的每份進行處理,而是直接對 K 個組同時進行處理,相比於 RadixMajorNaiveImp 的方式更加簡潔些。
作者在 paper 和 github 原始碼中也給出了兩者等價性的證明,原始碼可以檢視《SplAtConv2d 和 RadixMajorNaiveImp 的等價性證明》,連結:https://github.com/zhanghang1989/ResNeSt/blob/master/tests/test_radix_major.py#L100
4
最後
對於 ResNeSt, 初次接觸時往往會感覺其程式碼實現和paper描述得有出入,因此要把它講述明白,自己本身一定要理解得透徹。如果沒有親自敲過一遍程式碼,就很難做到。對於其它演算法模型也一樣,能真正掌握的辦法就是親自上陣實踐一番,所謂知而不行,乃是未知。
深藍學院 發起了一個讀者討論對於這個新的ResNeSt有什麼想法呢?趕快參與【讀者討論】,與筆者溝通交流吧!
【參考】
原始碼連結:
https://github.com/zhanghang1989/ResNeSt
https://github.com/zhanghang1989/ResNeSt/blob/master/tests/test_radix_major.py#L100
相關文章
- AndroidUtilCodeKTX !是時候提升你的開發效率了 !(持續更新中...)Android
- 是時候更新手裡的武器了—Jetpack最全簡析Jetpack
- 是時候,升級你的 Windows 了「GitHub 熱點速覽」WindowsGithub
- 是時候擁有一個你自己的命令列工具了命令列
- WebSocket是時候展現你優秀的一面了Web
- DrawIO 二開 —— 是時候給你的 ProcessOn 充值終身 VIP 了
- 是時候開發你自己的vscode擴充套件外掛了VSCode套件
- 你的專案剛剛啟動?是時候考慮Globalization了!
- 🚀提升生產力:是時候升級你的命令列工具了命令列
- 是時候給你的產品配一個AI問答助手了!AI
- 2024, 是時候告別CentOS了CentOS
- 是時候扔掉 Postman 了,Apifox 真香!PostmanAPI
- 你覺得你每天最佳的工作時間是什麼時候?
- 是時候學習真正的 spark 技術了Spark
- 是時候優雅的和NullPointException說再見了NullException
- 是時候來了解下 HTTPS 網站的部署了HTTP網站
- 【Android Adapter】是時候開啟Adapter新時代了AndroidAPT
- 是時候放棄 el-form 元件了ORM元件
- 是時候重新審視AB測試了
- “懶癌”患者福音:是時候找一個AI幫你做家務了AI
- 當你感到絕望時,可能是最接近成功的時候
- 《糖豆人》--是時候談談它的未來了
- 對DevOps的九大誤解,是時候糾正了!dev
- 是時候為Spring Boot 3.0做準備了Spring Boot
- 非智慧WAF,是時候轉身離場了
- 6 歲!是時候重新認識下 Serverless 了Server
- 6歲!是時候重新認識下Serverless了Server
- 你是什麼時候”突然”學會程式設計的程式設計
- 是時候談談JavaScript物件導向了!(我們什麼時候更需要它)JavaScript物件
- <span>得瑟的時候就是你要倒黴的時候。</span>
- 無伺服器時代:是時候做 Cloud Right 了 - Wardley伺服器Cloud
- 是時候捋一捋 Java 的深淺複製了Java
- 都8102年了!是時候有個新的狀態容器取代redux了!Redux
- 德勤:是時候認真對待資料了
- 《榮譽勳章》系列是時候重回戰場了
- 為什麼說是時候擁抱.NET CORE了?
- 還在學iOS?是時候學習Flutter了(二)iOSFlutter
- APK瘦身-是時候給App進行減負了APKAPP