天天看點

深度網絡之FishNet: A Versatile Backbone for Image, Region, and Pixel Level Prediction

FishNet: A Versatile Backbone for Image, Region, and Pixel Level Prediction

文章目錄

  • ​​FishNet: A Versatile Backbone for Image, Region, and Pixel Level Prediction​​
  • ​​一些了解​​
  • ​​背景介紹​​
  • ​​相關工作​​
  • ​​深度殘差網絡的恒等映射和孤立卷積​​
  • ​​FishNet結構細節​​
  • ​​特征細化(圖3b/c)​​
  • ​​UR-block​​
  • ​​DR-Block​​
  • ​​設計細節​​
  • ​​用于處理梯度傳播問題的FishNet設計​​
  • ​​上/下采樣函數的選擇​​
  • ​​body和tail之間的橋梁子產品​​
  • ​​實驗​​
  • ​​圖像分類​​
  • ​​實驗結果​​
  • ​​消融研究​​
  • ​​檢測與分割​​
  • ​​總結​​
  • ​​相關代碼​​
  • ​​相關連結​​
深度網絡之FishNet: A Versatile Backbone for Image, Region, and Pixel Level Prediction

原文存檔https://www.yuque.com/lart/papers/fish,若文中有表述不合理的地方請指出

更新于2019-07-15 20:35:39,補充一些新的了解,稍微調整了下結構

一些了解

這篇文章的研究思路是這樣的:

  1. 不同任務(分類與分割、檢測)需要的特征的分辨率是不同的:
  1. 分類要總結進階語義資訊
  2. 檢測、分割則需要有着高分辨率的進階語義資訊
  1. 希望将這些任務進行統一,同時利用針對像素級、區域級、圖像級任務設計的網絡的優勢,實作針對不同任務共同的增益
  2. 高層的富含語義資訊、分辨率較高的特征很有用,但是直接應用在分類中效果比較差
  1. 可能破壞了分類任務需要的平移旋轉不變性
  2. 可能分類任務需要較低的分辨率的特征
  1. 于是針對Hourglass模型附加一個下采樣高分辨進階特征的結構,整體構成了一個魚的結構——FishNet
  2. 但是網絡加大了,需要考慮的問題也會增多,例如優化問題,也就是梯度更新問題
  1. 已有的有效的ResBlock結構,其附加的短連接配接有效的促進了梯度的回傳與避免梯度消失的問題,但是在其結構中仍然存在一個不完美的地方,那就是用于調整尺寸和通道數的孤立卷積(Isolated Convolution),它的存在導緻梯度不能無阻礙的直接回傳
  2. 為什麼過去的結構中這一缺點不明顯呢?因為需要下采樣的次數比較少,但是對于FishNet這樣的結構,下采樣更多,也就會需要考慮這個問題,更加極端的,在​​Stacked Hourglass Networks​​中,會堆疊大量的hourglass結構,這個問題會更明顯
  3. FIshNet在網絡設計中就盡可能去掉了這些孤立卷積,使用了一種更為“平滑”的方式降低梯度所受到的影響,使用池化來實作下采樣,使用臨近插值上采樣,通道的調整可以使用拼接早期的特征以及分組縮減的設定來實作,這都是為了更好的進行梯度的回傳
  1. 進一步考慮特征融合問題。對于特征之間的結合,現有的類似與FPN的結構,直接融合來自不同深度的資訊。但是不同深度的特征有着對于圖像内容的不同抽象程度,應該保留所有這些以改善特征的多樣性。由于它們的互補性,它們可以用于互相細化
  1. 直接将來自高層和低層的特征相加(或者通過一些卷積處理後相加),得到的特征是混合後的特征,已經不再是原始的特征
  2. 高低層特征之間可以在保留(preserve)自身的情況下進行互相的細化(refine),而應避免混合(mix)
  3. 于是設計了FishNet中的DRBlock和URBlock(這一處知識點我開始沒有注意到,後來再次聽歐陽萬裡老師的講解的時候才明白,原來有這樣的考量),可以注意圖中提到的資訊提取的概念
  1. 網絡整體結構也就出來了,可能會疑惑,如何使用這樣的“整條魚”來處理具體的分割任務呢,因為分類任務還直覺些,可以直接使用最後的低分辨率的輸出,那分割任務這樣的需要高分辨率特征的,又該如何處理呢?(這裡有必要問下作者,歐陽萬裡老師說是可以直接切掉魚頭,這樣相較于原始的ResNet+FPN的效果要好,但是也說可以不切掉,這時如何處理,沒有聽明白, 文中提到了在FishNet後添加FPN)
  1. ​Object Detection Results Based on FPN. We report the results of detection using FPN with FishNet-150 on val-2017 for comparison.​

    ​​

    ​The top-down pathway and lateral connections(橫向連接配接) in FPN are attached to the fish head​

    ​​

    ​.​

  1. 整個網絡最後可以端到端的訓練,隻在最後進行監督

背景介紹

設計用于預測不同級别(例如圖像級,區域級和像素級)上的目标的卷積神經網絡(CNN)結構的基本原理是不同的。

  1. 通常,專門用于圖像分類的網絡結構直接用作包括檢測和分割在内的其他任務的預設骨幹結構,但是考慮統一為像素級或區域級預測任務設計的情況下設計的骨幹結構很少,這可能需要具有高分辨率的非常深的特征。為實作這一目标,設計了一個名為FishNet的網絡。在FishNet中,所有分辨率的資訊都會保留并針對最終任務進行細化。
  2. 此外,觀察到現有的工作仍然不能直接将梯度資訊從深層傳播到淺層。該設計可以更好地解決這個問題。

已經進行了大量實驗來證明FishNet的卓越性能。特别是在ImageNet-1k上,FishNet的精度能夠以更少的參數超越DenseNet和ResNet的性能。FishNet被用作COCO Detection 2018挑戰賽獲獎作品中的一個子產品。

深度網絡之FishNet: A Versatile Backbone for Image, Region, and Pixel Level Prediction

本文結構主要由以下的三個優勢:

  1. 這是第一個統一為像素級、區域級、圖像級任務設計的骨幹網絡。 相較于純粹為圖像分類任務設計的網絡,FishNet對于像素級和區域級任務而言更為有效。
  2. 它能夠将梯度從非常深的層直接傳播到較淺的層,這在文章中稱為直接BP(direct BP)。 最近的工作表明,有兩種設計可以實作直接BP,具有殘餘塊和串聯的恒等映射。然而,不言而喻的事實(unfold fact)是現有的網絡設計,例如,ResNet和DenseNet等仍然不能夠直接BP。此問題是由不同分辨率特征之間的卷積層引起的。
  1. 如圖1所示,ResNet利用跳過連接配接上的帶步幅的卷積層輸入和輸出通道數量或分辨率**的不一緻,這使得_恒等映射不适用_。沒有恒等映射或連接配接的卷積會降低從輸出到淺層的梯度。
  2. 文章的設計通過将非常不同深度的特征連接配接到最終輸出來更好地解決了這個問題。還仔細設計網絡中的元件以確定直接BP。通過這些的設計,特征的語義資訊也在整個網絡中得以保留。
  1. 來自非常不同深度的特征被保留,并且用來互相細化。改善特征的多樣性。由于它們的互補性,它們可以用于互相細化。
  1. 是以,文章設計了一種特征的保留和細化機制來實作這一目标。
# ResNet中的處理通道和分辨率不同的映射連接配接
if stride != 1 or self.inplanes != planes * block.expansion:
  downsample = nn.Sequential(
    conv1x1(self.inplanes, planes * block.expansion, stride),
    nn.BatchNorm2d(planes * block.expansion),
  )      

文章設計的一個可能違反直覺的效果是它 在參數數量和圖像分類精度之間的權衡中比傳統的卷積網絡表現更好。原因如下:

  1. 保留和細化的特征互相補充,比設計寬度或深度更大的網絡更有用;
  2. 促進直接BP。實驗結果表明,緊湊型FishNet-150,其參數數量接近ResNet-50:
  1. 能夠超越ImageNet-1k上的ResNet-101和DenseNet-161(k = 48)的精度。
  2. 對于區域和像素級任務,如對象檢測和執行個體分割,我們的模型作為Mask R-CNN的主幹,與基線ResNet50相比,MS COCO上的絕對AP分别提高了2.8%和2.3%。

