<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>

          代碼實(shí)踐|通過(guò)簡(jiǎn)單代碼來(lái)回顧卷積塊的歷史

          共 7475字,需瀏覽 15分鐘

           ·

          2021-06-13 14:14

          點(diǎn)擊上方小白學(xué)視覺(jué)”,選擇加"星標(biāo)"或“置頂

          重磅干貨,第一時(shí)間送達(dá)

          我試著定期閱讀ML和AI的論文,這是保持不掉隊(duì)的唯一的方法。作為一個(gè)計(jì)算機(jī)科學(xué)家,我常常會(huì)在看科學(xué)性的文字描述或者是數(shù)據(jù)公式的時(shí)候遇到麻煩。我發(fā)現(xiàn)通過(guò)代碼來(lái)理解會(huì)好很多。所以,在這篇文章中,我會(huì)通過(guò)Keras實(shí)現(xiàn)的方式,帶領(lǐng)大家回顧一下最近的一些文章中的重要的卷積塊。

          當(dāng)你在GitHub上尋找熱門的結(jié)構(gòu)的實(shí)現(xiàn)的時(shí)候,你可能會(huì)驚訝需要多少代碼。在代碼中包含足夠的注釋以及使用額外的參數(shù)是一個(gè)很好的實(shí)踐,但是同時(shí),也會(huì)使代碼不能聚焦于核心的結(jié)構(gòu)的實(shí)現(xiàn)。為了簡(jiǎn)化代碼,我使用了一些函數(shù)的別名:

            def conv(x, f, k=3, s=1, p='same', d=1, a='relu'):
           return Conv2D(filters=f, kernel_size=k, strides=s,
                         padding=p, dilation_rate=d, activation=a)(x)
          def dense(x, f, a='relu'):
           return Dense(f, activation=a)(x)
          def maxpool(x, k=2, s=2, p='same'):
           return MaxPooling2D(pool_size=k, strides=s, padding=p)(x)
          def avgpool(x, k=2, s=2, p='same'):
           return AveragePooling2D(pool_size=k, strides=s, padding=p)(x)
          def gavgpool(x):
           return GlobalAveragePooling2D()(x)
          def sepconv(x, f, k=3, s=1, p='same', d=1, a='relu'):
           return SeparableConv2D(filters=f, kernel_size=k, strides=s,
                         padding=p, dilation_rate=d, activation=a)(x)

          我發(fā)現(xiàn)不使用模板代碼,代碼的可讀性增加了不少。當(dāng)然,需要你理解我的單個(gè)單詞的表述才可以。我們開(kāi)始。

          Bottleneck 塊


          卷積層的參數(shù)的數(shù)量取決于kernel的尺寸,輸入的filter的數(shù)量和輸出filter的數(shù)量。你的網(wǎng)絡(luò)越寬,3x3卷積的代價(jià)越大。

            def bottleneck(x, f=32, r=4):
           x = conv(x, f//r, k=1)
           x = conv(x, f//r, k=3)
           return conv(x, f, k=1)

          bottleneck塊背后的思想是使用計(jì)算量很小的1x1的卷積將通道的數(shù)量減少r倍,接下來(lái)的3x3的卷積的參數(shù)會(huì)大大減小,最后,我們?cè)偈褂昧硪粋€(gè)1x1的卷積將通道數(shù)變回原來(lái)的樣子。

          Inception 模塊


          Inception模塊的思想是并行使用不同類型的操作,然后將結(jié)果合并。這樣,網(wǎng)絡(luò)可以學(xué)習(xí)到不同類型的filter。

            def naive_inception_module(x, f=32):
           a = conv(x, f, k=1)
           b = conv(x, f, k=3)
           c = conv(x, f, k=5)
           d = maxpool(x, k=3, s=1)
           return concatenate([a, b, c, d])

          這里我們將卷積核尺寸為1,3,5的結(jié)果進(jìn)行了合并,后面接一個(gè)MaxPooling層。上面這一小段顯示了一個(gè)inception的樸素的實(shí)現(xiàn)。實(shí)際的實(shí)現(xiàn)和bottlenecks 的思想結(jié)合起來(lái),會(huì)稍微更復(fù)雜一點(diǎn)。

          Inception 模塊

            def inception_module(x, f=32, r=4):
           a = conv(x, f, k=1)
           b = conv(x, f//3, k=1)
           b = conv(b, f, k=3)
           c = conv(x, f//r, k=1)
           c = conv(c, f, k=5)
           d = maxpool(x, k=3, s=1)
           d = conv(d, f, k=1)
           return concatenate([a, b, c, d])


          Residual 塊


          ResNet是微軟的研究人員發(fā)明的一種結(jié)構(gòu),可以讓網(wǎng)絡(luò)變得很深,要多深都可以,同時(shí)仍然可以提高模型的準(zhǔn)確率?,F(xiàn)在你也許已經(jīng)對(duì)很深的網(wǎng)絡(luò)司空見(jiàn)慣了,但是在ResNet之前卻不行。

            def residual_block(x, f=32, r=4):
           m = conv(x, f//r, k=1)
           m = conv(m, f//r, k=3)
           m = conv(m, f, k=1)
           return add([x, m])

          它的思想是在輸出的卷積塊上加上一個(gè)初始的激活。那樣的話,網(wǎng)絡(luò)可以決定在學(xué)習(xí)的過(guò)程中,輸出使用多少新的卷積。注意,inception模塊在拼接輸出的時(shí)候也拼接了加到上面的殘差塊。

          ResNeXt 塊


          看名字就知道,ResNeXt 和ResNet和接近。作者給卷積塊引入了一個(gè)新的名詞基數(shù),就像是另外的一個(gè)維度,就像寬度(通道數(shù))和深度(層數(shù))一樣。

          基數(shù)指的是卷積塊中并行出現(xiàn)的路徑的數(shù)量。聽(tīng)起來(lái)很像inception塊中4個(gè)不同的并行的操作。但是,這里使用的是完全相同的操作,4個(gè)基數(shù)指的是使用4次相同的操作。

          但是既然做的是同樣的事情,為什么要并行起來(lái)做呢?問(wèn)得好,這個(gè)概念要追溯到最早的AlexNet中的分組卷積,原先AlexNet是為了將運(yùn)算分開(kāi)利用不同的GPU,而ResNeXt主要是為了提高參數(shù)的使用效率。

            def resnext_block(x, f=32, r=2, c=4):
           l = []
           for i in range(c):
             m = conv(x, f//(c*r), k=1)
             m = conv(m, f//(c*r), k=3)
             m = conv(m, f, k=1)
             l.append(m)
           m = add(l)
           return add([x, m])

          思想就是對(duì)于所有的輸入通道,將它們分成組。卷積只在組中進(jìn)行,不會(huì)跨組。可以發(fā)現(xiàn),每個(gè)組會(huì)學(xué)到不同的特征,提高了權(quán)值的效率。

          想象一下,一個(gè)bottleneck塊首先使用壓縮率為4,將256通道降維到64通道,最后輸出的時(shí)候,再?gòu)?4通道回到256通道。如果我們引入了基數(shù)為32,壓縮率為2,我們并行使用32個(gè)1x1卷積層,每個(gè)組得到4 (256 / (32*2))個(gè)輸出通道。最后一步將32個(gè)并行路徑的結(jié)果加起來(lái),得到一個(gè)輸出,然后再加上初始的輸入,得到殘差連接。


          Left: ResNet Block?—?Right: RexNeXt Block of roughly the same parameter complexity

          這需要好好消化一下。使用上面的圖看看能不能得到一個(gè)可視化的表示,了解一下發(fā)生了什么,或者拷貝上面的幾行代碼,自己用Keras建一個(gè)小網(wǎng)絡(luò)試試。這么復(fù)雜的描述,只用了9行簡(jiǎn)單的代碼就實(shí)現(xiàn)了,是不是很酷?

          順便說(shuō)一下,如果基數(shù)的數(shù)量和通道的數(shù)量相同的話,我們會(huì)得到一個(gè)叫做深度可分離卷積的東西。這個(gè)東西自從Xception 結(jié)構(gòu)之后,就開(kāi)始火了起來(lái)。

          Dense 塊


          dense塊是殘差塊的一種極端的版本,每一個(gè)卷積層都會(huì)得到該模塊中之前的所有卷積層的輸出。第一,我們將輸入的激活加到一個(gè)列表中,然后進(jìn)入一個(gè)循環(huán),遍歷這模塊的深度。每個(gè)卷積的輸出都會(huì)加到這個(gè)列表中,所以下面的循環(huán)會(huì)得到越來(lái)越多的輸入特征圖,直到到達(dá)預(yù)定的深度。

            def dense_block(x, f=32, d=5):
             l = x
             for i in range(d):
                 x = conv(l, f)
                 l = concatenate([l, x])
             return l

          研究了幾個(gè)月得到了一個(gè)和DensNet一樣好的結(jié)構(gòu),實(shí)際的構(gòu)建模塊就是這么簡(jiǎn)單,太帥了。

          Squeeze-and-Excitation 塊


          SENet短期內(nèi)曾是ImageNet中最先進(jìn)的。它基于ResNext構(gòu)建,聚焦于對(duì)通道之間的信息進(jìn)行建模。在常規(guī)的卷積中,每個(gè)通道在內(nèi)積操作中對(duì)于加法操作具有相同的權(quán)重。

          SENet引入了一個(gè)非常簡(jiǎn)單的模塊,可以在任意的網(wǎng)絡(luò)結(jié)構(gòu)中加入。它構(gòu)建了一個(gè)小的神經(jīng)網(wǎng)絡(luò),可以學(xué)習(xí)到對(duì)于輸入來(lái)說(shuō),每個(gè)filter的權(quán)重是多少。可以看到,這不是一個(gè)卷積模塊,但是可以加入到任意的卷積塊中,而且有可能提高性能。

            def se_block(x, f, rate=16):
             m = gavgpool(x)
             m = dense(m, f // rate)
             m = dense(m, f, a='sigmoid')
             return multiply([x, m])

          每個(gè)通道被壓縮成一個(gè)數(shù)值,然后輸入到一個(gè)兩層的的神經(jīng)網(wǎng)絡(luò)中。依賴于通道的分布,這個(gè)網(wǎng)絡(luò)可以學(xué)到基于他們的重要性的權(quán)重。最后,這些權(quán)重和卷積的激活相乘。

          SENets引入了一個(gè)很小的計(jì)算量,同時(shí)提升了卷積模型的性能。在我看來(lái),這個(gè)模塊并沒(méi)有得到它應(yīng)有的關(guān)注。

          NASNet Normal Cell


          到了這里,開(kāi)始有點(diǎn)難看了。我們要離開(kāi)那個(gè)簡(jiǎn)單有效的設(shè)計(jì)空間了,進(jìn)入一個(gè)設(shè)計(jì)神經(jīng)網(wǎng)絡(luò)的算法的世界。NASNet從如何設(shè)計(jì)的看上去不可思議,但是實(shí)際結(jié)構(gòu)相當(dāng)?shù)膹?fù)雜。反正我就是知道在ImageNet上,表現(xiàn)非常好。

          作者手動(dòng)定義了一個(gè)搜索空間,使用不同可能的設(shè)置搜索不同類型的卷積核池化層,還定義了這些層是如何設(shè)計(jì)成并行的,如何相加的,如何拼接的。一旦定義好了,就開(kāi)始進(jìn)行強(qiáng)化學(xué)習(xí),基于循環(huán)神經(jīng)網(wǎng)絡(luò),如果設(shè)計(jì)出的網(wǎng)絡(luò)在CIFAR-10上表現(xiàn)的很好的話,就得到獎(jiǎng)勵(lì)。

          最后得到的結(jié)構(gòu)不僅僅是在CIFAR-10上表現(xiàn)的好,在ImageNet上也取得了業(yè)界領(lǐng)先。NASNet由基礎(chǔ)的Normal Cell和Reduction Cell相互重復(fù)而成。

            def normal_cell(x1, x2, f=32):
             a1 = sepconv(x1, f, k=3)
             a2 = sepconv(x1, f, k=5)
             a = add([a1, a2])
             b1 = avgpool(x1, k=3, s=1)
             b2 = avgpool(x1, k=3, s=1)
             b = add([b1, b2])
             c2 = avgpool(x2, k=3, s=1)
             c = add([x1, c2])
             d1 = sepconv(x2, f, k=5)
             d2 = sepconv(x1, f, k=3)
             d = add([d1, d2])
             e2 = sepconv(x2, f, k=3)
             e = add([x2, e2])
             return concatenate([a, b, c, d, e])

          上面是如何使用Keras來(lái)實(shí)現(xiàn)Normal Cell。除了這些層的組合之外,并沒(méi)有什么新的東西,效果非常好。

          Inverted Residual 塊

          到目前為止,你聽(tīng)說(shuō)過(guò)了 bottleneck block 和 可分離卷積,現(xiàn)在讓我們把這兩個(gè)東西放到一起,如果你跑一些測(cè)試,你會(huì)注意到可分離卷積已經(jīng)減少了參數(shù)的數(shù)量,再用 bottleneck block壓縮的話,可能會(huì)傷害到性能。

          作者實(shí)際上做了件和bottleneck residual block相反的事情,使用1x1的卷積核來(lái)增加通道的數(shù)量,因?yàn)榻酉聛?lái)的可分離卷積已經(jīng)很大程度上減小了參數(shù)的數(shù)量,然后在和初始激活相加之前把通道數(shù)降下來(lái)。

            def inv_residual_block(x, f=32, r=4):
           m = conv(x, f*r, k=1)
           m = sepconv(m, f, a='linear')
           return add([m, x]

          最后一個(gè)困惑是,可分離卷積后面并沒(méi)有接一個(gè)激活函數(shù),而是直接和輸入相加。這個(gè)block加到結(jié)構(gòu)里之后,非常的有效。

          AmoebaNet Normal Cell


          使用AmoebaNet ,我們達(dá)到了當(dāng)前在ImageNet上的業(yè)界最佳,也可能是圖像識(shí)別領(lǐng)域的業(yè)界最佳。和NASNet相似,這是由一個(gè)算法設(shè)計(jì)的,使用了相同的搜索空間。只是將強(qiáng)化學(xué)習(xí)算法換成了常常用來(lái)進(jìn)化的遺傳算法。這篇文章中,我們不進(jìn)行詳細(xì)的介紹。結(jié)果就是,通過(guò)進(jìn)化,作者可以找到一個(gè)比NASNet更好的方法,同時(shí)計(jì)算量也更小。在ImageNet上Top-5的準(zhǔn)確率達(dá)到了 97.87%,這是單個(gè)模型第一次有這樣的結(jié)果。

          看看代碼,這個(gè)block中并沒(méi)有加入什么你沒(méi)見(jiàn)過(guò)的新東西,為什么不基于上面的圖,自己試試實(shí)現(xiàn)一下新的Normal Cell,看看自己是不是能跟得上?

          總結(jié)


          我希望這個(gè)文章可以給你一個(gè)關(guān)于重要的卷積block的扎實(shí)的理解,實(shí)現(xiàn)這些block也許你想的要容易的多。去看看對(duì)應(yīng)的論文,可以得到一個(gè)更加詳細(xì)的理解。你會(huì)注意到,一旦你抓住了論文的核心思想,其余的理解起來(lái)就容易了。另外還要注意的是,在實(shí)際的實(shí)現(xiàn)中,常常會(huì)加入Batch Normalization,使用的激活函數(shù)也會(huì)有差別。


          下載1:OpenCV-Contrib擴(kuò)展模塊中文版教程
          在「小白學(xué)視覺(jué)」公眾號(hào)后臺(tái)回復(fù):擴(kuò)展模塊中文教程,即可下載全網(wǎng)第一份OpenCV擴(kuò)展模塊教程中文版,涵蓋擴(kuò)展模塊安裝、SFM算法、立體視覺(jué)、目標(biāo)跟蹤、生物視覺(jué)、超分辨率處理等二十多章內(nèi)容。

          下載2:Python視覺(jué)實(shí)戰(zhàn)項(xiàng)目52講
          小白學(xué)視覺(jué)公眾號(hào)后臺(tái)回復(fù):Python視覺(jué)實(shí)戰(zhàn)項(xiàng)目,即可下載包括圖像分割、口罩檢測(cè)、車道線檢測(cè)、車輛計(jì)數(shù)、添加眼線、車牌識(shí)別、字符識(shí)別、情緒檢測(cè)、文本內(nèi)容提取、面部識(shí)別等31個(gè)視覺(jué)實(shí)戰(zhàn)項(xiàng)目,助力快速學(xué)校計(jì)算機(jī)視覺(jué)。

          下載3:OpenCV實(shí)戰(zhàn)項(xiàng)目20講
          小白學(xué)視覺(jué)公眾號(hào)后臺(tái)回復(fù):OpenCV實(shí)戰(zhàn)項(xiàng)目20講即可下載含有20個(gè)基于OpenCV實(shí)現(xiàn)20個(gè)實(shí)戰(zhàn)項(xiàng)目,實(shí)現(xiàn)OpenCV學(xué)習(xí)進(jìn)階。

          交流群


          歡迎加入公眾號(hào)讀者群一起和同行交流,目前有SLAM、三維視覺(jué)、傳感器自動(dòng)駕駛、計(jì)算攝影、檢測(cè)、分割、識(shí)別、醫(yī)學(xué)影像、GAN、算法競(jìng)賽等微信群(以后會(huì)逐漸細(xì)分),請(qǐng)掃描下面微信號(hào)加群,備注:”昵稱+學(xué)校/公司+研究方向“,例如:”張三 + 上海交大 + 視覺(jué)SLAM“。請(qǐng)按照格式備注,否則不予通過(guò)。添加成功后會(huì)根據(jù)研究方向邀請(qǐng)進(jìn)入相關(guān)微信群。請(qǐng)勿在群內(nèi)發(fā)送廣告,否則會(huì)請(qǐng)出群,謝謝理解~


          瀏覽 41
          點(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>
                  91AV久久久 | 欧美性猛交XXXXⅩXX | 国产成人精品亚洲777人妖 | 美女被男生桶 | 无码污污网站 |