<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          輕量級(jí)網(wǎng)絡(luò)論文-VoVNet詳解

          共 28732字,需瀏覽 58分鐘

           ·

          2022-12-04 13:16

          • 摘要

          • 1,介紹

          • 2,高效網(wǎng)絡(luò)設(shè)計(jì)的影響因素

            • 2.1,內(nèi)存訪問代價(jià)

            • 2.2,GPU計(jì)算效率

          • 3,建議的方法

            • 3.1,重新思考密集連接

            • 3.2,One-Shot Aggregation

            • 3.3,構(gòu)建 VoVNet 網(wǎng)絡(luò)

          • 4,實(shí)驗(yàn)

          • 5,代碼解讀

          • 參考資料


          摘要

          Youngwan Lee* 作者于 2019 年發(fā)表的論文 An Energy and GPU-Computation Efficient Backbone Network for Real-Time Object Detection. 是對(duì) DenseNet 網(wǎng)絡(luò)推理效率低的改進(jìn)版本。

          因?yàn)?DenseNet 通過用密集連接,來聚合具有不同感受野大小的中間特征,因此它在對(duì)象檢測(cè)任務(wù)上表現(xiàn)出良好的性能。雖然特征重用(feature reuse)的使用,讓 DenseNet 以少量模型參數(shù)和 FLOPs,也能輸出有力的特征,但是使用 DenseNet 作為 backbone 的目標(biāo)檢測(cè)器卻表現(xiàn)出了運(yùn)行速度慢和效率低下的弊端。作者認(rèn)為是密集連接(dense connection)帶來的輸入通道線性增長(zhǎng),從而導(dǎo)高內(nèi)存訪問成本和能耗。為了提高 DenseNet 的效率,作者提出一個(gè)新的更高效的網(wǎng)絡(luò) VoVet,由 OSAOne-Shot Aggregation,一次聚合)組成。OSA 僅在模塊的最后一層聚合前面所有層的特征,這種結(jié)構(gòu)不僅繼承了 DenseNet 的多感受野表示多種特征的優(yōu)點(diǎn),也解決了密集連接效率低下的問題?;?VoVNet 的檢測(cè)器不僅速度比 DenseNet 快 2 倍,能耗也降低了 1.5-4.1 倍。另外,VoVNet 網(wǎng)絡(luò)的速度和效率還優(yōu)于 ResNet,并且其對(duì)于小目標(biāo)檢測(cè)的性能有了顯著提高。

          1,介紹

          隨著 CNN 模型:VGG、ResNetDensNet 的巨大進(jìn)步,它們開始被廣泛用作目標(biāo)檢測(cè)器的 backbone,用來提取圖像特征。

          ResNetDenseNet 主要的區(qū)別在于它們聚合特征的方式,ResNet 是通過逐元素相加(element-wise add)和前面特征聚合,DenseNet 則是通過拼接(concatenation)的方式。Zhu 等人在論文32[1] 中認(rèn)為前面的特征圖攜帶的信息將在與其他特征圖相加時(shí)被清除。換句話說,通過 concatenation 的方式,早期的特征才能傳遞下去,因?yàn)樗A袅颂卣鞯脑夹问剑]有改變特征本身)。

          最近的一些工作 [25, 17, 13] 表明具有多個(gè)感受野的抽象特征可以捕捉各種尺度的視覺信息。因?yàn)闄z測(cè)任務(wù)比分類更加需要多樣化尺度去識(shí)別對(duì)象,因此保留來自各個(gè)層的信息對(duì)于檢測(cè)尤為重要,因?yàn)榫W(wǎng)絡(luò)每一層都有不同的感受野。因此,在目標(biāo)檢測(cè)任務(wù)上,DenseNetResNet 有更好更多樣化的特征表示。

          這是不是說明對(duì)于,多標(biāo)簽分類問題,用 VoVNet 作為 backbone,效果要比 ResNet 要好。因?yàn)榍罢呖梢詫?shí)現(xiàn)多感受野表示特征。

          盡管使用 DenseNet 的檢測(cè)器的參數(shù)量和 FLOPs 都比 ResNet 小,但是前者的能耗能耗和速度卻更慢。這是因?yàn)?,還有其他因素 FLOPs 和模型尺寸(參數(shù)量)影響能耗。

          首先,內(nèi)存訪問代價(jià) MAC 是影響能耗的關(guān)鍵因素。如圖 1(a) 所示,因?yàn)?DenseNet 中的所有特征圖都被密集連接用作后續(xù)層的輸入,因此內(nèi)存訪問成本與網(wǎng)絡(luò)深度成二次方增加,從而導(dǎo)致計(jì)算開銷和更多的能耗。

          OSA和密集連接

          從圖 (a) 中可以看出,DenseBlock 中的每一層的輸入都是前面所有層 feature map 的疊加。而圖 (b)只有最后一層的輸入是前面所有層 feature map 的疊加。

          其次,關(guān)于 GPU 的并行計(jì)算,DenseNet 有計(jì)算瓶頸的限制。一般來說,當(dāng)操作的張量更大時(shí),GPU 的并行利用率會(huì)更高[19,29,13]。然而,由于為了線性增加輸入通道,需要 DenseNet 采用 1×1 卷積 bottleneck 架構(gòu)來減少輸入維度和 FLOPs,這導(dǎo)致使用較小的操作數(shù)張量增加層數(shù)。作為結(jié)果就是 GPU 計(jì)算變得低效??偨Y(jié)就是,bottleneck 結(jié)構(gòu)中的 卷積會(huì)導(dǎo)致 GPU 并行利用率。

          本文的目的在于將 DenseNet 改進(jìn)的更高效,同時(shí),還保留對(duì)目標(biāo)檢測(cè)有益的連接聚合(concatenative aggregation)操作。

          作者認(rèn)為 DenseNet 網(wǎng)絡(luò) DenseBlock 中間層的密集連接(dense connections)會(huì)導(dǎo)致網(wǎng)絡(luò)效率低下,并假設(shè)相應(yīng)的密集連接是多余的。

          作者使用 OSA 模塊構(gòu)建了 VoVNet 網(wǎng)絡(luò),為了驗(yàn)證有效性,將其作為 DSOD、RefineDet 和 Mask R-CNN 的 backbone 來做對(duì)比實(shí)驗(yàn)。實(shí)驗(yàn)結(jié)果表明,基于 VoVNet 的檢測(cè)器優(yōu)于 DenseNet 和 ResNet,速度和能耗都更優(yōu)。

          2,高效網(wǎng)絡(luò)設(shè)計(jì)的影響因素

          作者認(rèn)為,MobileNet v1 [8], MobileNet v2 [21], ShuffleNet v1 [31], ShuffleNet v2 [18], and Pelee 模型主要是通過使用 DW 卷積和 帶 卷積的 bottleneck 結(jié)構(gòu)來減少 FLOPs 和模型尺寸(參數(shù)量)。

          這里我覺得作者表達(dá)不嚴(yán)謹(jǐn),因?yàn)?shufflenetv2 在論文中已經(jīng)聲明過,F(xiàn)LOPs 和模型參數(shù)量不是模型運(yùn)行速度的唯一決定因素。

          實(shí)際上,減少 FLOPs 和模型大小并不總能保證減少 GPU 推理時(shí)間和實(shí)際能耗,典型的例子就是 DenseNetResNet 的對(duì)比,還有就是在 GPU 平臺(tái)上, Shufflenetv2 在同等參數(shù)條件下,運(yùn)行速度比 MobileNetv2 更快。這些現(xiàn)象告訴我們,FLOPs 和 模型尺寸(參數(shù))是衡量模型實(shí)用性(practicality)的間接指標(biāo)。為了設(shè)計(jì)更高效的網(wǎng)絡(luò),我們需要使用直接指標(biāo) FPS,除了上面說的 FLOPs 和模型參數(shù)量會(huì)影響模型的運(yùn)行速度(FPS),還有以下幾個(gè)因素。

          2.1,內(nèi)存訪問代價(jià)

          這個(gè) Shufflenetv2 作者已經(jīng)解釋得很清楚了,本文的作者的描述基本和 Shufflenetv2 一致。我這里直接給結(jié)論:

          • MAC 對(duì)能耗的影響超過了計(jì)算量 FLOPs [28]。
          • 卷積層輸入輸出通道數(shù)相等時(shí),MAC 取得最小值。
          • 即使模型參數(shù)量一致,只要 MAC 不同,那么模型的運(yùn)行時(shí)間也是不一致的(ShuffleNetv2 有實(shí)驗(yàn)證明)。

          論文 [28] Designing energy-efficient convolutional neural networks using energyaware pruning.

          2.2,GPU計(jì)算效率

          其實(shí)這個(gè)內(nèi)容和 shufflenetv2 論文中的 G3 原則(網(wǎng)絡(luò)碎片化會(huì)降低 GPU 并行度)基本一致。

          為提高速度而降低 FLOPs 的網(wǎng)絡(luò)架構(gòu)基于這樣一種理念,即設(shè)備中的每個(gè)浮點(diǎn)運(yùn)算都以相同的速度進(jìn)行處理。但是,當(dāng)模型部署在 GPU 上時(shí),不是這樣的,因?yàn)?GPU 是并行處理機(jī)制能同時(shí)處理多個(gè)浮點(diǎn)運(yùn)算進(jìn)程。我們用 GPU 計(jì)算效率來表示 GPU 的運(yùn)算能力。

          • 通過減少 FLOPs 是來加速的前提是,設(shè)備中的每個(gè)浮點(diǎn)運(yùn)算都以相同的速度進(jìn)行處理;
          • GPU 特性
            • 擅長(zhǎng) parallel computation,tensor 越大,GPU 使用效率越高。
            • 把大的卷積操作拆分成碎片的小操作將不利于 GPU 計(jì)算。
          • 因此,設(shè)計(jì) layer 數(shù)量少的網(wǎng)絡(luò)是更好的選擇。MobileNet使用額外的 1x1 卷積來減少計(jì)算量,不過這不利于 GPU 計(jì)算。
          • 為了衡量 GPU 利用率,引入有一個(gè)新指標(biāo):(每秒完成的計(jì)算量 FLOPs per Second),F(xiàn)LOP/s 高,則 GPU 利用率率也高。

          3,建議的方法

          3.1,重新思考密集連接

          1,DenseNet 的優(yōu)點(diǎn)

          在計(jì)算第 層的輸出時(shí),要用到之前所有層的輸出的 concat 的結(jié)果。這種密集的連接使得各個(gè)層的各個(gè)尺度的特征都能被提取,供后面的網(wǎng)絡(luò)使用。這也是它能得到比較高的精度的原因,而且密集的連接更有利于梯度的回傳(ResNet shorcut 操作的加強(qiáng)版)。

          2,DenseNet 缺點(diǎn)(導(dǎo)致了能耗和推理效率低的):

          • 密集連接會(huì)增加輸入通道大小,但輸出通道大小保持不變,導(dǎo)致的輸入和輸出通道數(shù)都不相等。因此,DenseNet 具有具有較高的 MAC。
          • DenseNet 采用了 bottleneck 結(jié)構(gòu),這種結(jié)構(gòu)將一個(gè) 卷積分成了兩個(gè)計(jì)算(1x1+3x3 卷積),這帶來了更多的序列計(jì)算(sequential computations),導(dǎo)致會(huì)降低推理速度。

          密集連接會(huì)導(dǎo)致計(jì)算量增加,所以不得不采用 卷積的 bottleneck 結(jié)構(gòu)。

          圖 7 的第 1 行是 DenseNet 各個(gè)卷積層之間的相互關(guān)系的大小。第 塊代表第 層和第 層之間這個(gè)卷積權(quán)值的平均 范數(shù)(按特征圖數(shù)量歸一化后的 L1 范數(shù))的大小,也就相當(dāng)于是表征 之間的關(guān)系。

          圖 2. 訓(xùn)練后的 DenseNet(頂部) 和 VoVNet(中間和底部) 中卷積層的濾波器權(quán)重的絕對(duì)值的平均值。像素塊的顏色表示的是相互連接的網(wǎng)絡(luò)層(i, j)的權(quán)重的平均 范數(shù)(按特征圖數(shù)量歸一化后的 L1 范數(shù))的值。OSA Module (x/y) 指的是 OSA 模塊由 層和 個(gè)通道組成。

          Figure2

          如圖 2 頂部圖所示, Hu 等人[9]通過評(píng)估每層輸入權(quán)重歸一化后的 L1 范數(shù)來說明密集連接的連通性(connectivity),這些值顯示了前面所有層對(duì)相應(yīng)層的歸一化影響,1 表示影響最大,0 表示沒有影響(兩個(gè)層之間的權(quán)重沒有關(guān)系)。

          這里重點(diǎn)解釋下連通性的理解。兩層之間的輸入權(quán)重的絕對(duì)值相差越大,即 L1 越大,那么說明卷積核的權(quán)重越不一樣,前面層對(duì)后面層影響越大(connectivity),即連通性越好(大)。從實(shí)用性角度講,我們肯定希望相互連接的網(wǎng)絡(luò)層的連通性越大越好(歸一化后是 0~1 范圍),這樣我的密集連接才起作用了嘛。不然,耗費(fèi)了計(jì)算量、犧牲了效率,但是連通性結(jié)果又差,那我還有必要設(shè)計(jì)成密集連接(dense connection)。作者通過圖 2 后面的兩張圖也證明了DenseBlock 模塊中各個(gè)層之間的聯(lián)系大部分都是沒用,只有少部分是有用的,即密集連接中大部分網(wǎng)絡(luò)層的連接是無效的。

          在 Dense Block3 中,對(duì)角線附近的紅色框表示中間層(intermediate layers)上的聚合處于活動(dòng)狀態(tài),但是分類層(classification layer)只使用了一小部分中間特征。相比之下,在 Dense Block1 中,過渡層(transition layer)很好地聚合了其大部分輸入特征,而中間層則沒有。

          Dense Block3 的分類層和 Dense Block1 的過渡層都是模塊的最后一層。

          通過前面的觀察,我們先假設(shè)中間層的聚集強(qiáng)度和最后一層的聚集強(qiáng)度之間存在負(fù)相關(guān)(中間層特征層的聚合能力越好,那么最后層的聚合能力就越弱)。如果中間層之間的密集連接導(dǎo)致了每一層的特征之間存在相關(guān)性,則密集連接會(huì)使后面的中間層產(chǎn)生更好的特征的同時(shí)與前一層的特征相似,則假設(shè)成立。在這種情況下,因?yàn)檫@兩種特征代表冗余信息,所以最后一層不需要學(xué)習(xí)聚合它們,從而前中間層對(duì)最終層的影響變小。

          因?yàn)樽詈笠粚拥奶卣鞫际峭ㄟ^聚集(aggregated)所有中間層的特征而產(chǎn)生的,所以,我們當(dāng)然希望中間層的這些特征能夠互補(bǔ)或者相關(guān)性越低越好。因此,進(jìn)一步提出假設(shè),相比于造成的損耗,中間特征層的 dense connection 產(chǎn)生的作用有限。為了驗(yàn)證假設(shè),我們重新設(shè)計(jì)了一個(gè)新的模塊 OSA,該模塊僅在最后一層聚合塊中其他層的特征(intermediate features,把中間的密集連接都去掉。

          3.2,One-Shot Aggregation

          為了驗(yàn)證我們的假設(shè),中間層的聚合強(qiáng)度和最后一層的聚合強(qiáng)度之間存在負(fù)相關(guān),并且密集連接是多余的,我們與 Hu 等人進(jìn)行了相同的實(shí)驗(yàn),實(shí)驗(yàn)結(jié)果是圖 2 中間和底部位置的兩張圖。

          Figure2-middle-bottom

          從圖 2(中間)可以觀察到,隨著中間層上的密集連接被剪掉,最終層中的聚合變得更加強(qiáng)烈。同時(shí),藍(lán)色的部分 (聯(lián)系大部分不緊密的部分) 明顯減少了很多,也就是說 OSA 模塊的每個(gè)連接都是相對(duì)有用的。

          從圖 2(底部)的可以觀察到,OSA 模塊的過渡層的權(quán)重顯示出與 DenseNet 不同的模式:來自淺層的特征更多地聚集在過渡層上。由于來自深層的特征對(duì)過渡層的影響不大,我們可以在沒有顯著影響的情況下減少 OSA 模塊的層數(shù),得到。令人驚訝的是,使用此模塊(5 層網(wǎng)絡(luò)),我們實(shí)現(xiàn)了 5.44% 的錯(cuò)誤率,與 DenseNet-40 (模塊里有 12 層網(wǎng)絡(luò))的錯(cuò)誤率(5.24%)相似。這意味著通過密集連接構(gòu)建深度中間特征的效果不如預(yù)期(This implies that building deep intermediate feature via dense connection is less effective than expected)。

          One-Shot Aggregation(只聚集一次)是指 OSA 模塊的 concat 操作只進(jìn)行一次,即只有最后一層的輸入是前面所有層 feature map 的 concat(疊加)。OSA 模塊的結(jié)構(gòu)圖如圖 1(b) 所示。

          Figure1

          在 OSA 模塊中,每一層產(chǎn)生兩種連接,一種是通過 conv 和下一層連接,產(chǎn)生 receptive field 更大的 feature map,另一種是和最后的輸出層相連,以聚合足夠好的特征。

          為了驗(yàn)證 OSA 模塊的有效性,作者使用 dense block 和 OSA 模塊構(gòu)成 DenseNet-40網(wǎng)絡(luò),使兩種模型參數(shù)量一致,做對(duì)比實(shí)驗(yàn)。OSA 模板版本在 CIFAR-10 數(shù)據(jù)集上的精度達(dá)到了 93.6,和 dense block 版本相比,只下降了 1.2%。再根據(jù) MAC 的公式,可知 MAC 從 3.7M 減少為 2.5M。MAC 的降低是因?yàn)?OSA 中的中間層具有相同大小的輸入輸出通道數(shù),從而使得 MAC 可以取最小值(lower boundary)。

          因?yàn)?OSA 模塊中間層的輸入輸出通道數(shù)一致,所以沒必要使用 bottleneck 結(jié)構(gòu),這又進(jìn)一步提高了 GPU 利用率。

          3.3,構(gòu)建 VoVNet 網(wǎng)絡(luò)

          因?yàn)?OSA 模塊的多樣化特征表示和效率,所以可以通過僅堆疊幾個(gè)模塊來構(gòu)建精度高、速度快的 VoVNet 網(wǎng)絡(luò)?;趫D 2 中淺層深度更容易聚合的認(rèn)識(shí),作者認(rèn)為可以配置比 DenseNet 具有更大通道數(shù)的但更少卷積層的 OSA 模塊。

          如下圖所示,分別構(gòu)建了 VoVNet-27-slim,VoVNet-39, VoVNet-57。注意,其中downsampling 層是通過 3x3 stride=2 的 max pooling 實(shí)現(xiàn)的,conv 表示的是 Conv-BN-ReLU 的順序連接。

          VoVNet網(wǎng)絡(luò)結(jié)構(gòu)概覽

          VOVNet 由 5 個(gè)階段組成,各個(gè)階段的輸出特征大小依次降為原來的一半。VOVNet-27 前 2 個(gè) stage 的連接圖如下所示。

          VOVNet-27前2個(gè)stage

          4,實(shí)驗(yàn)

          GPU 的能耗計(jì)算公式如下:

          GPU能耗計(jì)算公式

          實(shí)驗(yàn)1:VoVNet vs. DenseNet. 對(duì)比不同 backbone 下的目標(biāo)檢測(cè)模型性能(PASCALVOC)

          對(duì)比試驗(yàn)

          對(duì)比指標(biāo):

          • Flops:模型需要的計(jì)算量
          • FPS:模型推斷速度img/s
          • Params:參數(shù)數(shù)量
          • Memory footprint:內(nèi)存占用
          • Enegry Efficiency:能耗
          • Computation Efficiency:GPU 計(jì)算效率(GFlops/s)
          • mAP(目標(biāo)檢測(cè)性能評(píng)價(jià)指標(biāo))

          現(xiàn)象與總結(jié):

          • 現(xiàn)象 1:相比于 DenseNet-67,PeleeNet 減少了 Flops,但是推斷速度沒有提升,與之相反,VoVNet-27-slim 稍微增加了Flops,而推斷速度提升了一倍。同時(shí),VoVNet-27-sli m的精度比其他模型都高。
          • 現(xiàn)象 2:VoVNet-27-slim 的內(nèi)存占用、能耗、GPU 利用率都是最高的。
          • 結(jié)論 1:相比其他模型,VoVNet做到了準(zhǔn)確率和效率的均衡,提升了目標(biāo)檢測(cè)的整體性能

          實(shí)驗(yàn)2:Ablation study on 1×1 conv bottleneck.

          bottleneck驗(yàn)證實(shí)驗(yàn)

          結(jié)論 2:可以看出,1x1 bottleneck 增加了 GPU Inference 時(shí)間,降低了 mAP,盡管它減少了參數(shù)數(shù)量和計(jì)算量。

          因?yàn)?1x1 bottleneck 增加了網(wǎng)路的總層數(shù),需要更多的激活層,從而增加了內(nèi)存占用。

          實(shí)驗(yàn)3:GPU-Computation Efficiency.

          GPU計(jì)算效率對(duì)比實(shí)驗(yàn)
          • 圖3(a) VoVNet 兼顧準(zhǔn)確率和 Inference 速度
          • 圖3(b) VoVNet 兼顧準(zhǔn)確率和 GPU 使用率
          • 圖3(c) VoVNet 兼顧準(zhǔn)確率和能耗
          • 圖3(d) VoVNet 兼顧能耗和 GPU 使用率

          實(shí)驗(yàn)室4:基于RefineDet架構(gòu)比較VoVNet、ResNet和DenseNet。

          Table4

          結(jié)論 4:從 COCO 數(shù)據(jù)集測(cè)試結(jié)果看,相比于 ResNet,VoVnet在 Inference 速度,內(nèi)存占用,能耗,GPU 使用率和準(zhǔn)確率上都占據(jù)優(yōu)勢(shì)。盡管很多時(shí)候,VoVNet 需要更多的計(jì)算量以及參數(shù)量。

          • 對(duì)比 DenseNet161(k=48) 和 DenseNet201(k=32)可以發(fā)現(xiàn),深且”瘦“的網(wǎng)絡(luò),GPU 使用率更低。
          • 另外,作者發(fā)現(xiàn)相比于 ResNet,VoVNet 在小目標(biāo)上的表現(xiàn)更好。

          實(shí)驗(yàn) 5:Mask R-CNN from scratch.

          通過替換 Mask R-CNN 的 backbone,也發(fā)現(xiàn) VoVNet 在Inference 速度和準(zhǔn)確率上優(yōu)于 ResNet。

          mask-rcnn上的實(shí)驗(yàn)結(jié)果

          5,代碼解讀

          雖然 VoVNet 在 CenterMask 論文[2] 中衍生出了升級(jí)版本 VoVNetv2,但是本文的代碼解讀還是針對(duì)原本的 VoVNet,代碼來源這里[3]。

          1,定義不同類型的卷積函數(shù)

          def conv3x3(in_channels, out_channels, module_name, postfix,
                      stride=1, groups=1, kernel_size=3, padding=1)
          :

              """3x3 convolution with padding. conv3x3, bn, relu的順序組合
           """

              return [
                  ('{}_{}/conv'.format(module_name, postfix),
                      nn.Conv2d(in_channels, out_channels,
                                kernel_size=kernel_size,
                                stride=stride,
                                padding=padding,
                                groups=groups,
                                bias=False)),
                  ('{}_{}/norm'.format(module_name, postfix),
                      nn.BatchNorm2d(out_channels)),
                  ('{}_{}/relu'.format(module_name, postfix),
                      nn.ReLU(inplace=True)),
              ]

          def conv1x1(in_channels, out_channels, module_name, postfix,
                      stride=1, groups=1, kernel_size=1, padding=0)
          :

              """1x1 convolution"""
              return [
                  ('{}_{}/conv'.format(module_name, postfix),
                      nn.Conv2d(in_channels, out_channels,
                                kernel_size=kernel_size,
                                stride=stride,
                                padding=padding,
                                groups=groups,
                                bias=False)),
                  ('{}_{}/norm'.format(module_name, postfix),
                      nn.BatchNorm2d(out_channels)),
                  ('{}_{}/relu'.format(module_name, postfix),
                      nn.ReLU(inplace=True)),
              ]

          2,其中 OSA 模塊結(jié)構(gòu)的代碼如下。

          class _OSA_module(nn.Module):
              def __init__(self,
                           in_ch,
                           stage_ch,
                           concat_ch,
                           layer_per_block,
                           module_name,
                           identity=False)
          :

                  super(_OSA_module, self).__init__()

                  self.identity = identity # 默認(rèn)不使用恒等映射
                  self.layers = nn.ModuleList()
                  in_channel = in_ch
                  # stage_ch: 每個(gè) stage 內(nèi)部的 channel 數(shù)
                  for i in range(layer_per_block):
                      self.layers.append(nn.Sequential(
                          OrderedDict(conv3x3(in_channel, stage_ch, module_name, i))))
                      in_channel = stage_ch

                  # feature aggregation
                  in_channel = in_ch + layer_per_block * stage_ch
                  # concat_ch: 1×1 卷積輸出的 channel 數(shù)
                  # 也從 stage2 開始,每個(gè) stage 最開始的輸入 channnel 數(shù)
                  self.concat = nn.Sequential(
                      OrderedDict(conv1x1(in_channel, concat_ch, module_name, 'concat')))

              def forward(self, x):
                  identity_feat = x
                  output = []
                  output.append(x)
                  for layer in self.layers:  # 中間所有層的順序連接
                      x = layer(x)
                      output.append(x)
                  # 最后一層的輸出要和前面所有層的 feature map 做 concat
                  x = torch.cat(output, dim=1)
                  xt = self.concat(x)

                  if self.identity:
                      xt = xt + identity_feat

                  return xt

          3,定義 _OSA_stage,每個(gè) stage 有多少個(gè) OSA 模塊,由 _vovnet 函數(shù)的 block_per_stage 參數(shù)指定。

          class _OSA_stage(nn.Sequential):
           """
           in_ch: 每個(gè) stage 階段最開始的輸入通道數(shù)(feature map 數(shù)量)
           """

              def __init__(self,
                           in_ch,
                           stage_ch,
                           concat_ch,
                           block_per_stage,
                           layer_per_block,
                           stage_num)
          :

                  super(_OSA_stage, self).__init__()

                  if not stage_num == 2:
                      self.add_module('Pooling',
                          nn.MaxPool2d(kernel_size=3, stride=2, ceil_mode=True))

                  module_name = f'OSA{stage_num}_1'
                  self.add_module(module_name,
                      _OSA_module(in_ch,
                                  stage_ch,
                                  concat_ch,
                                  layer_per_block,
                                  module_name))
                  for i in range(block_per_stage-1):
                      module_name = f'OSA{stage_num}_{i+2}'
                      self.add_module(module_name,
                          _OSA_module(concat_ch,
                                      stage_ch,
                                      concat_ch,
                                      layer_per_block,
                                      module_name,
                                      identity=True))

          4,定義 VOVNet

          class VoVNet(nn.Module):
              def __init__(self, 
                           config_stage_ch,
                           config_concat_ch,
                           block_per_stage,
                           layer_per_block,
                           num_classes=1000)
          :

                  super(VoVNet, self).__init__()

                  # Stem module --> stage1
                  stem = conv3x3(3,   64'stem''1'2)
                  stem += conv3x3(64,  64'stem''2'1)
                  stem += conv3x3(64128'stem''3'2)
                  self.add_module('stem', nn.Sequential(OrderedDict(stem)))

                  stem_out_ch = [128]
                  # vovnet-57,in_ch_list 結(jié)果是 [128, 256, 512, 768]
                  in_ch_list = stem_out_ch + config_concat_ch[:-1]
                  self.stage_names = []
                  for i in range(4): #num_stages
                      name = 'stage%d' % (i+2)
                      self.stage_names.append(name)
                      self.add_module(name,
                                      _OSA_stage(in_ch_list[i],
                                                 config_stage_ch[i],
                                                 config_concat_ch[i],
                                                 block_per_stage[i],
                                                 layer_per_block,
                                                 i+2))

                  self.classifier = nn.Linear(config_concat_ch[-1], num_classes)

                  for m in self.modules():
                      if isinstance(m, nn.Conv2d):
                          nn.init.kaiming_normal_(m.weight)
                      elif isinstance(m, (nn.BatchNorm2d, nn.GroupNorm)):
                          nn.init.constant_(m.weight, 1)
                          nn.init.constant_(m.bias, 0)
                      elif isinstance(m, nn.Linear):
                          nn.init.constant_(m.bias, 0)

              def forward(self, x):
                  x = self.stem(x)
                  for name in self.stage_names:
                      x = getattr(self, name)(x)
                  x = F.adaptive_avg_pool2d(x, (11)).view(x.size(0), -1)
                  x = self.classifier(x)
                  return x

          5,VoVNet 各個(gè)版本的實(shí)現(xiàn)。vovnet57 中有 4 個(gè) stage,每個(gè) stage 的 OSP 模塊數(shù)目依次是 [1,1,4,3],每個(gè) 個(gè) stage 內(nèi)部對(duì)應(yīng)的通道數(shù)都是一樣的,分別是 [128, 160, 192, 224]。每個(gè) stage 最后的輸出通道數(shù)分別是 [256, 512, 768, 1024],由 concat_ch 參數(shù)指定。

          所有版本的 vovnet 的 OSA 模塊中的卷積層數(shù)都是 5。

          def _vovnet(arch,
                      config_stage_ch,
                      config_concat_ch,
                      block_per_stage,
                      layer_per_block,
                      pretrained,
                      progress,
                      **kwargs)
          :

              model = VoVNet(config_stage_ch, config_concat_ch,
                             block_per_stage, layer_per_block,
                             **kwargs)
              if pretrained:
                  state_dict = load_state_dict_from_url(model_urls[arch],
                                                        progress=progress)
                  model.load_state_dict(state_dict)
              return model

          def vovnet57(pretrained=False, progress=True, **kwargs):
              r"""Constructs a VoVNet-57 model as described in 
              `"An Energy and GPU-Computation Efficient Backbone Networks"
              <https://arxiv.org/abs/1904.09730>`_.
              Args:
                  pretrained (bool): If True, returns a model pre-trained on ImageNet
                  progress (bool): If True, displays a progress bar of the download to stderr
              """

              return _vovnet('vovnet57', [128160192224], [2565127681024],
                              [1,1,4,3], 5, pretrained, progress, **kwargs)

          def vovnet39(pretrained=False, progress=True, **kwargs):
              r"""Constructs a VoVNet-39 model as described in
              `"An Energy and GPU-Computation Efficient Backbone Networks"
              <https://arxiv.org/abs/1904.09730>`_.
              Args:
                  pretrained (bool): If True, returns a model pre-trained on ImageNet
                  progress (bool): If True, displays a progress bar of the download to stderr
              """

              return _vovnet('vovnet39', [128160192224], [2565127681024],
                              [1,1,2,2], 5, pretrained, progress, **kwargs)


          def vovnet27_slim(pretrained=False, progress=True, **kwargs):
              r"""Constructs a VoVNet-39 model as described in
              `"An Energy and GPU-Computation Efficient Backbone Networks"
              <https://arxiv.org/abs/1904.09730>`_.
              Args:
                  pretrained (bool): If True, returns a model pre-trained on ImageNet
                  progress (bool): If True, displays a progress bar of the download to stderr
              """

              return _vovnet('vovnet27_slim', [648096112], [128256384512],
                              [1,1,1,1], 5, pretrained, progress, **kwargs)

          參考資料

          [1]

          32: https://arxiv.org/abs/1801.05895

          [2]

          CenterMask 論文: https://link.zhihu.com/?target=https%3A//arxiv.org/pdf/1911.06667.pdf

          [3]

          這里: https://github.com/stigma0617/VoVNet.pytorch/blob/master/models_vovnet/vovnet.py

          [4]

          論文筆記VovNet(專注GPU計(jì)算、能耗高效的網(wǎng)絡(luò)結(jié)構(gòu)): https://zhuanlan.zhihu.com/p/79677425

          [5]

          實(shí)時(shí)目標(biāo)檢測(cè)的新backbone網(wǎng)絡(luò):VOVNet: https://zhuanlan.zhihu.com/p/393740052

          瀏覽 34
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产真实乱婬A片三区高 | AA片在线观看视频在线播放 | 99视频+国产日韩欧美 | 欧美天天性爱 | 国产精品秘 国产A级 |