相關工作

  1. CNN architectures for image classification: 高分辨率的深層特征有着進階語義資訊,并且同時可以提升圖像分類任務的準确率。
  2. Design in combining features from different layers: 之前的例如hyper-column、hourglass和fpn等的工作,雖然利用了來自深層和淺層的特征,但是并沒有用來互相細化。常用于融合的操作有 ​

    ​add​

    ​​ ,但這隻是混合了不同抽象等級的特征,并不能保留或者互相細化,而 ​

    ​cat+conv​

    ​​ 的操作和 ​

    ​add​

    ​ 的操作是類似的。當殘差塊(也帶有加法)用于組合特征時,現有工作具有待細化的預定義目标。如果跳過層用于深層特征,則淺層特征僅用于細化深層特征,在殘差塊之後會被丢棄。總之,現有工程中的加法和殘差塊不會保留淺層和深層的特征,而文章的設計會保留和細化它們。
  3. Networks with up-sampling mechanism: 由于計算機視覺中還有許多其他任務,例如對象檢測,分割,需要大特征映射來保持分辨率:
  1. 有必要将上采樣方法應用于網絡。這種機制通常用于 具有非常不同深度的特征之間的通信。包括U-Net,FPN,堆疊hourglass等在内的一系列作品都在像素級任務和區域級任務中展示了它們的能力。但是,它們都沒有被證明對圖像分類任務有效。
  2. MSDNet(Multi-Scale Dense Convolutional Networks,黃高)試圖保持大分辨率的特征映射,這是文中架構最相似的工作。
  1. 但是,MSDNet的體系結構仍然使用不同分辨率的特征之間的卷積,這不能保留表示。
  2. 此外,它沒有提供上采樣途徑來實作具有大分辨率和更多語義含義的特征。
  3. MSDNet将多尺度機制引入其架構的目的是進行預算預測(do budget prediction)。然而,這種設計沒有顯示出圖像分類精度的提高。
  1. FishNet是第一個證明U-Net結構可以有效進行圖像分類的網絡。此外,為最終任務保留和優化淺層和深層的特征,這 在具有上采樣或MSDNet的現有網絡中是無法實作的。
  1. Message passing among features/outputs: 有一些方法使用特征之間的消息傳遞進行分割,姿态估計和目标檢測。這些設計基于骨幹網絡,FishNet是與它們互補的骨幹網絡。

深度殘差網絡的恒等映射和孤立卷積

ResNet的基礎建構單元是殘差塊,有着恒等映射的殘差塊可以表示為:

深度網絡之FishNet: A Versatile Backbone for Image, Region, and Pixel Level Prediction

這裡的xl表示輸入特征,這裡表示的是第l層的殘差塊。并且F表示殘差函數,有着輸入xl,和參數Wl。這裡認為所有相同分辨率殘差塊的堆疊為一個階段“stage”。階段s中的第l層的特征表示為xl,s,是以有如下的關系:

深度網絡之FishNet: A Versatile Backbone for Image, Region, and Pixel Level Prediction

這裡的Ls表示階段s中堆疊的殘差塊的數量,L是損失函數。(2)中的附加項

深度網絡之FishNet: A Versatile Backbone for Image, Region, and Pixel Level Prediction

保證了xLs,s的梯度可以被直接傳播到x0,s上。

在原始的ResNet中,考慮到不同分辨率的特征有着不同的通道數。是以一個過渡函數h()需要在下采樣之前改變通道數:

深度網絡之FishNet: A Versatile Backbone for Image, Region, and Pixel Level Prediction

這裡的sigma表示激活函數,lambda表示濾波器,bLs,s表示偏置,這都是階段s中的參數,而其中的圈叉運算符表示卷積操作。因為輸入的xLs,s和輸出的x’0,s+1通道數不同,是以恒等映射不再适用。

所謂的 孤立(Isolated)卷積(I-conv) 是式子3中的卷積,沒有恒等映射或連接配接。通過[Identity mappings in deep residual networks]中的實驗分析和驗證,希望将深層的梯度直接傳輸到淺層。具有恒等映射的殘差塊[Identity mappings in deep residual networks]和具有串聯的密集塊[Densely connected convolutional networks]促進了這種直接梯度傳播。

如果存在I-conv,則深層的梯度不能直接傳輸到淺層。 然而,ResNet中不同分辨率的特征之間以及相鄰密集塊之間的I-conv(在[DenseNet]中稱為過渡層)阻礙了直接梯度傳播。

  • 由于ResNet和DenseNet仍然具有I-conv,是以輸出的梯度不能直接傳播到它們的淺層,類似于[Imagenet classification with deep convolutional neural networks,Very deep convolutional networks for large-scale image recognition]中的網絡。
  • [i-revnet: Deep invertible networks]中的可逆下采樣通過使用目前階段的所有特征用于下一階段來避免I-conv的問題。問題是随着階段ID的增加,它會以指數方式增加參數的數量([i-revnet: Deep invertible networks]中為188M)。

已經在現有網絡中确定了I-conv的梯度傳播問題。是以,提出了一種新的架構,即FishNet,來解決這個問題。

FishNet結構細節

深度網絡之FishNet: A Versatile Backbone for Image, Region, and Pixel Level Prediction

這裡顯示了FishNet的結構,整個網絡分為了三個部分,tail,body,head。

  • tail是現有的CNN,例如ResNet,随着網絡的深入,特征分辨率逐漸減小。
  • body則是有着數個上采樣和細化塊的結構,主要用來細化來自tail和body的特征。
  • head則是有着數個下采樣和細化塊的結構,用來保留和細化來自tail,body和head的特征。最後一個卷積層的細化特征被用來應對最終的任務。

本文中的”階段“(stage)是指由具有相同分辨率的特征饋送的一堆卷積塊。根據輸出特征的分辨率,FishNet中的每個部分可以分為幾個階段。 随着分辨率變小,階段ID變得更高。例如,輸出分辨率為56x56和28x28的塊分别位于FishNet的所有三個部分的第1和第2階段。是以,在魚尾和頭部,階段ID在前向傳播時變得更高,而在身體部分中ID越來越小。

深度網絡之FishNet: A Versatile Backbone for Image, Region, and Pixel Level Prediction

圖3顯示了兩個階段特征的尾部,身體和頭部之間的互相作用。

  1. 圖3a中的tail可被視為殘差網絡。tail的特征經曆(undergo)幾個殘餘塊并且還通過水準箭頭傳遞到nody。
  2. 圖3a中的body通過連接配接保留了尾部的特征和身體前一階段的特征。然後,這些連接配接的特征将被上采樣并細化,細節如b中所示。
  3. 對于head會使用前面細化的特征和之前的head的特征。head中的資訊傳遞方式可見c。
  4. 在tail,body,head的水準連接配接表示之間的傳遞塊。在圖3a中, 使用殘差塊作為傳輸塊。

特征細化(圖3b/c)

FishNet中有兩個特征細化子產品,一個是3b中所示的UR-block和3c中所示的DR-block。

UR-block

該子產品主要存在于body部分,是以其輸入也就是來自于tail和body的特征。其表達式可以寫成:

深度網絡之FishNet: A Versatile Backbone for Image, Region, and Pixel Level Prediction
  • 其中的xst和xsb表示來自tail和body的位于階段s的第一層的特征。
  • 由于這裡是相同的分辨率之間互相關聯,是以這裡的s最小為1,最大為tail和body中階段數N減去1後的小值。
  • 式子裡的τ表示的從tail到body之間傳送特征xs-1t用的殘差塊。
  • 這裡的xs-1b表示從body上個階段細化後得到的特征。
深度網絡之FishNet: A Versatile Backbone for Image, Region, and Pixel Level Prediction

具體細節: 從xst和xsb細化得到輸出的過程表示如下:

深度網絡之FishNet: A Versatile Backbone for Image, Region, and Pixel Level Prediction
  • 特征使用了串聯的方式進行了組合。
  • 這裡的up表示的上采樣函數。順序一次是7->6->5。得到這一階段的輸出。
  • 式子中的M表示從特征提取資訊的函數。這裡使用卷積實作。相似于式子1中的殘差函數F,這裡的M使用ResNet中的Bottleneck單元實作,有着3個卷積層。
  • 式子中的r表示通道級縮減函數可以表示為如下的關系,這是元素級加和,将k個通道關聯到了一個通道上,這裡将 通道縮減為原來的1/k,這使得可以降低計算和存儲規模。
深度網絡之FishNet: A Versatile Backbone for Image, Region, and Pixel Level Prediction

這裡的

深度網絡之FishNet: A Versatile Backbone for Image, Region, and Pixel Level Prediction

表示有着cin通道的輸入特征圖,hatx表示有着cout通道的輸出特征圖,且有這關系cin/cout=k,是以等式中x(k*n+j)表示按照輸入與輸出的比例關系對輸入的特征進行了一個分組,每個輸出的通道隻和其中的一組k個輸入有關,是其中一組的加和。

DR-Block

而該子產品主要用在head部分,相似于UR-block。隻有兩處不同:

  1. 使用2x2最大池化來下采樣。
  2. 不使用通道縮減函數,以至于目前階段的梯度可以直接被傳送到先前的階段。
深度網絡之FishNet: A Versatile Backbone for Image, Region, and Pixel Level Prediction

具體細節: 從xsh和xsb得到xs+1h的過程表示如下:

深度網絡之FishNet: A Versatile Backbone for Image, Region, and Pixel Level Prediction

符号表示類似。以這種方式,整個網絡的每個階段的特征都可以 通過串聯、跳躍連結和最大池化的方式直接連接配接到最後一層。注意這裡沒有使用通道縮減操作r。是以從DR-block中獲得hatxs’h的層可以被看作是殘差塊。

設計細節

用于處理梯度傳播問題的FishNet設計

在FishNet中設計了body和head,來自tail和body各個階段的特征都在head串聯起來。

仔細設計了head的層,這樣就沒有I-conv。head中的層由串聯,帶有恒等映射的卷積和最大池化組成。是以,FishNet解決尾部中先前那些骨幹網絡的梯度傳播問題,主要通過:

  1. 排除head的I-conv
  2. 在body和head使用連接配接

上/下采樣函數的選擇

對于使用步幅2進行下采樣,核為2x2以避免像素之間的重疊。消融研究将顯示網絡中不同類型核心大小的影響。

