源碼解析目標(biāo)檢測的跨界之星DETR(三)托猩、Backbone與位置編碼

Date: 2020/07/14

Coder: CW

Foreword:

這一篇開始對 DETR 的模型構(gòu)建部分進(jìn)行解析呈野,model主要由兩部分組成烛愧,其中一部分是backbone酪惭,另一部分是Transformer希痴。另外,在DETR的源碼實(shí)現(xiàn)中春感,將位置編碼模塊與backbone集成到一起作為一個(gè)module砌创,在backbone輸出特征圖的同時(shí)對其進(jìn)行位置編碼虏缸,以便后續(xù)Transformer使用。


Outline

I. Build Backbone

II. Build Position Encoding

III. Joiner


Build Backbone

backbone的構(gòu)建通過bulid_backbone這個(gè)方法封裝嫩实,主要做的就是分別構(gòu)建位置編碼部分與backbone刽辙,然后將兩者封裝到一個(gè)nn.Module里,在前向過程中實(shí)現(xiàn)兩者的功能甲献。

build_backbone

先來看backbone的構(gòu)建宰缤,以下這個(gè)類繼承BackboneBase這個(gè)類,實(shí)際的backbone是使用torchvision里實(shí)現(xiàn)的resnet晃洒。其中 pretrained=is_main_process() 代表僅在主進(jìn)程中使用預(yù)訓(xùn)練權(quán)重慨灭。

Backbone

而對于 norm_layer=FrozenBatchNorm2d,代表這里使用的歸一化層是FrozenBatchNorm2d球及,這個(gè)nn.Module與batch normalization的工作原理類似氧骤,只不過將統(tǒng)計(jì)量(均值與方差)和可學(xué)習(xí)的仿射參數(shù)固定住,doc string里的描述是:

BatchNorm2d where the batch statistics and the affine parameters are fixed.

在實(shí)現(xiàn)的時(shí)候吃引,需要將以上4個(gè)量注冊到buffer筹陵,以便阻止梯度反向傳播而更新它們,同時(shí)又能夠記錄在模型的state_dict中镊尺。

FrozenBatchNorm2d

在BackboneBase中可以看到朦佩,若return_interm_layers設(shè)置為True,則需要記錄每一層(ResNet的layer)的輸出庐氮。

BackboneBase

注意语稠,IntermediateLayerGetter 這個(gè)類是在torchvision中實(shí)現(xiàn)的,它繼承nn.ModuleDict旭愧,接收一個(gè)nn.Module和一個(gè)dict作為初始化參數(shù)颅筋,dict的key對應(yīng)nn.Module的模塊,value則是用戶自定義的對應(yīng)各個(gè)模塊輸出的命名输枯,官方給出的例子如下:

Examples::

? ? ? ? >>> m = torchvision.models.resnet18(pretrained=True)

? ? ? ? >>> # extract layer1 and layer3, giving as names `feat1` and feat2`

? ? ? ? >>> new_m = torchvision.models._utils.IntermediateLayerGetter(m,

? ? ? ? >>>? ? {'layer1': 'feat1', 'layer3': 'feat2'})

? ? ? ? >>> out = new_m(torch.rand(1, 3, 224, 224))

? ? ? ? >>> print([(k, v.shape) for k, v in out.items()])

? ? ? ? >>>? ? [('feat1', torch.Size([1, 64, 56, 56])),

? ? ? ? >>>? ? ? ('feat2', torch.Size([1, 256, 14, 14]))]

現(xiàn)在回過頭來看看BackboneBase的前向過程议泵。self.body就是上述提到的IntermediateLayerGetter,它的輸出是一個(gè)dict桃熄,對應(yīng)了每層的輸出先口,key是用戶自定義的賦予輸出特征圖的名字。

BackboneBase

注意BackboneBase的前向方法中的輸入是NestedTensor這個(gè)類的實(shí)例瞳收,其實(shí)質(zhì)就是將圖像張量和對應(yīng)的mask封裝到一起碉京。

NestedTensor

至此,Backbone的構(gòu)建就完事了螟深。綜上可知谐宙,若設(shè)置return_interm_layers為True,即指定需要返回每層的輸出界弧,那么backbone的輸出將是 out={'0': f1, '1': f2, '2': f3, '3': f4}凡蜻,否則輸出將是 out={'0': f4},搭综,其中f_{i} 代表第i層的輸出(比如ResNet的話,就是layer_{i} )划栓。


Build Position Encoding

