1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        【深度學(xué)習(xí)】基于PyTorch的卷積神經(jīng)網(wǎng)絡(luò)經(jīng)典BackBone(骨干網(wǎng)絡(luò))復(fù)現(xiàn)

        共 1961字,需瀏覽 4分鐘

         ·

        2022-05-27 21:26

        ??作者丨helton_yan@CSDN(已授權(quán))
        來源丨h(huán)ttps://blog.csdn.net/SESESssss/article/details/114340066
        編輯丨極市平臺

        導(dǎo)讀

        ?

        本文基于代碼實戰(zhàn)復(fù)現(xiàn)了經(jīng)典的Backbone結(jié)構(gòu)Inception v1、ResNet-50和FPN,基于PyTorch分享一些網(wǎng)絡(luò)搭建技巧,很詳細(xì)很干貨!

        文章目錄

        • 1.VGG

        • 1.1改進:

        • 1.2 PyTorch復(fù)現(xiàn)VGG19

        • 1.2.1 小Tips:

        • 1.2.2 打印網(wǎng)絡(luò)信息:

        • Inception(GoogLeNet)

        • 2.1改進(Inception v1)

        • 2.2.2改進(Inception v2)

        • 2.2 PyTorch復(fù)現(xiàn)Inception v1:

        • 2.2.1 網(wǎng)絡(luò)的整體框架:

        • 2.2.2 各層的參數(shù)情況:

        • 2.2.3 pytorch復(fù)現(xiàn)Inception基礎(chǔ)模塊

        • 2.2.4 小Tips

        • ResNet

        • 3.1改進

        • 3.2PyTorch 復(fù)現(xiàn) ResNet-50

        • 3.2.1ResNet-50網(wǎng)絡(luò)整體架構(gòu)

        • 3.2.2 Bottleneck結(jié)構(gòu)

        • 3.2.3 ResNet-50圖解及各層參數(shù)細(xì)節(jié)

        • 3.2.4 實現(xiàn)一個Bottleneck模塊:

        • 3.2.5 實現(xiàn)resnet-50

        • FPN(特征金字塔)

        • 4.1 特征的語義信息

        • 4.2 改進

        • 4.3 PyTorch 復(fù)現(xiàn) FPN

        • 4.3.1 FPN網(wǎng)絡(luò)架構(gòu)

        • 4.3.2 復(fù)現(xiàn)FPN

        前言

        卷積神經(jīng)網(wǎng)絡(luò)的發(fā)展,從上個世紀(jì)就已經(jīng)開始了,讓時間回到1998年,在當(dāng)時,Yann LeCun 教授提出了一種較為成熟的卷積神經(jīng)網(wǎng)絡(luò)架構(gòu)LeNet-5,現(xiàn)在被譽為卷積神經(jīng)網(wǎng)絡(luò)的“HelloWorld”,但由于當(dāng)時計算機算力的局限性以及支持向量機(核學(xué)習(xí)方法)的興起,CNN方法并不是當(dāng)時學(xué)術(shù)界認(rèn)可的主流方法。時間推移到14年后,隨著AlexNet以高出第二名約10%的accuracy rate成為了2012年ImageNet圖像識別競賽的第一名,深度學(xué)習(xí)以及卷積神經(jīng)網(wǎng)絡(luò)的研究熱潮被徹底引爆,從此CNN進入了飛速發(fā)展的階段,從無人問津到一度成為計算機視覺的主流框架,在此之后,各種基于CNN的圖像識別網(wǎng)絡(luò)開始大放異彩。各種CNN網(wǎng)絡(luò)層出不窮。

        本次博客將介紹如今圖像識別領(lǐng)域十分經(jīng)典的一些CNN網(wǎng)絡(luò),雖然現(xiàn)在卷積網(wǎng)絡(luò)框架也隨著研究的深入變得越來越復(fù)雜,但我們?nèi)匀豢梢栽谝恍┳钚碌木W(wǎng)絡(luò)結(jié)構(gòu)中發(fā)現(xiàn)它們的身影,這些經(jīng)典CNN網(wǎng)絡(luò)有時候是整個算法提取特征的骨架(特征的質(zhì)量往往直接影響到分類結(jié)果的準(zhǔn)確度,表達(dá)能力更強的特征也能給模型帶來更強的分類能力),因此又稱為“Backbone”(骨干網(wǎng)絡(luò))。

        本次博客基于代碼實戰(zhàn)復(fù)現(xiàn)經(jīng)典的Backbone結(jié)構(gòu),并基于PyTorch分享一些網(wǎng)絡(luò)搭建技巧。

        1.VGG

        網(wǎng)絡(luò)架構(gòu):

        VGG16網(wǎng)絡(luò)由13層卷積層+3層全連接層構(gòu)成。

        1.1改進:

        1. 更小的卷積核,對比AlexNet,VGG網(wǎng)絡(luò)使用的卷積核大小不超過3x3,這種結(jié)構(gòu)相比于大卷積核有一個優(yōu)點,就是兩個3x3的卷積核堆疊對于原圖提取特征的感受野(特征圖一個像素融合了輸入多少像素的信息決定了感受野的大小)相當(dāng)于一個5x5卷積核(如圖),并且在同等感受野的條件下,兩個3x3卷積之間加入激活函數(shù),其非線性能力比單個5x5卷積要強。

        2. 更深的網(wǎng)絡(luò)結(jié)構(gòu),相比于AlexNet只有5層卷積層,VGG系列加深了網(wǎng)絡(luò)的深度,更深的結(jié)構(gòu)有助于網(wǎng)絡(luò)提取圖像中更復(fù)雜的語義信息。

        1.2 PyTorch復(fù)現(xiàn)VGG19

        class?VGG19(nn.Module):
        ?def?__init__(self,?num_classes?=?1000):?#?num_classes?預(yù)分類數(shù)

        ??super(VGG19,?self).__init__()

        ??#構(gòu)造特征提取層:
        ??feature_layers?=?[]?#?將卷積層存儲在list中
        ??in_dim?=?3?#?輸入是三通道圖像
        ??out_dim?=?64?#?輸出特征的深度為64

        ??#采用循環(huán)構(gòu)造的方式,對于深度網(wǎng)絡(luò)能避免代碼形式冗余:
        ??for?i?in?range(16):#?vgg19共16層卷積
        ???feature_layers?+=?[nn.Conv2d(in_dim,?out_dim,3,1,1),?nn.ReLU(inplace?=?True)]?#?基本結(jié)構(gòu):卷積+激活函數(shù)
        ???in_dim?=?out_dim
        ???#?在第2,4,8,12,16,層卷積后增加最大池化:
        ???if?i?==?1?or?i?==?3?or?i?==?7?or?i?==?11?or?i?==?15?:
        ????feature_layers?+=?[nn.MaxPool2d(2)]
        ????if?i?11:
        ?????out_dim?*=?2
        ????self.features?=?nn.Sequential(*feature_layers)?
        ????????????????#?*表示傳入?yún)?shù)的數(shù)量不固定,否則報錯list?is?not?a?Module?subclass


        ??#全連接層分類:
        ??self.classifier?=?nn.Sequential(
        ???nn.Linear(512?*?7?*?7,?4096),
        ???nn.ReLU(inplace?=?True),
        ???nn.Dropout(),
        ???nn.Linear(4096,4096),
        ???nn.ReLU(inplace?=?True),
        ???nn.Dropout(),
        ???nn.Linear(4096,num_classes),
        ???)

        ?#前向傳播
        ?def?forward(self,?x):
        ??x?=?self.features(x)
        ??x?=?x.view(x.size(0),?-1)
        ??x?=?self.classifier(x)
        ??return?x

        1.2.1 小Tips:

        1. 當(dāng)網(wǎng)絡(luò)的結(jié)構(gòu)重復(fù)時,使用for循環(huán)構(gòu)造避免代碼形式冗余

        2. 將不同功能的網(wǎng)絡(luò)各自封裝到一個大的Sequential模塊中,結(jié)構(gòu)分明

        3. 卷積操作輸出尺寸計算公式:Out=(In-Kernel+2Padding)/Stride+1 (Kernel:卷積核尺寸,Stride:步長,Padding:邊界填充) 若要保證輸出尺寸和原尺寸一致,Padding可以設(shè)置為:Padding = (kernel-1)/2)

        4. 池化操作輸出尺寸計算公式同卷積操作一致

        5. 在實際深度學(xué)習(xí)框架實現(xiàn)卷積和全連接的計算中,本質(zhì)都是矩陣運算:

          若輸入的特征圖深度是N,輸出特征圖深度是M,則卷積核的維度是:NxMxKxK(K為卷積核大小)。因此全卷積網(wǎng)絡(luò)對輸入圖像的尺寸沒有要求。

          全連接層的尺寸和輸入的特征尺寸相關(guān)(將特征圖展平成為一維向量),若輸入的特征向量是1xN,輸出是1xM,則全連接層的維度是:MxN。

        1.2.2 打印網(wǎng)絡(luò)信息:

        使用torch.summary輸出網(wǎng)絡(luò)架構(gòu):

        vgg19?=?VGG19()

        #print(vgg19)?#輸出網(wǎng)絡(luò)的架構(gòu)
        summary(vgg19,?input_size?=?[(3,?224,?224)])?#輸出網(wǎng)絡(luò)架構(gòu),每一層的輸出特征尺寸,及網(wǎng)絡(luò)參數(shù)情況

        輸出網(wǎng)絡(luò)每一層的尺寸:

        for?param?in?vgg19.parameters():?#?輸出每一層網(wǎng)絡(luò)的尺寸
        ?print(param.size())


        batch_size?=?16
        input?=?torch.randn(batch_size,?3,?224,?224)?#構(gòu)建一個隨機數(shù)據(jù),模擬一個batch_size
        output?=?vgg19(input)
        print(output.shape)??#?torch.Size([16,?1000])

        2.Inception(GoogLeNet)

        2.1改進(Inception v1)

        以往網(wǎng)絡(luò)的不足:

        1. 加深深度導(dǎo)致的網(wǎng)絡(luò)參數(shù)增加
        2. 深層網(wǎng)絡(luò)需要更多的訓(xùn)練數(shù)據(jù),容易產(chǎn)生過擬合
        3. 深層網(wǎng)絡(luò)在訓(xùn)練過程中容易導(dǎo)致梯度消失

        改進:

        1. 引入了Inception模塊作為網(wǎng)絡(luò)的基礎(chǔ)模塊,整體的網(wǎng)絡(luò)基于基礎(chǔ)模塊的堆疊;在模塊中使用了通道拼接(Concat)的方法對不同卷積核提取的特征進行拼接

          Inception基礎(chǔ)的模塊如圖所示,使用3個不同尺寸的卷積核進行卷積運算,同時還包括一個最大池化,最后將這四個部分輸出的結(jié)果進行通道拼接,傳給下一層:

        1. 使用1x1卷積進行數(shù)據(jù)降維(減少深度),減少訓(xùn)練的參數(shù)量。

          上圖這個結(jié)構(gòu)有一個弊端,即模塊中一個分支的輸入通道數(shù)就是前一個模塊所有分支輸出通道數(shù)之和(通道合并),在多個模塊堆疊后計算的參數(shù)量將會變得十分巨大,為了解決這個問題,作者在每一個分支的卷積層之前單獨加了一個1x1卷積,來進行通道數(shù)的降維

        我們或許會有一個疑問,為什么不在3x3或5x5卷積輸出上直接降維特征,而非得使用1x1卷積呢,(作者認(rèn)為這樣做能夠增加網(wǎng)絡(luò)的非線性能力,因為卷積和卷積之間有激活函數(shù))

        1. 引入輔助分類器(在不同深度計算分類最后一并回傳計算損失)

          作者發(fā)現(xiàn)網(wǎng)絡(luò)中間層的特征和較深層的特征有很大的不同,因此在訓(xùn)練時額外在中間層增加了兩個輔助分類器。輔助分類器的結(jié)果同輸出結(jié)果一并計算損失,并且輔助分類器的損失為網(wǎng)絡(luò)總損失的0.3。作者認(rèn)為這樣的結(jié)構(gòu)有利于增強網(wǎng)絡(luò)在較淺層特征的分類能力,**相當(dāng)于給網(wǎng)絡(luò)加了一個額外的約束(正則化)**,并且在推理時這些輔助網(wǎng)絡(luò)的結(jié)構(gòu)將被舍棄。

        2.2.2改進(Inception v2)

        卷積分解

        Inception v2較Inception v1將5x5的大卷積分解成兩個3x3的小卷積(效仿VGG網(wǎng)絡(luò)的處理方式,減少了參數(shù)量同時增加網(wǎng)絡(luò)的非線性能力),并加入了BN層:

        進一步的,Inception v2將nxn卷積分解為兩個1xn和nx1卷積(空間可分離卷積Spatially Separable Convolution),在感受野相當(dāng)?shù)那闆r下,進一步減少了網(wǎng)絡(luò)的參數(shù):


        參考:

        Inception系列之Inception_v2-v3:https://www.cnblogs.com/wxkang/p/13955363.html

        [論文筆記] Xception:https://zhuanlan.zhihu.com/p/127042277

        2.2 PyTorch復(fù)現(xiàn)Inception v1:

        2.2.1 網(wǎng)絡(luò)的整體框架:

        2.2.2 各層的參數(shù)情況:

        紅色框表示用于特征降維的1x1卷積

        2.2.3 pytorch復(fù)現(xiàn)Inception基礎(chǔ)模塊

        將卷積+激活函數(shù)作為一個基礎(chǔ)的卷積組:

        #?將Conv+ReLU封裝成一個基礎(chǔ)類:
        class?BasicConv2d(nn.Module):
        ????def?__init__(self,?in_channel,?out_channel,?kernel_size,?stride=1,?padding=0):
        ????????super(BasicConv2d,?self).__init__()
        ????????self.conv?=?nn.Sequential(
        ????????????nn.Conv2d(in_channel,?out_channel,?kernel_size,
        ??????????????????????stride=stride,?padding=padding),
        ????????????nn.ReLU(True)
        ????????)

        ????def?forward(self,?x):
        ????????x?=?self.conv(x)
        ????????return?x

        構(gòu)造一個Inception模塊:

        #?構(gòu)造Inception基礎(chǔ)模塊:
        class?Inception(nn.Module):
        ????def?__init__(self,?in_dim,?out_1x1,?out_3x3_reduce,?out_3x3,?out_5x5_reduce,?out_5x5,?out_pool):
        ????????super(Inception,?self).__init__()
        ????????#?分支1:
        ????????self.branch_1x1?=?BasicConv2d(in_dim,?out_1x1,?1)
        ????????#?分支2:
        ????????self.branch_3x3?=?nn.Sequential(
        ????????????BasicConv2d(in_dim,?out_3x3_reduce,?1),
        ????????????BasicConv2d(out_3x3_reduce,?out_3x3,?3,?padding=1),
        ????????)
        ????????#?分支3:
        ????????self.branch_5x5?=?nn.Sequential(
        ????????????BasicConv2d(in_dim,?out_5x5_reduce,?1),
        ????????????BasicConv2d(out_5x5_reduce,?out_5x5,?5,?padding=2),
        ????????)
        ????????#?分支4:
        ????????self.branch_pool?=?nn.Sequential(
        ????????????nn.MaxPool2d(3,?stride=1,?padding=1),
        ????????????BasicConv2d(in_dim,?out_pool,?1),
        ????????)

        ????def?forward(self,?x):
        ????????b1?=?self.branch_1x1(x)
        ????????b2?=?self.branch_3x3(x)
        ????????b3?=?self.branch_5x5(x)
        ????????b4?=?self.branch_pool(x)

        ????????output?=?torch.cat((b1,?b2,?b3,?b4),?dim=1)??#?四個模塊沿特征圖通道方向拼接
        ????????return?output

        搭建完整的Inceptionv1:

        #?構(gòu)建Inceptionv1:
        class?Inception_v1(nn.Module):
        ????def?__init__(self,?num_classes=1000,?state="test"):
        ????????super(Inception_v1,?self).__init__()
        ????????self.state?=?state
        ????????self.block1?=?nn.Sequential(
        ????????????BasicConv2d(3,?64,?7,?stride=2,?padding=3),
        ????????????nn.MaxPool2d(kernel_size=3,?stride=2,?padding=1),
        ????????????nn.LocalResponseNorm(64),
        ????????????BasicConv2d(64,?64,?1),
        ????????????BasicConv2d(64,?192,?3,?padding=1),
        ????????????nn.LocalResponseNorm(192),
        ????????????nn.MaxPool2d(kernel_size=3,?stride=2,?padding=1),
        ????????)
        ????????self.block2?=?nn.Sequential(
        ????????????Inception(192,?64,?96,?128,?16,?32,?32),
        ????????????Inception(256,?128,?128,?192,?32,?96,?64),
        ????????????nn.MaxPool2d(kernel_size=3,?stride=2,?padding=1),
        ????????????Inception(480,?192,?96,?208,?16,?48,?64),
        ????????)
        ????????self.block3?=?nn.Sequential(
        ????????????Inception(512,?160,?112,?224,?24,?64,?64),
        ????????????Inception(512,?128,?128,?256,?24,?64,?64),
        ????????????Inception(512,?112,?144,?288,?32,?64,?64),
        ????????)
        ????????self.block4?=?nn.Sequential(
        ????????????nn.MaxPool2d(kernel_size=3,?stride=2,?padding=1),
        ????????????Inception(528,?256,?160,?320,?32,?128,?128),
        ????????????Inception(832,?256,?160,?320,?32,?128,?128),
        ????????????Inception(832,?384,?192,?384,?48,?128,?128),
        ????????????nn.AvgPool2d(3,?stride=1),
        ????????)
        ????????self.classifier?=?nn.Linear(4096,?num_classes)

        ????????if?state?==?"train":
        ????????????#?兩個輔助分類器:
        ????????????self.aux_classifier1?=?Inception_classify(
        ????????????????192?+?208?+?48?+?64,?num_classes)
        ????????????self.aux_classifier2?=?Inception_classify(
        ????????????????112?+?288?+?64?+?64,?num_classes)

        ????def?forward(self,?x):
        ????????x?=?self.block1(x)
        ????????x?=?self.block2(x)
        ????????#?插入輔助分類層1
        ????????if?self.state?==?'train':
        ????????????aux1?=?self.aux_classifier1(x)
        ????????x?=?self.block3(x)
        ????????#?插入輔助分類層2
        ????????if?self.state?==?'train':
        ????????????aux2?=?self.aux_classifier2(x)
        ????????x?=?self.block4(x)
        ????????x?=?x.view(x.size(0),?-1)
        ????????out?=?self.classifier(x)

        ????????if?self.state?==?'train':
        ????????????return?aux1,?aux2,?out
        ????????else:
        ????????????return?out

        2.2.4 小Tips

        在構(gòu)建比較復(fù)雜的網(wǎng)絡(luò)時,將網(wǎng)絡(luò)重疊使用的一些基礎(chǔ)模塊封裝為一個基礎(chǔ)的類(層次分明)。

        3.ResNet

        在以往的經(jīng)驗上,人們普遍認(rèn)為通過加深網(wǎng)絡(luò)的層數(shù)能夠使得網(wǎng)絡(luò)具有更強的學(xué)習(xí)能力,即使網(wǎng)絡(luò)容易產(chǎn)生過擬合/梯度消失的問題,在現(xiàn)有方法下也可以通過增加數(shù)據(jù)集,Dropout或者正則化/加入BN層解決。但是通過實驗數(shù)據(jù)發(fā)現(xiàn),即使加入有效的措施抑制網(wǎng)絡(luò)產(chǎn)生過擬合或者梯度消失,網(wǎng)絡(luò)的精度也會隨著深度的增加而下降,并且還不是由于過擬合引起的(實驗數(shù)據(jù)表明越深的網(wǎng)絡(luò)training loss反而越高)

        事實上,阻礙網(wǎng)絡(luò)向深度發(fā)展的一個主要因素就是梯度不能得到有效的傳播,越深的網(wǎng)絡(luò)反傳過程中的梯度相關(guān)性會越來越差,接近于白噪聲,導(dǎo)致梯度的更新也相當(dāng)于隨機擾動。

        Resnet到底在解決一個什么問題呢?https://www.zhihu.com/question/64494691

        打個形象的比喻,就如我們小時候玩過的口傳悄悄話游戲,隨著參與人數(shù)的增多,最后一個人口中說出的信息往往早已和原先紙條上的信息大相徑庭。

        3.1 改進

        以往的瓶頸:深度網(wǎng)絡(luò)不可控的梯度消失,深層網(wǎng)絡(luò)與淺層網(wǎng)絡(luò)的梯度相關(guān)性下降,網(wǎng)絡(luò)難以訓(xùn)練。

        ResNet的改進:引入了一個殘差映射的結(jié)構(gòu)來解決網(wǎng)絡(luò)退化的問題:

        何為殘差映射?

        假設(shè)輸入的特征為x,期望輸出的特征為H(x)。我們知道,對于一般的神經(jīng)網(wǎng)絡(luò)而言,每一層的目的無非就是對輸入x進行非線性變換,將特征x映射到盡量趨近H(x),即,網(wǎng)絡(luò)需要直接擬合輸出H(x).

        而對于殘差映射,模塊中通過引入一個shortcut分支(恒等映射),將網(wǎng)絡(luò)需要擬合的映射變?yōu)闅埐頕(x):F(x) = H(x) - x.

        作者在論文中假設(shè):相較于直接優(yōu)化H(x),優(yōu)化殘差映射F(x)能有效緩解反向傳播過程中的梯度消失問題,解決了深度網(wǎng)絡(luò)不可訓(xùn)練的困難:[Resnet-50網(wǎng)絡(luò)結(jié)構(gòu)詳解]https://www.cnblogs.com/qianchaomoon/p/12315906.html

        3.2 PyTorch 復(fù)現(xiàn) ResNet-50

        3.2.1 ResNet-50網(wǎng)絡(luò)整體架構(gòu)

        3.2.2 Bottleneck結(jié)構(gòu)

        論文中將Resnet-50分成了4個大的卷積組,每一個大的卷積組叫做一個Bottleneck(瓶頸)模塊(輸入和輸出的特征圖通道較多,中間的卷積層特征深度較淺,類似瓶頸的中間小兩頭大的結(jié)構(gòu))。卷積組與卷積組之間會通過一個shortcut相連。

        左:非瓶頸結(jié)構(gòu),右:瓶頸結(jié)構(gòu)

        值得注意的是,ResNet使用Bottleneck結(jié)構(gòu)主要是是為了減小網(wǎng)絡(luò)的參數(shù)量(特征降維),在實際中作者注意到,瓶頸結(jié)構(gòu)的使用同樣出現(xiàn)了普通網(wǎng)絡(luò)的退化問題:

        3.2.3 ResNet-50圖解及各層參數(shù)細(xì)節(jié)

        對于F(x)+x,ResNet采取的是逐通道相加的形式,因此在相加時需要考慮兩者的通道數(shù)是否相同,相同的情況直接相加即可(圖實線處),若兩者通道不同,需要用1x1卷積對特征進行升維,將通道數(shù)變?yōu)橄嗤?圖虛線處):

        3.2.4 實現(xiàn)一個Bottleneck模塊:

        #?將Conv+BN封裝成一個基礎(chǔ)卷積類:
        class?BasicConv2d(nn.Module):
        ????def?__init__(self,?in_channel,?out_channel,?kernel_size,?stride=1,?padding=0):
        ????????super(BasicConv2d,?self).__init__()
        ????????self.conv?=?nn.Sequential(
        ????????????nn.Conv2d(in_channel,?out_channel,?kernel_size,
        ??????????????????????stride=stride,?padding=padding,?bias=False),
        ????????????nn.BatchNorm2d(out_channel)
        ????????)

        ????def?forward(self,?x):
        ????????x?=?self.conv(x)
        ????????return?x

        #?一個Bottleneck模塊:
        class?Bottleneck(nn.Module):
        ????def?__init__(self,?in_channel,?mid_channel,?out_channel,?stride=1):
        ????????super(Bottleneck,?self).__init__()

        ????????self.judge?=?in_channel?==?out_channel

        ????????self.bottleneck?=?nn.Sequential(
        ????????????BasicConv2d(in_channel,?mid_channel,?1),
        ????????????nn.ReLU(True),
        ????????????BasicConv2d(mid_channel,?mid_channel,?3,?padding=1,?stride=stride),
        ????????????nn.ReLU(True),
        ????????????BasicConv2d(mid_channel,?out_channel,?1),
        ????????)
        ????????self.relu?=?nn.ReLU(True)
        ????????#?下采樣部分由一個包含BN層的1x1卷積構(gòu)成:
        ????????if?in_channel?!=?out_channel:
        ????????????self.downsample?=?BasicConv2d(
        ????????????????in_channel,?out_channel,?1,?stride=stride)

        ????def?forward(self,?x):
        ????????out?=?self.bottleneck(x)
        ????????#?若通道不一致需使用1x1卷積下采樣
        ????????if?not?self.judge:
        ????????????self.identity?=?self.downsample(x)
        ????????????#?殘差+恒等映射=輸出
        ????????????out?+=?self.identity
        ????????#?否則直接相加
        ????????else:
        ????????????out?+=?x

        ????????out?=?self.relu(out)

        ????????return?out

        3.2.5 實現(xiàn)resnet-50

        #?Resnet50:
        class?ResNet_50(nn.Module):
        ????def?__init__(self,?class_num):
        ????????super(ResNet_50,?self).__init__()
        ????????self.conv?=?BasicConv2d(3,?64,?7,?stride=2,?padding=3)
        ????????self.maxpool?=?nn.MaxPool2d(3,?stride=2,?padding=1)
        ????????#?卷積組1
        ????????self.block1?=?nn.Sequential(
        ????????????Bottleneck(64,?64,?256),
        ????????????Bottleneck(256,?64,?256),
        ????????????Bottleneck(256,?64,?256),
        ????????)
        ????????#?卷積組2
        ????????self.block2?=?nn.Sequential(
        ????????????Bottleneck(256,?128,?512,?stride=2),
        ????????????Bottleneck(512,?128,?512),
        ????????????Bottleneck(512,?128,?512),
        ????????????Bottleneck(512,?128,?512),
        ????????)
        ????????#?卷積組3
        ????????self.block3?=?nn.Sequential(
        ????????????Bottleneck(512,?256,?1024,?stride=2),
        ????????????Bottleneck(1024,?256,?1024),
        ????????????Bottleneck(1024,?256,?1024),
        ????????????Bottleneck(1024,?256,?1024),
        ????????????Bottleneck(1024,?256,?1024),
        ????????????Bottleneck(1024,?256,?1024),
        ????????)
        ????????#?卷積組4
        ????????self.block4?=?nn.Sequential(
        ????????????Bottleneck(1024,?512,?2048,?stride=2),
        ????????????Bottleneck(2048,?512,?2048),
        ????????????Bottleneck(2048,?512,?2048),
        ????????)
        ????????self.avgpool?=?nn.AvgPool2d(4)
        ????????self.classifier?=?nn.Linear(2048,?class_num)

        ????def?forward(self,?x):
        ????????x?=?self.conv(x)
        ????????x?=?self.maxpool(x)
        ????????x?=?self.block1(x)
        ????????x?=?self.block2(x)
        ????????x?=?self.block3(x)
        ????????x?=?self.block4(x)
        ????????x?=?self.avgpool(x)
        ????????x?=?x.view(x.size(0),?-1)
        ????????out?=?self.classifier(x)

        ????????return?out

        4.FPN(特征金字塔)

        4.1 特征的語義信息

        對于CNN網(wǎng)絡(luò),圖像通過網(wǎng)絡(luò)淺層的卷積層,輸出的特征圖往往只能表示一些簡單的語義信息(比如一些簡單的線條),越深層的網(wǎng)絡(luò),提取特征表示的語義信息也就越復(fù)雜(從一些紋理,到一些類別具有的相似輪廓):(圖中的特征有經(jīng)過反卷積上采樣)

        因此,傳統(tǒng)的檢測網(wǎng)絡(luò)通常只在最后一個卷積輸出上的高層語義特征圖進行后續(xù)的步驟,但這也不可避免的存在一些問題。

        4.2 改進

        我們知道,越是深層的網(wǎng)絡(luò),特征的下采樣率也就越高,即深層的特征圖一個像素就對應(yīng)淺層特征的一片區(qū)域,這對于大目標(biāo)的檢測不會造成太大的影響。但對于圖像上的小目標(biāo),在深層特征上的有效信息較少,導(dǎo)致網(wǎng)絡(luò)對于小物體的檢測性能急劇下降,這種現(xiàn)象也被稱作多尺度問題。

        基于多尺度問題,一個直接的解決辦法便是利用圖像金字塔,將原始的輸入變換為多張不同尺寸的多尺度圖像,將這些圖像分別進行特征提取,生成多尺度的特征后再進行后續(xù)的處理,這樣一來,在小尺度的特征上檢測到小目標(biāo)的幾率就大大增加。這種方法簡單有效,曾大量在COCO目標(biāo)檢測競賽上使用。但這種方法的缺點就在于計算量大,需要消耗大量的時間。

        對此,FPN網(wǎng)絡(luò)(Feature Pyramid Networks)針對這一問題改進了提取多尺度特征的方法?;?.1的介紹我們知道,卷積網(wǎng)絡(luò)不同層提取的特征尺寸各不相同,本身就類似于一個金字塔的結(jié)構(gòu),同時,每一層的語義信息也各不相同,越淺的特征語義信息越簡單,顯示的細(xì)節(jié)也就越多,越深層的特征顯示的細(xì)節(jié)越少,語義信息越高級?;诖?,FPN網(wǎng)絡(luò)在特征提取的過程中融合了不同卷積層的特征,較好的改善了多尺度檢測問題。

        4.3 PyTorch 復(fù)現(xiàn) FPN

        4.3.1 FPN網(wǎng)絡(luò)架構(gòu)

        FPN網(wǎng)絡(luò)主要包含四個部分,自下而上網(wǎng)絡(luò),自上而下網(wǎng)絡(luò),橫向連接與卷積融合。

        1. 自下而上網(wǎng)絡(luò)(提供不同尺度的特征):

          最左側(cè)為普通的特征提取卷積網(wǎng)絡(luò)(ResNet),C2-C4代表resnet中的四個大的卷積組,包含了多個Bottleneck結(jié)構(gòu),原始圖像的輸入就從該結(jié)構(gòu)開始。

        2. 自上而下網(wǎng)絡(luò)(提供高層語義特征): 在這一結(jié)構(gòu)中,首先對C5進行1x1卷積降低通道數(shù)得到M5,接著依次上采樣得到M4,M3,M2.目的是得到與C4,C3,C2相同尺寸但不同語義的特征。方便特征的融合(融合的方式為逐元素相加)。

          值得注意的是,在網(wǎng)絡(luò)的上采樣過程中采用的不是反卷積或者非線性插值方法,而是普通的2倍最鄰近上采樣(可以最大程度保留特征圖的語義信息,得到既有良好的空間信息又有較強烈的語義信息的特征圖。):【論文筆記】FPN —— 特征金字塔:https://zhuanlan.zhihu.com/p/92005927

        1. 橫向連接:

          將高層的語義特征與淺層的細(xì)節(jié)特征相融合(中途使用1x1卷積使得兩者的通道數(shù)相同)

        2. 卷積融合:

          得到相加的特征后,再利用3x3卷積對M2-M4進一步融合(論文表示這么做可以消除上采樣帶來的重疊效應(yīng))

        4.3.2 復(fù)現(xiàn)FPN網(wǎng)絡(luò)

        #?導(dǎo)入resnet50
        resnet?=?models.resnet50(pretrained=True)
        #?分塊,?以便提取不同深度網(wǎng)絡(luò)的特征
        layer1?=?nn.Sequential(
        ????resnet.conv1,
        ????resnet.bn1,
        ????resnet.relu,
        ????resnet.maxpool,
        )
        layer2?=?resnet.layer1
        layer3?=?resnet.layer2
        layer4?=?resnet.layer3
        layer5?=?resnet.layer4


        class?FPN(nn.Module):
        ????def?__init__(self):
        ????????super(FPN,?self).__init__()
        ????????#?3x3?卷積融合特征
        ????????self.MtoP?=?nn.Conv2d(256,?256,?3,?1,?1)
        ????????#?橫向連接,?使用1x1卷積降維
        ????????self.C2toM2?=?nn.Conv2d(256,?256,?1,?1,?0)
        ????????self.C3toM3?=?nn.Conv2d(512,?256,?1,?1,?0)
        ????????self.C4toM4?=?nn.Conv2d(1024,?256,?1,?1,?0)
        ????????self.C5toM5?=?nn.Conv2d(2048,?256,?1,?1,?0)
        ????#?特征融合方法
        ????def?_upsample_add(self,?in_C,?in_M):
        ????????H?=?in_M.shape[2]
        ????????W?=?in_M.shape[3]
        ????????#?最鄰近上采樣方法
        ????????return?F.upsample_bilinear(in_C,?size=(H,?W))?+?in_M

        ????def?forward(self,?x):
        ????????#?自下而上
        ????????C1?=?layer1(x)
        ????????C2?=?layer2(C1)
        ????????C3?=?layer3(C2)
        ????????C4?=?layer4(C3)
        ????????C5?=?layer5(C4)
        ????????#?自上而下+橫向連接
        ????????M5?=?self.C5toM5(C5)
        ????????M4?=?self._upsample_add(M5,?self.C4toM4(C4))
        ????????M3?=?self._upsample_add(M4,?self.C3toM3(C3))
        ????????M2?=?self._upsample_add(M3,?self.C2toM2(C2))
        ????????#?卷積融合
        ????????P5?=?self.MtoP(M5)
        ????????P4?=?self.MtoP(M4)
        ????????P3?=?self.MtoP(M3)
        ????????P2?=?self.MtoP(M2)
        ????????#?返回的是多尺度特征
        ????????return?P2,?P3,?P4,?P5

        如發(fā)現(xiàn)本文中存在任何錯誤或是有不解的地方,歡迎在評論區(qū)留言~

        往期精彩回顧






        瀏覽 56
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            天堂网一级片 | 青娱乐在线视频精品 | 啊啊啊成人 | 小黄片免费在线观看 | 97在线影院 | 黃色一级A片一級片 | 色悠久久综合 | 欧美色涩在线第一页 | (h)触手欲潮h动漫 | 永久免费人成在线看不良视频 |