為了避免I-conv的問題,應該避免上采樣方法中的權重反卷積。為簡單起見,選擇最近鄰插值進行上采樣。

個人了解:權重反卷積實際上就是在指代“反卷積”或者“轉置卷積”的操作,這本身就是一種卷積操作,是一種I-Conv。并不利于梯度的傳播。

由于 上采樣操作會以較低的分辨率稀釋(dilute)輸入特征,是以在細化塊中應用擴張卷積。

body和tail之間的橋梁子產品

由于tail将對特征進行向下采樣分辨率為1x1,是以需要将這1x1的特征上采樣為7x7。在此處應用SE塊以使用通道注意力操作,将特征從1x1映射到7x7。

實驗

圖像分類

  • For image classification, we evaluate our network on the ImageNet 2012 classification dataset that consists of 1000 classes.
  • 1.2 million images for training
  • 50000 images for validation (denoted by ImageNet-1k val)
  • All the experiments in this paper are evaluated through single-crop validation process its shorter side being resized to 256 This 224x224 image region is the input of the network.
  • Training:
  • randomly crop the images into the resolution of 224x224 with batch size 256
  • We follow the way of augmentation ( random crop, horizontal flip and standard color augmentation) used in [ResNet] for fair comparison.
  • stochastic gradient descent (SGD)
  • the base learning rate set to 0.1
  • weight decay and momentum are 1e-4 and 0.9 respectively
  • 100 epochs
  • the learning rate is decreased by 10 times every 30 epochs
  • the normalization process is done by first converting the value of each pixel into the interval [0, 1], and then subtracting the mean and dividing the variance for each channel of the RGB respectively

由于FishNet是一個架構,并不制定構件塊,對于本文的實驗結果,FishNet使用的是帶有恒等映射的殘差塊作為基礎建構塊,而FishNeXt則是使用帶有恒等連接配接和分組的殘差塊作為構件塊。

實驗結果

深度網絡之FishNet: A Versatile Backbone for Image, Region, and Pixel Level Prediction

When our network uses pre-activation ResNet as the tail part of the FishNet, the FishNet performs better than ResNet and DenseNet. (不是原始的ResNet,Conv-BN-ReLU的順序有變化,所謂預激活)

FishNet與ResNet: 為了公平比較,重制了ResNet,在圖中彙報了結果,實際要比ResNet的論文結果要高,因為使用的是預激活殘差塊來作為基礎構件塊。可見,相比之下,FishNet實作了更高的名額,而且參數也相對更少,FishNet-150(21.93%,26.4M)的參數接近于ResNet-50(23.78%,25.5M),但是top1誤差率低了。并且性能也超過了ResNet101(22.30%,44.5M)。在FLOPs上也實作了較好的表現。

FishNet與DenseNet: DenseNet通過串聯疊代地聚合具有相同分辨率的特征,然後通過過渡層在每個dense塊之間減小次元。根據圖4中的結果,DenseNet能夠使用更少的參數超過ResNet的精度。由于FishNet保留了更多樣化的特征并且更好地處理了梯度傳播問題,是以FishNet能夠以更少的參數實作比DenseNet更好的性能。 此外,FishNet的記憶體成本也低于DenseNet。以FishNet-150為例,當單個GPU上的批量大小為32時,FishNet-150的記憶體成本為6505M,比DenseNet-161(9269M)小2764M。

深度網絡之FishNet: A Versatile Backbone for Image, Region, and Pixel Level Prediction

FishNeXt與ResNeXt: FishNet的架構可以與其他類型的設計相結合,例如ResNeXt采用的通道分組。遵循以下标準: 同一級的每個塊(UR / DR塊和傳輸塊)的組中的通道數應該相同。 一旦階段索引增加1,單個組的寬度将加倍。這樣,基于ResNet的FishNet可以建構為基于ResNeXt的網絡,即FishNeXt。我們建構了一個具有2600萬個參數的緊湊型FishNeXt-150。FishNeXt-150的參數數量接近ResNeXt-50。從表1可以看出,與相應的ResNeXt架構相比,絕對top1錯誤率可降低0.7%。

消融研究

深度網絡之FishNet: A Versatile Backbone for Image, Region, and Pixel Level Prediction

池化與步幅卷積: 研究了基于FishNet-150的四種下采樣方法,包括卷積、核為2x2和3x3的最大池化,以及核為2x2的平均池化。

  • 如表2所示,應用2x2 max-pooling的性能優于其他方法。
  • Stride-Convolution将阻止(hinder)直接将損失梯度傳播到淺層,而池化則不會。
  • 還發現核為3x3的max-pooling比2x2更糟糕,因為結構資訊可能受到具有重疊的池化視窗的3x3的最大池化的幹擾。

When convolution with a stride of 2 is used, it is used for both the tail and the head of the FishNet.

When pooling is used, we still put a 1x1 convolution on the skip connection of the last residual blocks for each stage at the tail to change the number of channels between two stages, but we do not use such convolution at the head.

擴張卷積:[Dilated residual networks]發現 空間敏銳度的喪失可能導緻圖像分類準确性的限制。在FishNet中,UR-block将稀釋原始的低分辨率特征,是以,在body部分中采用擴張卷積。

  • 當在body上使用擴張卷積來上采樣時,基于FishNet-150,絕對top1錯誤率降低0.13%。
  • 然而,如果沒有引入任何擴張的模型中,在body和head中使用擴張卷積,則絕對top1錯誤率增加0.1%。
  • 此外,用兩個殘差塊替換第一個7x7步幅卷積層,這将減少絕對top1個誤差0.18%。

檢測與分割