這部分的實(shí)現(xiàn)和Transformer那篇paper中的基本類似兑巾,有兩種方式來實(shí)現(xiàn)位置編碼:一種是可學(xué)習(xí)的;另一種則是使用正忠荞、余弦函數(shù)來對各位置的奇蒋歌、偶維度進(jìn)行編碼,不需要額外的參數(shù)進(jìn)行學(xué)習(xí)委煤,Transformer和DETR默認(rèn)使用的也是這種堂油。

不同的是,這里處理的對象是2D圖像特征碧绞,而非1D的序列称诗,因此位置編碼需要分別對行、列進(jìn)行(當(dāng)然头遭,你可能想到把特征圖flatten成h*w的1D序列,但應(yīng)該是考慮到保持圖像結(jié)構(gòu)因此DETR并沒有那么做癣诱,感興趣的童鞋可以試試计维,并且進(jìn)行實(shí)驗(yàn)對比下效果)。

build_position_encoding

先來對可學(xué)習(xí)的編碼方式進(jìn)行解析撕予。

這里默認(rèn)需要編碼的特征圖的行鲫惶、列不超為50(相當(dāng)于特征圖尺寸不超過50x50),即位置索引在0~50范圍內(nèi)实抡,對每個(gè)位置都嵌入到num_pos_feats(默認(rèn)256)維欠母。

PositionEmbeddingLearned(i)

下面是前向過程,分別對一行和一列中的每個(gè)位置進(jìn)行編碼吆寨。

PositionEmbeddingLearned(ii)

最后將行赏淌、列編碼結(jié)果拼接起來并擴(kuò)充第一維,與batch size對應(yīng)啄清,得到以下變量pos(N,num\_pos\_feats*2,h,w)六水。

在這種方式的編碼下,所有行同一列的橫坐標(biāo)(x_emb)編碼結(jié)果是一樣的辣卒,在dim1中處于pos的前num_pos_feats維掷贾;同理,所有列所有列同一行的縱坐標(biāo)(y_emb)編碼結(jié)果也是一樣的荣茫,在dim1中處于pos的后num_pos_feats維想帅。

PositionEmbeddingLearned(iii)

再來看看正、余弦編碼的方式啡莉。

這種方式是將每個(gè)位置的各個(gè)維度映射到角度上港准,因此有個(gè)scale參數(shù)旨剥,若初始化時(shí)沒有指定,則默認(rèn)為0~2π叉趣。

PositionEmbeddingSine(i)

在該系列上一篇:?源碼解析目標(biāo)檢測的跨界之星DETR(二)泞边、模型訓(xùn)練過程與數(shù)據(jù)處理?中的數(shù)據(jù)處理部分,CW提到過mask指示了圖像哪些位置是padding而來的疗杉,其值為True的部分就是padding的部分阵谚,這里取反后得到not_mask,那么值為True的部分就是圖像真實(shí)有效(而非padding)的部分烟具。

PositionEmbeddingSine(ii)

上圖中使用了張量的cumsum()方法在列和行的方向分別進(jìn)行累加梢什,并且數(shù)據(jù)類型由布爾型轉(zhuǎn)換為浮點(diǎn)型。不得不說朝聋,這個(gè)操作十分妙嗡午!

在行方向累加,就會得到以下形式(y_embed):

[ [1,1,1,..,1],

? [2,2,2,..,2],

? ...

? [h,h,h,..,h] ]

而在列方向累加冀痕,則得到以下形式(x_embed):

[ [1,2,3,..,w],

? [1,2,3,..,w],

? ...

? [1,2,3,..,w]?]

這樣荔睹,各行(列)都映射到不同的值(當(dāng)然,pad部分的位置由于mask取反后值是0言蛇,因此累加后得到的值會與前面行僻他、列的值重復(fù),但是不要緊腊尚,通過下一篇文章關(guān)于注意力權(quán)重計(jì)算的講解會知道這些位置會被忽略掉而不受影響)吨拗,并且,最后一行(列)是所有行(列)的總和h(w)婿斥,還方便進(jìn)行歸一化操作:

PositionEmbeddingSine(iii)

下圖部分的代碼與正劝篷、余弦編碼的公式對應(yīng):

PE(pos, 2i) = \sin(\frac{pos}{10000^{\frac{2i}07n7cfx } } )PE(pos, 2i+1) = \cos(\frac{pos}{10000^{\frac{2i}zp7t9pv } } )

PositionEmbeddingSine(iv)

使用這種方式編碼民宿,就是對各行各列的奇偶維度分別進(jìn)行正娇妓、余弦編碼。

