Date: 2020/04/30 夜晚 ~?2020/05/01 凌晨
Author: CW
前言:
趕在月末暑竟,終于有時(shí)間寫文了,最近工作上需求比較急育勺,抽不出時(shí)間來簡(jiǎn)書更文但荤,但我心早已狂熱!在我敲上這行字的時(shí)候涧至,真的很開心腹躁,因?yàn)檎嫘暮芟硎苓@種靜靜地碼字向別人分享學(xué)習(xí)心得的時(shí)光(雖然不知道有沒有人看..)。OK南蓬,廢話不多說纺非,如今就為大家奉上這個(gè)新鮮出爐的新品 —— ResNeSt!
你沒看錯(cuò)赘方,是 ResNeSt 而不是 ResNet 喲烧颖!這是張航、李沐等大佬創(chuàng)造的 ResNet 改進(jìn)版窄陡,在參數(shù)量沒有顯著增加的情況下顯著提升了性能炕淮,并且可以很方便地如 ResNet 般集成到現(xiàn)有模型中。通過本文泳梆,我們就一起來看看它有多香吧鳖悠!
Outline
I. 主要思想
II. 分組的通道注意力機(jī)制:Split-Attention
III. 從代碼出發(fā),知行合一
主要思想
ResNeSt 很好懂优妙,不復(fù)雜,簡(jiǎn)單來說就是結(jié)合了 ResNeXt 的分組卷積和 SE-Net 的通道注意力機(jī)制憎账,將通道進(jìn)行分組套硼,對(duì)每組運(yùn)用注意力機(jī)制,同時(shí)保留了 ResNet 的殘差結(jié)構(gòu)胞皱。
分組的通道注意力機(jī)制:Split-Attention
這部分我們來詳談分組的通道注意力是怎樣一種操作邪意,作者論述到可能的實(shí)現(xiàn)方式有多種,這里我先談?wù)勂渲幸环N反砌。
了解 ResNeXt 的朋友們都知道雾鬼,其引入了 Cardinality 的概念,代表分組的組數(shù)宴树,為方便敘述策菜,這里記為 K;ResNeSt 則在此基礎(chǔ)上進(jìn)一步分組,稱為 split 操作又憨,同時(shí)引入一個(gè)超參 Radix翠霍,代表將 K 個(gè)組中的每一個(gè)進(jìn)一步劃分的組數(shù),這里記為 R蠢莺。這里的分組都是在通道這個(gè)維度上進(jìn)行寒匙,由此看來,就是將輸入在通道這個(gè)維度劃分為 KxR 個(gè)組躏将。
分組完畢后锄弱,對(duì)每個(gè)組實(shí)施不同的特征變換(Conv+Bn+Relu 等),然后將它們分成 R 份祸憋,這樣每份就包含原來的 K 個(gè)組棵癣,對(duì)每一份應(yīng)用投票機(jī)制形成注意力(Softmax or Sigmoid),接著將這 R 份注意力與特征圖對(duì)應(yīng)相乘(element-wise multiply)夺衍,最后將這 R 份結(jié)果加起來(element-wise sum)形成輸出狈谊,輸出相當(dāng)于對(duì)應(yīng)了原來的 K 個(gè)組。
梳理下沟沙,可以知道注意力在是分了 K 個(gè)組后再分R個(gè)組上執(zhí)行的河劝,記 R 中的每一份為 r,K 中的每一份為k矛紫,那么每個(gè) r 上得到的注意力是不同的赎瞎,即每個(gè) k split 下的每個(gè) r 上的注意力不同,而同一個(gè) r 下對(duì)應(yīng)的不同 k 的注意力是一致的颊咬。
很奇妙务甥,對(duì)于分得的K個(gè)組,每個(gè)組內(nèi)切分R份分配不同的注意力喳篇,但不同組依次對(duì)應(yīng)的這R份注意力卻分別是一致的敞临,是謂同又不盡全同!
從代碼出發(fā)麸澜,知行合一
看過 paper 和源碼的朋友們可能會(huì)一頭霧水挺尿,paper 中展示的結(jié)構(gòu)圖和代碼實(shí)現(xiàn)的有出入,一開始 CW 也是如此炊邦,看了幾篇文但總感覺自己理解得依舊不那么清晰编矾,于是乎親自把代碼手?jǐn)]一遍,并結(jié)合畫圖理解馁害,最終眼前的迷霧也就散開了窄俏。
我國古代優(yōu)秀大佬王陽明推崇知行合一,雖然凡事不一定硬要知行結(jié)合碘菜,但是吾以為有了認(rèn)知才有“行”的方向凹蜈,“行”了才能加深認(rèn)知或者說真正認(rèn)知限寞,這是一個(gè)循環(huán),最終達(dá)到合二為一的高手境界踪区。
(⊙o⊙)… sorry昆烁,裝b裝過頭了,接下來進(jìn)入正題缎岗。
作者在源碼中對(duì)于 split attention 使用了兩個(gè)類對(duì)應(yīng)兩種實(shí)現(xiàn)方式静尼,其中一個(gè)類為 SplAtConv2d,對(duì)應(yīng)于上一部分展示的圖中結(jié)構(gòu)传泊;另一個(gè)類為 RadixMajorNaiveImp鼠渺,對(duì)應(yīng)下圖中的結(jié)構(gòu)。
RadixMajorNaiveImp
結(jié)合上圖和代碼眷细,先來看看 RadixMajorNaiveImp 具體如何實(shí)現(xiàn)拦盹。
首先將輸入分為 KxR 個(gè)組,然后依次對(duì)K中的每個(gè) k 執(zhí)行注意力機(jī)制溪椎,具體做法是取出同一個(gè) k 下的所有 r普舆,然后把它們加起來,輸入全局平均池化層和兩層全連接層校读。
接著令通道這個(gè)維度等于 R沼侣,在這個(gè)維度上生成注意力權(quán)重,同時(shí)歉秫,將同一 k 下的所有 r 在通道這個(gè)維度上拼接起來蛾洛,與注意力權(quán)重相乘,相乘后的結(jié)果分為 R 份雁芙,將這 R 份結(jié)果加起來形成這一個(gè) k 的輸出轧膘,最終將K組中所有 k 的結(jié)果在通道數(shù)這個(gè)維度上拼接起來。
總的來說兔甘,這種方式就是依次對(duì) K 組中的每份 k 進(jìn)行處理谎碍,每份 k 進(jìn)一步 split 成 R 份,其中每份 r 生成不同的注意力裂明,K 組中的每份 k 都結(jié)合完注意力后椿浓,再將它們的結(jié)果在通道上拼接起來。
SplAtConv2d
接下來看看 SplAtConv2d 的實(shí)現(xiàn)方式闽晦。
仔細(xì)觀察上圖,我們可以發(fā)現(xiàn)提岔,這種實(shí)現(xiàn)方式是將輸入分為 R 份仙蛉,其中的每份 r 包含了 K 個(gè)組,每份 r 生成的注意力不同(對(duì)應(yīng)上圖中的虛線框)碱蒙,上一節(jié)便說到了荠瘪,同一 k 下 不同的 split r 上形成的注意力不一致夯巷,但不同的 k 對(duì)應(yīng)相同的 r 上形成的注意力卻是一致的。
再回顧下 RadixMajorNaiveImp 的實(shí)現(xiàn)方式哀墓,同一 k 下 不同的 split r 上形成的注意力也是不一致趁餐,但不同 k 的注意力是獨(dú)立生成的,它們之間并沒有聯(lián)系篮绰,這就是兩種實(shí)現(xiàn)方式的最大差別了后雷。
一起來瞄瞄代碼~
這里提醒大家注意下,訓(xùn)練過程中在測(cè)試這個(gè)模塊時(shí)吠各,記住把 batch size 設(shè)置大于1臀突,由于使用了 global average pooling,輸出特征的大小變?yōu)?x1贾漏,因此其后接 bn 的話(上圖中 self.bn1)就要求每個(gè)通道上多于一個(gè)元素候学,而如果 batch size 為1的話就會(huì)報(bào)錯(cuò)了:
ValueError: Expected more than 1 value per channel when training
bn 是在每個(gè)通道上(channel-wise)做歸一化的,如果通道上只有1個(gè)元素纵散,那么歸一化就無意義了梳码,所以在訓(xùn)練過程中, bn 要求每個(gè)通道上必須多于1個(gè)元素伍掀。
另外掰茶,SplAtConv2d 這種實(shí)現(xiàn)方式不需要依次對(duì) K 組中的每份進(jìn)行處理,而是直接對(duì) K 個(gè)組同時(shí)進(jìn)行處理硕盹,相比于 RadixMajorNaiveImp 的方式更加簡(jiǎn)潔些符匾。
作者在 paper 和 github 源碼中也給出了兩者等價(jià)性的證明,源碼可以看這里:
SplAtConv2d 和 RadixMajorNaiveImp 的等價(jià)性證明
另外還可參考?Amusi (CVer) 的這篇文:
最后:
對(duì)于 ResNeSt啊胶, 初次接觸時(shí)往往會(huì)感覺其代碼實(shí)現(xiàn)和paper描述得有出入,因此要把它講述明白垛贤,自己本身一定要理解得透徹焰坪。如果沒有親自敲過一遍代碼,就很難做到聘惦。對(duì)于其它算法模型也一樣某饰,能真正掌握的辦法就是親自上陣實(shí)踐一番,所謂知而不行善绎,乃是未知黔漂。