We evaluate the generalization capability of FishNet on object detection and instance segmentation on MS COCO. For fair comparison, all models implemented by ourselves use the same settings except for the network backbone. All the codes implementing the results reported in this paper about object detection and instance segmentation are released at [​​https://github.com/open-mmlab/mmdetection​​].

資料集與名額:

  • There are 80 classes with bounding box annotations and pixel-wise instance mask annotations. It consists of:
  • 118k images for training (train-2017)
  • 5k images for validation (val-2017)
  • We train our models on the train-2017 and report results on the val-2017.
  • We evaluate all models with the standard COCO evaluation metrics AP (averaged mean Average Precision over different IoU thresholds), and the APS, APM, APL (AP at different scales).
深度網絡之FishNet: A Versatile Backbone for Image, Region, and Pixel Level Prediction

We re-implement the Feature Pyramid Networks (FPN) and Mask R-CNN based on PyTorch, and report the re-implemented results in Table 3.

  • Our re-implemented results are close to the results reported in Detectron[​​https://github.com/facebookresearch/detectron​​].
  • With FishNet, we trained all networks on 16 GPUs with batch size 16 (one per GPU) for 32 epochs.
  • SGD is used as the training optimizer with a learning rate 0.02, which is decreased by 10 at the 20 epoch and 28 epoch.
  • As the mini-batch size is small, the batch-normalization layers in our network are all fixed during the whole training process.
  • A warming-up training process is applied for 1 epoch
  • The gradients are clipped below a maximum hyper-parameter of 5.0 in the first 2 epochs to handle the huge gradients during the initial training stage.
  • The weights of the convolution on the resolution of 224x224 are all fixed. We use a weight decay of 0.0001 and a momentum of 0.9.
  • The networks are trained and tested in an end-to-end manner. All other hyper-parameters used in experiments follow those in [​​https://github.com/facebookresearch/detectron​​].

Object Detection Results Based on FPN. We report the results of detection using FPN with FishNet-150 on val-2017 for comparison. The top-down pathway and lateral connections(橫向連接配接) in FPN are attached to the fish head. As shown in Table 3, the FishNet-150 obtains a 2.6% absolute AP increase to ResNet-50, and a 1.3% absolute AP increase to ResNeXt-50.

Instance Segmentation and Object Detection Results Based on Mask R-CNN. Similar to the method adopted in FPN, we also plug FishNet into Mask R-CNN for simultaneous segmentation and detection(同時分割和檢測). As shown in Table 3, for the task of instance segmentation, 2.3% and 1.3% absolute AP gains are achieved compared to the ResNet-50 and ResNeXt-50. Moreover, when the network is trained in such multi-task fashion, the performance of object detection could be even better. With the FishNet plugged into the Mask R-CNN, 2.8% and 1.5% improvement in absolute AP have been observed compared to the ResNet-50 and ResNeXt-50 respectively.

Note that FishNet-150 does NOT use channel-wise grouping, and the number of parameters for FishNet-150 is close to that of ResNet-50 and ResNeXt-50. When compared with ResNeXt-50, FishNet-150 only reduces absolute error rate by 0.2% for image classification, while it improves the absolute AP by 1.3% and 1.5% respectively for object detection and instance segmentation. This shows that the FishNet provides features that are more effective for the region-level task of object detection and the pixel-level task of segmentation.

COCO Detection Challenge 2018. FishNet was used as one of the network backbones of the winning entry. By embedding the FishNet into our framework, the single model FishNeXt-229 could finally achieve 43.3% on the task of instance segmentation on the test-dev set.

總結

相關代碼

# https://github.com/kevin-ssy/FishNet/blob/master/models/fishnet.py
'''
FishNet
Author: Shuyang Sun
'''
from __future__ import division

import math

import torch
import torch.nn as nn
from torchsummary import summary


class Bottleneck(nn.Module):
    def __init__(self, inplanes, planes, stride=1, mode='NORM', k=1, dilation=1):
        """
        基礎殘差塊,用來建構整個網絡的基石

        :param inplanes: 輸入通道數
        :param planes: 輸出通道數,若是不等于輸入通道數,則使用孤立卷積進行處理
        :param stride: 步長,決定這是否調整分辨率,若調整分辨率,則使用孤立卷積進行處理,
            實際上代碼中并沒有使用非1的步長,是以這項沒有太大的意義,使用的是雙線性插值上采樣和
            最大遲化下采樣進行的調整
        :param mode: 快捷連接配接的模式
        :param k: 上采樣時,通道縮減比例
        :param dilation: 擴張率
        """
        super(Bottleneck, self).__init__()
        self.mode = mode
        # ReLU可以反複用,沒必要多次定義
        self.relu = nn.ReLU(inplace=True)
        self.k = k

        btnk_ch = planes // 4
        # 1x1
        self.bn1 = nn.BatchNorm2d(inplanes)
        self.conv1 = nn.Conv2d(inplanes, btnk_ch, kernel_size=1, bias=False)
        # 3x3 dilated
        self.bn2 = nn.BatchNorm2d(btnk_ch)
        self.conv2 = nn.Conv2d(btnk_ch, btnk_ch, kernel_size=3, stride=stride, padding=dilation,
                               dilation=dilation, bias=False)
        # 1x1
        self.bn3 = nn.BatchNorm2d(btnk_ch)
        self.conv3 = nn.Conv2d(btnk_ch, planes, kernel_size=1, bias=False)

        if mode == 'UP':
            self.shortcut = None
        elif inplanes != planes or stride > 1:
            # 隻有下采樣的時候或者通道改變的時候使用孤立卷積
            self.shortcut = nn.Sequential(
                nn.BatchNorm2d(inplanes),
                self.relu,
                nn.Conv2d(inplanes, planes, kernel_size=1, stride=stride, bias=False)
            )
        else:
            self.shortcut = None

    def _pre_act_forward(self, x):
        residual = x

        out = self.bn1(x)
        out = self.relu(out)
        out = self.conv1(out)

        out = self.bn2(out)
        out = self.relu(out)
        out = self.conv2(out)

        out = self.bn3(out)
        out = self.relu(out)
        out = self.conv3(out)

        if self.mode == 'UP':
            # 隻有上采樣的時候,要降低通道,這裡使用了分組融合的方式
            residual = self.squeeze_idt(x)
        elif self.shortcut is not None:
            residual = self.shortcut(residual)

        out += residual

        return out

    def squeeze_idt(self, idt):
        n, c, h, w = idt.size()
        # 注意這裡分組融合的實作方式,實作了由c到c//self.k的過渡
        return idt.view(n, c // self.k, self.k, h, w).sum(2)

    def forward(self, x):
        out = self._pre_act_forward(x)
        return out


class Fish(nn.Module):
    def __init__(self, block, num_cls=1000, num_down_sample=5, num_up_sample=3,
                 trans_map=(2, 1, 0, 6, 5, 4),
                 network_planes=None, num_res_blks=None, num_trans_blks=None):
        """
        魚形結構構造
        :param block: 基礎結構,這裡使用的是一個預激活殘差塊
        :param num_cls: 最終分類數量
        :param num_down_sample: 下采樣次數
        :param num_up_sample: 上采樣次數
        :param trans_map: 還不清楚
        :param network_planes: 網絡各層通道數
        :param num_res_blks: 各個位置殘差塊的數量
        :param num_trans_blks: 各個位置傳輸塊數量
        """
        super(Fish, self).__init__()
        self.block = block
        self.trans_map = trans_map
        self.upsample = nn.Upsample(scale_factor=2)
        # 研究了四種下采樣方法,包括卷積、核為2x2和3x3的最大池化,以及核為2x2的平均池化,其中2x2的最大池化效果最好
        # When pooling is used, we still put a 1x1 convolution on the skip
        # connection of the last residual blocks(涉及到了調整分辨率) for each
        # stage at the tail to change the number of channels
        # between two stages, but we do not use such convolution at the head.
        self.down_sample = nn.MaxPool2d(2, stride=2)
        self.num_cls = num_cls
        self.num_down = num_down_sample
        self.num_up = num_up_sample
        self.network_planes = network_planes[1:]
        self.depth = len(self.network_planes)
        self.num_trans_blks = num_trans_blks
        self.num_res_blks = num_res_blks
        # 建構網絡
        self.fish = self._make_fish(network_planes[0])

    def _make_score(self, in_ch, out_ch=1000, has_pool=False):
        """
             BatchNorm2d-396           [-1, 2112, 7, 7]           4,224
                    ReLU-397           [-1, 2112, 7, 7]               0
                  Conv2d-398           [-1, 1056, 7, 7]       2,230,272
             BatchNorm2d-399           [-1, 1056, 7, 7]           2,112
                    ReLU-400           [-1, 1056, 7, 7]               0
        AdaptiveAvgPool2d-401           [-1, 1056, 1, 1]               0
                  Conv2d-402           [-1, 1000, 1, 1]       1,057,000
        :param in_ch: 輸入通道數
        :param out_ch: 輸出通道數
        :param has_pool: 是否使用全局平均池化
        :return: [conv, fc]  前者輸出為in_ch//2,後者輸出為out_ch
        """
        bn = nn.BatchNorm2d(in_ch)
        relu = nn.ReLU(inplace=True)
        conv_trans = nn.Conv2d(in_ch, in_ch // 2, kernel_size=1, bias=False)
        bn_out = nn.BatchNorm2d(in_ch // 2)
        conv = nn.Sequential(bn, relu, conv_trans, bn_out, relu)

        if has_pool:
            fc = nn.Sequential(
                nn.AdaptiveAvgPool2d(1),
                nn.Conv2d(in_ch // 2, out_ch, kernel_size=1, bias=True)
            )
        else:
            fc = nn.Conv2d(in_ch // 2, out_ch, kernel_size=1, bias=True)

        # 因為上面的輸出還要結合前面的傳輸過來的特征,是以這裡還得将conv也輸出
        return [conv, fc]

    def _make_se_block(self, in_ch, out_ch):
        """
        構造了一個se通道注意力子產品:
        bn->relu->global_pool->conv1x1->relu->conv1x1->sigmoid
        """
        bn = nn.BatchNorm2d(in_ch)
        sq_conv = nn.Conv2d(in_ch, out_ch // 16, kernel_size=1)
        ex_conv = nn.Conv2d(out_ch // 16, out_ch, kernel_size=1)
        return nn.Sequential(bn,
                             nn.ReLU(inplace=True),
                             nn.AdaptiveAvgPool2d(1),
                             sq_conv,
                             nn.ReLU(inplace=True),
                             ex_conv,
                             nn.Sigmoid())

    def _make_residual_block(self, inplanes, outplanes, nstage, is_up=False, k=1, dilation=1):
        """
        在上下采樣之後(如果需要的話),緊跟一系列殘差塊,後面這些通道是一緻的。
        :param inplanes: 輸入的通道數
        :param outplanes: 輸出的通道數
        :param nstage: 該部分要堆疊多少個殘差塊
        :param is_up: 是否上采樣
        :param k: 上采樣的時候通道壓縮的比例
        :param dilation: 除了上下采樣部分後續殘差塊擴張率
        :return: nn.Sequential(*layers) 一個堆疊的殘差塊序列
        """
        layers = []

        if is_up:
            # 上采樣的時候,要通道縮減,使用函數r
            layers.append(self.block(inplanes, outplanes, mode='UP', dilation=dilation, k=k))
        else:
            # 其他的情況調整通道使用一個額外的孤立卷積
            layers.append(self.block(inplanes, outplanes, stride=1))

        # 每個階段中的殘差塊除了調整次元的那一個殘差塊之外的其餘殘差塊,這些都是直接的shortcut,同時,這些都是用擴張卷積的形式的
        for i in range(1, nstage):
            layers.append(self.block(outplanes, outplanes, stride=1, dilation=dilation))

        return nn.Sequential(*layers)

    def _make_stage(self, is_down_sample, inplanes, outplanes, n_blk, has_trans=True,
                    has_score=False, trans_planes=0, no_sampling=False, num_trans=2, **kwargs):
        """
        構造階段子產品,階段中的上下采樣隻是在最後輸出的時候,考慮最大池化下采樣還是雙線性插值上采樣
        :param is_down_sample: 是否遭過程中進行下采樣
        :param inplanes: 輸入的通道數,這裡應該是已經拼接之後的輸入通道數
        :param outplanes: 輸出的通道數
        :param n_blk: 每個曉得殘差塊序列内部殘差塊的數量
        :param has_trans: 是否有傳輸層
        :param has_score: 是否有得分層
        :param trans_planes: 傳輸通道
        :param no_sampling: 是否有采樣操作
        :param num_trans: 傳輸數量
        :param kwargs: 其他參數
        :return: 階段中的子產品清單
        """
        sample_block = []

        if has_score:
            sample_block.extend(self._make_score(outplanes, outplanes * 2, has_pool=False))

        # 這裡進行了上、下采樣之前需要的通道的調整,在調整完後會進行一系列(算上上下采樣部分總共有n_blk個)的殘差塊處理,隻是通道數都是一緻的
        if no_sampling or is_down_sample:
            # 對于階段中的下采樣,先進行殘差塊的建構,這裡建構殘差塊,也就是M(+r)的步驟
            res_block = self._make_residual_block(inplanes, outplanes, n_blk, **kwargs)
        else:
            # 上采樣需要制定is_up,因為它有特殊的處理,需要進行通道縮減
            res_block = self._make_residual_block(inplanes, outplanes, n_blk, is_up=True, **kwargs)
        sample_block.append(res_block)

        # 上下采樣之前會考慮拼接的來自傳輸層和上一階段的輸出
        # 上下采樣之前的調整結束之後,會考慮來自傳輸層的特征,這裡的num_trans表示傳輸層的殘差塊數量
        if has_trans:
            trans_in_planes = self.in_planes if trans_planes == 0 else trans_planes
            sample_block.append(
                self._make_residual_block(trans_in_planes, trans_in_planes, num_trans))

        # 上下采樣的部分,下采樣使用的是最大遲化,上采樣使用的是最鄰近插值
        if not no_sampling and is_down_sample:
            sample_block.append(self.down_sample)
        elif not no_sampling:  # Up-Sample
            sample_block.append(self.upsample)

        return nn.ModuleList(sample_block)

    def _make_fish(self, in_planes):
        """
        建構不同階段的子產品
        """
        def get_trans_planes(index):
            """擷取傳輸層的通道數"""
            map_id = self.trans_map[index - self.num_down - 1] - 1
            p = in_planes if map_id == -1 else cated_planes[map_id]
            return p

        def get_trans_blk(index):
            """擷取傳輸層的殘差塊數"""
            return self.num_trans_blks[index - self.num_down - 1]

        def get_cur_planes(index):
            """擷取目前階段的通道數"""
            return self.network_planes[index]

        def get_blk_num(index):
            """擷取目前階段的殘差塊數"""
            return self.num_res_blks[index]

        cated_planes, fish = [in_planes] * self.depth, []
        for i in range(self.depth):
            # even num for down-sample, odd for up-sample,根據奇偶索引确定上下采樣
            is_down = i not in range(self.num_down,
                                     self.num_down + self.num_up + 1)
            has_trans, no_sampling = i > self.num_down, i == self.num_down

            cur_planes, trans_planes = get_cur_planes(i), get_trans_planes(i)
            cur_blocks, num_trans = get_blk_num(i), get_trans_blk(i)

            stg_args = [is_down, cated_planes[i - 1], cur_planes, cur_blocks]

            if is_down or no_sampling:
                k, dilation = 1, 1
            else:
                k, dilation = cated_planes[i - 1] // cur_planes, \
                              2 ** (i - self.num_down - 1)

            # 建構階段塊
            sample_block = self._make_stage(*stg_args,
                                            has_trans=has_trans,
                                            trans_planes=trans_planes,
                                            has_score=(i == self.num_down),
                                            num_trans=num_trans,
                                            k=k,
                                            dilation=dilation,
                                            no_sampling=no_sampling)

            if i == self.depth - 1:
                # 在最後建構得分層
                sample_block.extend(self._make_score(
                    cur_planes + trans_planes, out_ch=self.num_cls, has_pool=True
                ))
            elif i == self.num_down:
                # 建構收縮擴張階段之間的se-block
                sample_block.append(nn.Sequential(
                    self._make_se_block(cur_planes * 2, cur_planes)
                ))

            if i == self.num_down - 1:
                cated_planes[i] = cur_planes * 2
            elif has_trans:
                cated_planes[i] = cur_planes + trans_planes
            else:
                cated_planes[i] = cur_planes
            fish.append(sample_block)
        return nn.ModuleList(fish)

    def _fish_forward(self, all_feat):
        def _concat(a, b):
            return torch.cat([a, b], dim=1)

        def stage_factory(*blks):
            """
            :param blks:
            :return:
            """
            def stage_forward(*inputs):
                if stg_id < self.num_down:  # tail
                    tail_blk = nn.Sequential(*blks[:2])
                    return tail_blk(*inputs)
                elif stg_id == self.num_down:
                    score_blks = nn.Sequential(*blks[:2])
                    score_feat = score_blks(inputs[0])
                    att_feat = blks[3](score_feat)
                    return blks[2](score_feat) * att_feat + att_feat
                else:  # refine
                    feat_trunk = blks[2](blks[0](inputs[0]))
                    feat_branch = blks[1](inputs[1])
                return _concat(feat_trunk, feat_branch)

            return stage_forward

        stg_id = 0
        # tail:
        while stg_id < self.depth:
            stg_blk = stage_factory(*self.fish[stg_id])

            if stg_id <= self.num_down:
                # 存放上一階段的輸出
                in_feat = [all_feat[stg_id]]
            else:
                # 存放上一階段的輸出和來自傳輸層的特征
                trans_id = self.trans_map[stg_id - self.num_down - 1]
                in_feat = [all_feat[stg_id], all_feat[trans_id]]
            # 使用上面的得到的特征更新all_feat
            all_feat[stg_id + 1] = stg_blk(*in_feat)

            # 更新索引
            stg_id += 1

            # loop exit,此時到了最後
            if stg_id == self.depth:
                # 最後的卷積
                score_feat = self.fish[self.depth - 1][-2](all_feat[-1])
                # 最後的fc
                score = self.fish[self.depth - 1][-1](score_feat)
                return score

    def forward(self, x):
        all_feat = [None] * (self.depth + 1)
        # 所有的特征的收集清單
        all_feat[0] = x
        return self._fish_forward(all_feat)


class FishNet(nn.Module):
    def __init__(self, block, **kwargs):
        """
        建構整體的網絡
        :param block: 網絡的基礎子產品,這裡實際使用了一個殘差塊
        :param kwargs: 網絡配置參數
        """
        super(FishNet, self).__init__()
        # 輸如通道數
        inplanes = kwargs['network_planes'][0]
        # 降低分辨率為56x56,注意,這裡使用的不是預激活的政策,而是Conv->BN->ReLU
        # resolution: 224x224 -> 56x56
        self.conv1 = self._conv_bn_relu(3, inplanes // 2, stride=2)  # out 32
        self.conv2 = self._conv_bn_relu(inplanes // 2, inplanes // 2)  # out 32
        self.conv3 = self._conv_bn_relu(inplanes // 2, inplanes)  # out 64
        self.pool1 = nn.MaxPool2d(3, padding=1, stride=2)

        # construct fish, resolution 56x56
        self.fish = Fish(block, **kwargs)

        # 網絡構造結束,初始權重參數
        self._init_weights()

    def _conv_bn_relu(self, in_ch, out_ch, stride=1):
        return nn.Sequential(
            nn.Conv2d(in_ch, out_ch, kernel_size=3, padding=1, stride=stride, bias=False),
            nn.BatchNorm2d(out_ch),
            nn.ReLU(inplace=True))

    def _init_weights(self):
        for m in self.modules():
            if isinstance(m, nn.Conv2d):
                n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels
                m.weight.data.normal_(0, math.sqrt(2. / n))
            elif isinstance(m, nn.BatchNorm2d):
                m.weight.data.fill_(1)
                m.bias.data.zero_()

    def forward(self, x):
        x = self.conv1(x)
        x = self.conv2(x)
        x = self.conv3(x)
        x = self.pool1(x)

        score = self.fish(x)

        # 1*1 output
        out = score.view(x.size(0), -1)

        return out


def fish(**kwargs):
    return FishNet(Bottleneck, **kwargs)


def fishnet99(**kwargs):
    """
    :return:
    """
    net_cfg = {
        #  input size:   [224, 56, 28,  14  |  7,   7,  14,  28 | 56,   28,  14]
        # output size:   [56,  28, 14,   7  |  7,  14,  28,  56 | 28,   14,   7]
        #                  |    |    |   |     |    |    |    |    |     |    |
        'network_planes': [64, 128, 256, 512, 512, 512, 384, 256, 320, 832, 1600],
        'num_res_blks': [2, 2, 6, 2, 1, 1, 1, 1, 2, 2],
        'num_trans_blks': [1, 1, 1, 1, 1, 4],
        'num_cls': 1000,
        'num_down_sample': 3,
        'num_up_sample': 3,
    }
    cfg = {**net_cfg, **kwargs}
    return fish(**cfg)


def fishnet150(**kwargs):
    """
    :return:
    """
    net_cfg = {
        #  input size:   [224, 56, 28,  14  |  7,   7,  14,  28 | 56,   28,  14]
        # output size:   [56,  28, 14,   7  |  7,  14,  28,  56 | 28,   14,   7]
        #                  |    |    |   |     |    |    |    |    |     |    |
        'network_planes': [64, 128, 256, 512, 512, 512, 384, 256, 320, 832, 1600],
        'num_res_blks': [2, 4, 8, 4, 2, 2, 2, 2, 2, 4],
        'num_trans_blks': [2, 2, 2, 2, 2, 4],
        'num_cls': 1000,
        'num_down_sample': 3,
        'num_up_sample': 3,
    }
    cfg = {**net_cfg, **kwargs}
    return fish(**cfg)


def fishnet201(**kwargs):
    """
    :return:
    """
    net_cfg = {
        #  input size:   [224, 56, 28,  14  |  7,   7,  14,  28 | 56,   28,  14]
        # output size:   [56,  28, 14,   7  |  7,  14,  28,  56 | 28,   14,   7]
        #                  |    |    |   |     |    |    |    |    |     |    |
        'network_planes': [64, 128, 256, 512, 512, 512, 384, 256, 320, 832, 1600],
        'num_res_blks': [3, 4, 12, 4, 2, 2, 2, 2, 3, 10],
        'num_trans_blks': [2, 2, 2, 2, 2, 9],
        'num_cls': 1000,
        'num_down_sample': 3,
        'num_up_sample': 3,
    }
    cfg = {**net_cfg, **kwargs}
    return fish(**cfg)


if __name__ == '__main__':
    in_data = torch.randint(0, 255, (1, 3, 224, 224), dtype=torch.float32)
    net = fishnet99()
    summary(net, input_size=(3, 224, 224), device='cpu')

"""
----------------------------------------------------------------
        Layer (type)               Output Shape         Param #
================================================================
            Conv2d-1         [-1, 32, 112, 112]             864
       BatchNorm2d-2         [-1, 32, 112, 112]              64
              ReLU-3         [-1, 32, 112, 112]               0
            Conv2d-4         [-1, 32, 112, 112]           9,216
       BatchNorm2d-5         [-1, 32, 112, 112]              64
              ReLU-6         [-1, 32, 112, 112]               0
            Conv2d-7         [-1, 64, 112, 112]          18,432
       BatchNorm2d-8         [-1, 64, 112, 112]             128
              ReLU-9         [-1, 64, 112, 112]               0
        MaxPool2d-10           [-1, 64, 56, 56]               0
      BatchNorm2d-11           [-1, 64, 56, 56]             128
             ReLU-12           [-1, 64, 56, 56]               0
             ReLU-13           [-1, 64, 56, 56]               0
           Conv2d-14           [-1, 32, 56, 56]           2,048
      BatchNorm2d-15           [-1, 32, 56, 56]              64
             ReLU-16           [-1, 32, 56, 56]               0
             ReLU-17           [-1, 32, 56, 56]               0
           Conv2d-18           [-1, 32, 56, 56]           9,216
      BatchNorm2d-19           [-1, 32, 56, 56]              64
             ReLU-20           [-1, 32, 56, 56]               0
             ReLU-21           [-1, 32, 56, 56]               0
           Conv2d-22          [-1, 128, 56, 56]           4,096
      BatchNorm2d-23           [-1, 64, 56, 56]             128
             ReLU-24           [-1, 64, 56, 56]               0
             ReLU-25           [-1, 64, 56, 56]               0
           Conv2d-26          [-1, 128, 56, 56]           8,192
       Bottleneck-27          [-1, 128, 56, 56]               0
      BatchNorm2d-28          [-1, 128, 56, 56]             256
             ReLU-29          [-1, 128, 56, 56]               0
           Conv2d-30           [-1, 32, 56, 56]           4,096
      BatchNorm2d-31           [-1, 32, 56, 56]              64
             ReLU-32           [-1, 32, 56, 56]               0
           Conv2d-33           [-1, 32, 56, 56]           9,216
      BatchNorm2d-34           [-1, 32, 56, 56]              64
             ReLU-35           [-1, 32, 56, 56]               0
           Conv2d-36          [-1, 128, 56, 56]           4,096
       Bottleneck-37          [-1, 128, 56, 56]               0
        MaxPool2d-38          [-1, 128, 28, 28]               0
        MaxPool2d-39          [-1, 128, 28, 28]               0
        MaxPool2d-40          [-1, 128, 28, 28]               0
        MaxPool2d-41          [-1, 128, 28, 28]               0
        MaxPool2d-42          [-1, 128, 28, 28]               0
        MaxPool2d-43          [-1, 128, 28, 28]               0
        MaxPool2d-44          [-1, 128, 28, 28]               0
      BatchNorm2d-45          [-1, 128, 28, 28]             256
             ReLU-46          [-1, 128, 28, 28]               0
             ReLU-47          [-1, 128, 28, 28]               0
           Conv2d-48           [-1, 64, 28, 28]           8,192
      BatchNorm2d-49           [-1, 64, 28, 28]             128
             ReLU-50           [-1, 64, 28, 28]               0
             ReLU-51           [-1, 64, 28, 28]               0
           Conv2d-52           [-1, 64, 28, 28]          36,864
      BatchNorm2d-53           [-1, 64, 28, 28]             128
             ReLU-54           [-1, 64, 28, 28]               0
             ReLU-55           [-1, 64, 28, 28]               0
           Conv2d-56          [-1, 256, 28, 28]          16,384
      BatchNorm2d-57          [-1, 128, 28, 28]             256
             ReLU-58          [-1, 128, 28, 28]               0
             ReLU-59          [-1, 128, 28, 28]               0
           Conv2d-60          [-1, 256, 28, 28]          32,768
       Bottleneck-61          [-1, 256, 28, 28]               0
      BatchNorm2d-62          [-1, 256, 28, 28]             512
             ReLU-63          [-1, 256, 28, 28]               0
           Conv2d-64           [-1, 64, 28, 28]          16,384
      BatchNorm2d-65           [-1, 64, 28, 28]             128
             ReLU-66           [-1, 64, 28, 28]               0
           Conv2d-67           [-1, 64, 28, 28]          36,864
      BatchNorm2d-68           [-1, 64, 28, 28]             128
             ReLU-69           [-1, 64, 28, 28]               0
           Conv2d-70          [-1, 256, 28, 28]          16,384
       Bottleneck-71          [-1, 256, 28, 28]               0
        MaxPool2d-72          [-1, 256, 14, 14]               0
        MaxPool2d-73          [-1, 256, 14, 14]               0
        MaxPool2d-74          [-1, 256, 14, 14]               0
        MaxPool2d-75          [-1, 256, 14, 14]               0
        MaxPool2d-76          [-1, 256, 14, 14]               0
        MaxPool2d-77          [-1, 256, 14, 14]               0
        MaxPool2d-78          [-1, 256, 14, 14]               0
      BatchNorm2d-79          [-1, 256, 14, 14]             512
             ReLU-80          [-1, 256, 14, 14]               0
             ReLU-81          [-1, 256, 14, 14]               0
           Conv2d-82          [-1, 128, 14, 14]          32,768
      BatchNorm2d-83          [-1, 128, 14, 14]             256
             ReLU-84          [-1, 128, 14, 14]               0
             ReLU-85          [-1, 128, 14, 14]               0
           Conv2d-86          [-1, 128, 14, 14]         147,456
      BatchNorm2d-87          [-1, 128, 14, 14]             256
             ReLU-88          [-1, 128, 14, 14]               0
             ReLU-89          [-1, 128, 14, 14]               0
           Conv2d-90          [-1, 512, 14, 14]          65,536
      BatchNorm2d-91          [-1, 256, 14, 14]             512
             ReLU-92          [-1, 256, 14, 14]               0
             ReLU-93          [-1, 256, 14, 14]               0
           Conv2d-94          [-1, 512, 14, 14]         131,072
       Bottleneck-95          [-1, 512, 14, 14]               0
      BatchNorm2d-96          [-1, 512, 14, 14]           1,024
             ReLU-97          [-1, 512, 14, 14]               0
           Conv2d-98          [-1, 128, 14, 14]          65,536
      BatchNorm2d-99          [-1, 128, 14, 14]             256
            ReLU-100          [-1, 128, 14, 14]               0
          Conv2d-101          [-1, 128, 14, 14]         147,456
     BatchNorm2d-102          [-1, 128, 14, 14]             256
            ReLU-103          [-1, 128, 14, 14]               0
          Conv2d-104          [-1, 512, 14, 14]          65,536
      Bottleneck-105          [-1, 512, 14, 14]               0
     BatchNorm2d-106          [-1, 512, 14, 14]           1,024
            ReLU-107          [-1, 512, 14, 14]               0
          Conv2d-108          [-1, 128, 14, 14]          65,536
     BatchNorm2d-109          [-1, 128, 14, 14]             256
            ReLU-110          [-1, 128, 14, 14]               0
          Conv2d-111          [-1, 128, 14, 14]         147,456
     BatchNorm2d-112          [-1, 128, 14, 14]             256
            ReLU-113          [-1, 128, 14, 14]               0
          Conv2d-114          [-1, 512, 14, 14]          65,536
      Bottleneck-115          [-1, 512, 14, 14]               0
     BatchNorm2d-116          [-1, 512, 14, 14]           1,024
            ReLU-117          [-1, 512, 14, 14]               0
          Conv2d-118          [-1, 128, 14, 14]          65,536
     BatchNorm2d-119          [-1, 128, 14, 14]             256
            ReLU-120          [-1, 128, 14, 14]               0
          Conv2d-121          [-1, 128, 14, 14]         147,456
     BatchNorm2d-122          [-1, 128, 14, 14]             256
            ReLU-123          [-1, 128, 14, 14]               0
          Conv2d-124          [-1, 512, 14, 14]          65,536
      Bottleneck-125          [-1, 512, 14, 14]               0
     BatchNorm2d-126          [-1, 512, 14, 14]           1,024
            ReLU-127          [-1, 512, 14, 14]               0
          Conv2d-128          [-1, 128, 14, 14]          65,536
     BatchNorm2d-129          [-1, 128, 14, 14]             256
            ReLU-130          [-1, 128, 14, 14]               0
          Conv2d-131          [-1, 128, 14, 14]         147,456
     BatchNorm2d-132          [-1, 128, 14, 14]             256
            ReLU-133          [-1, 128, 14, 14]               0
          Conv2d-134          [-1, 512, 14, 14]          65,536
      Bottleneck-135          [-1, 512, 14, 14]               0
     BatchNorm2d-136          [-1, 512, 14, 14]           1,024
            ReLU-137          [-1, 512, 14, 14]               0
          Conv2d-138          [-1, 128, 14, 14]          65,536
     BatchNorm2d-139          [-1, 128, 14, 14]             256
            ReLU-140          [-1, 128, 14, 14]               0
          Conv2d-141          [-1, 128, 14, 14]         147,456
     BatchNorm2d-142          [-1, 128, 14, 14]             256
            ReLU-143          [-1, 128, 14, 14]               0
          Conv2d-144          [-1, 512, 14, 14]          65,536
      Bottleneck-145          [-1, 512, 14, 14]               0
       MaxPool2d-146            [-1, 512, 7, 7]               0
       MaxPool2d-147            [-1, 512, 7, 7]               0
       MaxPool2d-148            [-1, 512, 7, 7]               0
       MaxPool2d-149            [-1, 512, 7, 7]               0
       MaxPool2d-150            [-1, 512, 7, 7]               0
       MaxPool2d-151            [-1, 512, 7, 7]               0
       MaxPool2d-152            [-1, 512, 7, 7]               0
     BatchNorm2d-153            [-1, 512, 7, 7]           1,024
            ReLU-154            [-1, 512, 7, 7]               0
          Conv2d-155            [-1, 256, 7, 7]         131,072
     BatchNorm2d-156            [-1, 256, 7, 7]             512
            ReLU-157            [-1, 256, 7, 7]               0
          Conv2d-158           [-1, 1024, 7, 7]         263,168
     BatchNorm2d-159           [-1, 1024, 7, 7]           2,048
            ReLU-160           [-1, 1024, 7, 7]               0
AdaptiveAvgPool2d-161           [-1, 1024, 1, 1]               0
          Conv2d-162             [-1, 32, 1, 1]          32,800
            ReLU-163             [-1, 32, 1, 1]               0
          Conv2d-164            [-1, 512, 1, 1]          16,896
         Sigmoid-165            [-1, 512, 1, 1]               0
     BatchNorm2d-166           [-1, 1024, 7, 7]           2,048
            ReLU-167           [-1, 1024, 7, 7]               0
            ReLU-168           [-1, 1024, 7, 7]               0
          Conv2d-169            [-1, 128, 7, 7]         131,072
     BatchNorm2d-170            [-1, 128, 7, 7]             256
            ReLU-171            [-1, 128, 7, 7]               0
            ReLU-172            [-1, 128, 7, 7]               0
          Conv2d-173            [-1, 128, 7, 7]         147,456
     BatchNorm2d-174            [-1, 128, 7, 7]             256
            ReLU-175            [-1, 128, 7, 7]               0
            ReLU-176            [-1, 128, 7, 7]               0
          Conv2d-177            [-1, 512, 7, 7]          65,536
     BatchNorm2d-178           [-1, 1024, 7, 7]           2,048
            ReLU-179           [-1, 1024, 7, 7]               0
            ReLU-180           [-1, 1024, 7, 7]               0
          Conv2d-181            [-1, 512, 7, 7]         524,288
      Bottleneck-182            [-1, 512, 7, 7]               0
     BatchNorm2d-183            [-1, 512, 7, 7]           1,024
            ReLU-184            [-1, 512, 7, 7]               0
          Conv2d-185            [-1, 128, 7, 7]          65,536
     BatchNorm2d-186            [-1, 128, 7, 7]             256
            ReLU-187            [-1, 128, 7, 7]               0
          Conv2d-188            [-1, 128, 7, 7]         147,456
     BatchNorm2d-189            [-1, 128, 7, 7]             256
            ReLU-190            [-1, 128, 7, 7]               0
          Conv2d-191            [-1, 512, 7, 7]          65,536
      Bottleneck-192            [-1, 512, 7, 7]               0
     BatchNorm2d-193            [-1, 512, 7, 7]           1,024
            ReLU-194            [-1, 512, 7, 7]               0
          Conv2d-195            [-1, 128, 7, 7]          65,536
     BatchNorm2d-196            [-1, 128, 7, 7]             256
            ReLU-197            [-1, 128, 7, 7]               0
          Conv2d-198            [-1, 128, 7, 7]         147,456
     BatchNorm2d-199            [-1, 128, 7, 7]             256
            ReLU-200            [-1, 128, 7, 7]               0
          Conv2d-201            [-1, 512, 7, 7]          65,536
      Bottleneck-202            [-1, 512, 7, 7]               0
        Upsample-203          [-1, 512, 14, 14]               0
        Upsample-204          [-1, 512, 14, 14]               0
        Upsample-205          [-1, 512, 14, 14]               0
        Upsample-206          [-1, 512, 14, 14]               0
     BatchNorm2d-207          [-1, 256, 14, 14]             512
            ReLU-208          [-1, 256, 14, 14]               0
          Conv2d-209           [-1, 64, 14, 14]          16,384
     BatchNorm2d-210           [-1, 64, 14, 14]             128
            ReLU-211           [-1, 64, 14, 14]               0
          Conv2d-212           [-1, 64, 14, 14]          36,864
     BatchNorm2d-213           [-1, 64, 14, 14]             128
            ReLU-214           [-1, 64, 14, 14]               0
          Conv2d-215          [-1, 256, 14, 14]          16,384
      Bottleneck-216          [-1, 256, 14, 14]               0
     BatchNorm2d-217          [-1, 768, 14, 14]           1,536
            ReLU-218          [-1, 768, 14, 14]               0
          Conv2d-219           [-1, 96, 14, 14]          73,728
     BatchNorm2d-220           [-1, 96, 14, 14]             192
            ReLU-221           [-1, 96, 14, 14]               0
          Conv2d-222           [-1, 96, 14, 14]          82,944
     BatchNorm2d-223           [-1, 96, 14, 14]             192
            ReLU-224           [-1, 96, 14, 14]               0
          Conv2d-225          [-1, 384, 14, 14]          36,864
      Bottleneck-226          [-1, 384, 14, 14]               0
        Upsample-227          [-1, 384, 28, 28]               0
        Upsample-228          [-1, 384, 28, 28]               0
        Upsample-229          [-1, 384, 28, 28]               0
        Upsample-230          [-1, 384, 28, 28]               0
     BatchNorm2d-231          [-1, 128, 28, 28]             256
            ReLU-232          [-1, 128, 28, 28]               0
          Conv2d-233           [-1, 32, 28, 28]           4,096
     BatchNorm2d-234           [-1, 32, 28, 28]              64
            ReLU-235           [-1, 32, 28, 28]               0
          Conv2d-236           [-1, 32, 28, 28]           9,216
     BatchNorm2d-237           [-1, 32, 28, 28]              64
            ReLU-238           [-1, 32, 28, 28]               0
          Conv2d-239          [-1, 128, 28, 28]           4,096
      Bottleneck-240          [-1, 128, 28, 28]               0
     BatchNorm2d-241          [-1, 512, 28, 28]           1,024
            ReLU-242          [-1, 512, 28, 28]               0
          Conv2d-243           [-1, 64, 28, 28]          32,768
     BatchNorm2d-244           [-1, 64, 28, 28]             128
            ReLU-245           [-1, 64, 28, 28]               0
          Conv2d-246           [-1, 64, 28, 28]          36,864
     BatchNorm2d-247           [-1, 64, 28, 28]             128
            ReLU-248           [-1, 64, 28, 28]               0
          Conv2d-249          [-1, 256, 28, 28]          16,384
      Bottleneck-250          [-1, 256, 28, 28]               0
        Upsample-251          [-1, 256, 56, 56]               0
        Upsample-252          [-1, 256, 56, 56]               0
        Upsample-253          [-1, 256, 56, 56]               0
        Upsample-254          [-1, 256, 56, 56]               0
     BatchNorm2d-255           [-1, 64, 56, 56]             128
            ReLU-256           [-1, 64, 56, 56]               0
          Conv2d-257           [-1, 16, 56, 56]           1,024
     BatchNorm2d-258           [-1, 16, 56, 56]              32
            ReLU-259           [-1, 16, 56, 56]               0
          Conv2d-260           [-1, 16, 56, 56]           2,304
     BatchNorm2d-261           [-1, 16, 56, 56]              32
            ReLU-262           [-1, 16, 56, 56]               0
          Conv2d-263           [-1, 64, 56, 56]           1,024
      Bottleneck-264           [-1, 64, 56, 56]               0
     BatchNorm2d-265          [-1, 320, 56, 56]             640
            ReLU-266          [-1, 320, 56, 56]               0
          Conv2d-267           [-1, 80, 56, 56]          25,600
     BatchNorm2d-268           [-1, 80, 56, 56]             160
            ReLU-269           [-1, 80, 56, 56]               0
          Conv2d-270           [-1, 80, 56, 56]          57,600
     BatchNorm2d-271           [-1, 80, 56, 56]             160
            ReLU-272           [-1, 80, 56, 56]               0
          Conv2d-273          [-1, 320, 56, 56]          25,600
      Bottleneck-274          [-1, 320, 56, 56]               0
       MaxPool2d-275          [-1, 320, 28, 28]               0
       MaxPool2d-276          [-1, 320, 28, 28]               0
       MaxPool2d-277          [-1, 320, 28, 28]               0
       MaxPool2d-278          [-1, 320, 28, 28]               0
       MaxPool2d-279          [-1, 320, 28, 28]               0
       MaxPool2d-280          [-1, 320, 28, 28]               0
       MaxPool2d-281          [-1, 320, 28, 28]               0
     BatchNorm2d-282          [-1, 512, 28, 28]           1,024
            ReLU-283          [-1, 512, 28, 28]               0
          Conv2d-284          [-1, 128, 28, 28]          65,536
     BatchNorm2d-285          [-1, 128, 28, 28]             256
            ReLU-286          [-1, 128, 28, 28]               0
          Conv2d-287          [-1, 128, 28, 28]         147,456
     BatchNorm2d-288          [-1, 128, 28, 28]             256
            ReLU-289          [-1, 128, 28, 28]               0
          Conv2d-290          [-1, 512, 28, 28]          65,536
      Bottleneck-291          [-1, 512, 28, 28]               0
     BatchNorm2d-292          [-1, 832, 28, 28]           1,664
            ReLU-293          [-1, 832, 28, 28]               0
          Conv2d-294          [-1, 208, 28, 28]         173,056
     BatchNorm2d-295          [-1, 208, 28, 28]             416
            ReLU-296          [-1, 208, 28, 28]               0
          Conv2d-297          [-1, 208, 28, 28]         389,376
     BatchNorm2d-298          [-1, 208, 28, 28]             416
            ReLU-299          [-1, 208, 28, 28]               0
          Conv2d-300          [-1, 832, 28, 28]         173,056
      Bottleneck-301          [-1, 832, 28, 28]               0
     BatchNorm2d-302          [-1, 832, 28, 28]           1,664
            ReLU-303          [-1, 832, 28, 28]               0
          Conv2d-304          [-1, 208, 28, 28]         173,056
     BatchNorm2d-305          [-1, 208, 28, 28]             416
            ReLU-306          [-1, 208, 28, 28]               0
          Conv2d-307          [-1, 208, 28, 28]         389,376
     BatchNorm2d-308          [-1, 208, 28, 28]             416
            ReLU-309          [-1, 208, 28, 28]               0
          Conv2d-310          [-1, 832, 28, 28]         173,056
      Bottleneck-311          [-1, 832, 28, 28]               0
       MaxPool2d-312          [-1, 832, 14, 14]               0
       MaxPool2d-313          [-1, 832, 14, 14]               0
       MaxPool2d-314          [-1, 832, 14, 14]               0
       MaxPool2d-315          [-1, 832, 14, 14]               0
       MaxPool2d-316          [-1, 832, 14, 14]               0
       MaxPool2d-317          [-1, 832, 14, 14]               0
       MaxPool2d-318          [-1, 832, 14, 14]               0
     BatchNorm2d-319          [-1, 768, 14, 14]           1,536
            ReLU-320          [-1, 768, 14, 14]               0
          Conv2d-321          [-1, 192, 14, 14]         147,456
     BatchNorm2d-322          [-1, 192, 14, 14]             384
            ReLU-323          [-1, 192, 14, 14]               0
          Conv2d-324          [-1, 192, 14, 14]         331,776
     BatchNorm2d-325          [-1, 192, 14, 14]             384
            ReLU-326          [-1, 192, 14, 14]               0
          Conv2d-327          [-1, 768, 14, 14]         147,456
      Bottleneck-328          [-1, 768, 14, 14]               0
     BatchNorm2d-329         [-1, 1600, 14, 14]           3,200
            ReLU-330         [-1, 1600, 14, 14]               0
          Conv2d-331          [-1, 400, 14, 14]         640,000
     BatchNorm2d-332          [-1, 400, 14, 14]             800
            ReLU-333          [-1, 400, 14, 14]               0
          Conv2d-334          [-1, 400, 14, 14]       1,440,000
     BatchNorm2d-335          [-1, 400, 14, 14]             800
            ReLU-336          [-1, 400, 14, 14]               0
          Conv2d-337         [-1, 1600, 14, 14]         640,000
      Bottleneck-338         [-1, 1600, 14, 14]               0
     BatchNorm2d-339         [-1, 1600, 14, 14]           3,200
            ReLU-340         [-1, 1600, 14, 14]               0
          Conv2d-341          [-1, 400, 14, 14]         640,000
     BatchNorm2d-342          [-1, 400, 14, 14]             800
            ReLU-343          [-1, 400, 14, 14]               0
          Conv2d-344          [-1, 400, 14, 14]       1,440,000
     BatchNorm2d-345          [-1, 400, 14, 14]             800
            ReLU-346          [-1, 400, 14, 14]               0
          Conv2d-347         [-1, 1600, 14, 14]         640,000
      Bottleneck-348         [-1, 1600, 14, 14]               0
       MaxPool2d-349           [-1, 1600, 7, 7]               0
       MaxPool2d-350           [-1, 1600, 7, 7]               0
       MaxPool2d-351           [-1, 1600, 7, 7]               0
       MaxPool2d-352           [-1, 1600, 7, 7]               0
       MaxPool2d-353           [-1, 1600, 7, 7]               0
       MaxPool2d-354           [-1, 1600, 7, 7]               0
       MaxPool2d-355           [-1, 1600, 7, 7]               0
     BatchNorm2d-356            [-1, 512, 7, 7]           1,024
            ReLU-357            [-1, 512, 7, 7]               0
          Conv2d-358            [-1, 128, 7, 7]          65,536
     BatchNorm2d-359            [-1, 128, 7, 7]             256
            ReLU-360            [-1, 128, 7, 7]               0
          Conv2d-361            [-1, 128, 7, 7]         147,456
     BatchNorm2d-362            [-1, 128, 7, 7]             256
            ReLU-363            [-1, 128, 7, 7]               0
          Conv2d-364            [-1, 512, 7, 7]          65,536
      Bottleneck-365            [-1, 512, 7, 7]               0
     BatchNorm2d-366            [-1, 512, 7, 7]           1,024
            ReLU-367            [-1, 512, 7, 7]               0
          Conv2d-368            [-1, 128, 7, 7]          65,536
     BatchNorm2d-369            [-1, 128, 7, 7]             256
            ReLU-370            [-1, 128, 7, 7]               0
          Conv2d-371            [-1, 128, 7, 7]         147,456
     BatchNorm2d-372            [-1, 128, 7, 7]             256
            ReLU-373            [-1, 128, 7, 7]               0
          Conv2d-374            [-1, 512, 7, 7]          65,536
      Bottleneck-375            [-1, 512, 7, 7]               0
     BatchNorm2d-376            [-1, 512, 7, 7]           1,024
            ReLU-377            [-1, 512, 7, 7]               0
          Conv2d-378            [-1, 128, 7, 7]          65,536
     BatchNorm2d-379            [-1, 128, 7, 7]             256
            ReLU-380            [-1, 128, 7, 7]               0
          Conv2d-381            [-1, 128, 7, 7]         147,456
     BatchNorm2d-382            [-1, 128, 7, 7]             256
            ReLU-383            [-1, 128, 7, 7]               0
          Conv2d-384            [-1, 512, 7, 7]          65,536
      Bottleneck-385            [-1, 512, 7, 7]               0
     BatchNorm2d-386            [-1, 512, 7, 7]           1,024
            ReLU-387            [-1, 512, 7, 7]               0
          Conv2d-388            [-1, 128, 7, 7]          65,536
     BatchNorm2d-389            [-1, 128, 7, 7]             256
            ReLU-390            [-1, 128, 7, 7]               0
          Conv2d-391            [-1, 128, 7, 7]         147,456
     BatchNorm2d-392            [-1, 128, 7, 7]             256
            ReLU-393            [-1, 128, 7, 7]               0
          Conv2d-394            [-1, 512, 7, 7]          65,536
      Bottleneck-395            [-1, 512, 7, 7]               0
     BatchNorm2d-396           [-1, 2112, 7, 7]           4,224
            ReLU-397           [-1, 2112, 7, 7]               0
          Conv2d-398           [-1, 1056, 7, 7]       2,230,272
     BatchNorm2d-399           [-1, 1056, 7, 7]           2,112
            ReLU-400           [-1, 1056, 7, 7]               0
AdaptiveAvgPool2d-401           [-1, 1056, 1, 1]               0
          Conv2d-402           [-1, 1000, 1, 1]       1,057,000
            Fish-403           [-1, 1000, 1, 1]               0
================================================================
Total params: 16,628,904
Trainable params: 16,628,904
Non-trainable params: 0
----------------------------------------------------------------
Input size (MB): 0.57
Forward/backward pass size (MB): 390.95
Params size (MB): 63.43
Estimated Total Size (MB): 454.96
----------------------------------------------------------------
"""      

相關連結

  • 代碼:​​https://github.com/kevin-ssy/FishNet​​
  • 講解:​​https://linkinpark213.com/2019/04/21/fishnet/​​

繼續閱讀