對于每個(gè)位置(x,y)活鹰,其所在列對應(yīng)的編碼值排在通道這個(gè)維度上的前num_pos_feats維峡蟋,而其所在行對應(yīng)的編碼值則排在通道這個(gè)維度上的后num_pos_feats維。這樣华望,特征圖上的各位置(總共h*w個(gè))都對應(yīng)到不同的維度為2*num\_pos\_feats的編碼值(向量)蕊蝗。

至于這種方式為何能夠保證不同位置映射到不同的位置編碼可以看下CW這篇文章中的分析(在最后一小節(jié)):Transformer 修煉之道(一)、Input Embedding

另外赖舟,這種方式相比于可學(xué)習(xí)的方式還有個(gè)“可拓展”的好處:即使在測試時(shí)來到一個(gè)比以往訓(xùn)練時(shí)遇到的圖像尺寸都大的圖像蓬戚,也照樣能夠獲得編碼值。

Joiner

Joiner就是將backbone和position encoding集成的一個(gè)nn.Module里宾抓,使得前向過程中更方便地使用兩者的功能子漩。

Joinernn.Sequential的子類豫喧,通過初始化,使得self[0]是backbone幢泼,self[1]是position encoding紧显。前向過程就是對backbone的每層輸出都進(jìn)行位置編碼,最終返回backbone的輸出及對應(yīng)的位置編碼結(jié)果缕棵。

Joiner

@最后

就這篇文章的整體內(nèi)容來說孵班,重點(diǎn)應(yīng)該是在位置編碼的部分,backbone部分畢竟是調(diào)用torchvision的內(nèi)置模型招驴,因此幾乎沒什么可講的了篙程,位置編碼的技巧可以私下多碼幾遍,碼熟它别厘,從而掌握一個(gè)基本技能虱饿,便于日后應(yīng)用。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
禁止轉(zhuǎn)載触趴,如需轉(zhuǎn)載請通過簡信或評論聯(lián)系作者氮发。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市冗懦,隨后出現(xiàn)的幾起案子折柠,更是在濱河造成了極大的恐慌,老刑警劉巖批狐,帶你破解...
    沈念sama閱讀 218,036評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異前塔,居然都是意外死亡嚣艇,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評論 3 395
  • 文/潘曉璐 我一進(jìn)店門华弓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來食零,“玉大人,你說我怎么就攤上這事寂屏》∫ィ” “怎么了?”我有些...
    開封第一講書人閱讀 164,411評論 0 354
  • 文/不壞的土叔 我叫張陵迁霎,是天一觀的道長吱抚。 經(jīng)常有香客問我,道長考廉,這世上最難降的妖魔是什么秘豹? 我笑而不...
    開封第一講書人閱讀 58,622評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮昌粤,結(jié)果婚禮上既绕,老公的妹妹穿的比我還像新娘啄刹。我一直安慰自己,他們只是感情好凄贩,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,661評論 6 392
  • 文/花漫 我一把揭開白布誓军。 她就那樣靜靜地躺著,像睡著了一般疲扎。 火紅的嫁衣襯著肌膚如雪昵时。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,521評論 1 304
  • 那天评肆,我揣著相機(jī)與錄音债查,去河邊找鬼。 笑死瓜挽,一個(gè)胖子當(dāng)著我的面吹牛盹廷,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播久橙,決...
    沈念sama閱讀 40,288評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼俄占,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了淆衷?” 一聲冷哼從身側(cè)響起缸榄,我...
    開封第一講書人閱讀 39,200評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎祝拯,沒想到半個(gè)月后甚带,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,644評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡佳头,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,837評論 3 336
  • 正文 我和宋清朗相戀三年鹰贵,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片康嘉。...
    茶點(diǎn)故事閱讀 39,953評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡碉输,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出亭珍,到底是詐尸還是另有隱情敷钾,我是刑警寧澤,帶...
    沈念sama閱讀 35,673評論 5 346
  • 正文 年R本政府宣布肄梨,位于F島的核電站阻荒,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏众羡。R本人自食惡果不足惜财松,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,281評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧辆毡,春花似錦菜秦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至眨攘,卻和暖如春主慰,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背鲫售。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評論 1 269
  • 我被黑心中介騙來泰國打工共螺, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人情竹。 一個(gè)月前我還...
    沈念sama閱讀 48,119評論 3 370
  • 正文 我出身青樓藐不,卻偏偏與公主長得像,于是被迫代替她去往敵國和親秦效。 傳聞我的和親對象是個(gè)殘疾皇子雏蛮,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,901評論 2 355