綜述 | 輕量級(jí)CNN架構(gòu)設(shè)計(jì)
點(diǎn)擊左上方藍(lán)字關(guān)注我們

引言
卷積神經(jīng)網(wǎng)絡(luò)架構(gòu)設(shè)計(jì),又指backbone設(shè)計(jì),主要是根據(jù)具體任務(wù)的數(shù)據(jù)集特點(diǎn)以及相關(guān)的評(píng)價(jià)指標(biāo)來確定一個(gè)網(wǎng)絡(luò)結(jié)構(gòu)的輸入圖像分辨率,深度,每一層寬度,拓?fù)浣Y(jié)構(gòu)等細(xì)節(jié)。公開發(fā)表的論文大多都是基于ImageNet這種大型的公開數(shù)據(jù)集來進(jìn)行的通用結(jié)構(gòu)設(shè)計(jì),早期只以其分類精度來證明設(shè)計(jì)的優(yōu)劣,后來也慢慢開始對(duì)比參數(shù)量(Params)和計(jì)算量(FLOPs),由于ImageNet的數(shù)據(jù)量十分巨大且豐富,所以通常在該數(shù)據(jù)集上獲得很好精度的網(wǎng)絡(luò)結(jié)構(gòu)泛化到其他任務(wù)性能也都不會(huì)差。但在很多特定任務(wù)中,這種通用的結(jié)構(gòu)雖然效果還可以,卻并不算最好,所以一般在實(shí)際應(yīng)用時(shí)通常是基于已公開發(fā)表的優(yōu)秀網(wǎng)絡(luò)結(jié)構(gòu)再根據(jù)任務(wù)特點(diǎn)進(jìn)行適當(dāng)修改得到自己需要的模型結(jié)構(gòu)。
目前人工智能技術(shù)應(yīng)用的一個(gè)趨勢(shì)是在端側(cè)平臺(tái)上部署高性能的神經(jīng)網(wǎng)絡(luò)模型并能在真實(shí)場(chǎng)景中實(shí)時(shí)(大于30幀)運(yùn)行,如移動(dòng)端/嵌入式端設(shè)備。這些平臺(tái)的特點(diǎn)是內(nèi)存資源少,處理器性能不高,功耗受限,這使得目前精度最高的模型由于對(duì)內(nèi)存和計(jì)算資源的超額要求使得根本無法在上面部署且達(dá)到實(shí)時(shí)性的要求,雖然可以通過知識(shí)蒸餾,通道剪枝,低比特量化等一系列手段來降低模型參數(shù)量和計(jì)算量,但仍然遠(yuǎn)遠(yuǎn)不夠,且在精度和幀率之間各種trade-off也非常繁瑣,所以直接設(shè)計(jì)輕量級(jí)的架構(gòu),然后結(jié)合剪枝量化是最有效的解決辦法,本文將結(jié)合自己看的論文和參加項(xiàng)目比賽的經(jīng)驗(yàn)講述輕量級(jí)CNN的發(fā)展以及一些設(shè)計(jì)總結(jié),如有不對(duì)之處請(qǐng)不吝賜教。
基本概念
感受野(Receptive Field)
感受野指的是卷積神經(jīng)網(wǎng)絡(luò)每一層輸出的特征圖(feature map)上每個(gè)像素點(diǎn)映射回輸入圖像上的區(qū)域大小,神經(jīng)元感受野的范圍越大表示其能接觸到的原始圖像范圍就越大,也意味著它能學(xué)習(xí)更為全局,語義層次更高的特征信息,相反,范圍越小則表示其所包含的特征越趨向局部和細(xì)節(jié)。因此感受野的范圍可以用來大致判斷每一層的抽象層次,并且我們可以很明顯地知道網(wǎng)絡(luò)越深,神經(jīng)元的感受野越大。

分辨率(Resolution)
分辨率指的是輸入模型的圖像尺寸,即長寬大小。通常情況會(huì)根據(jù)模型下采樣次數(shù)n和最后一次下采樣后feature map的分辨率k×k來決定輸入分辨率的大小,即:
從輸入r×r到最后一個(gè)卷積特征feature map的k×k,整個(gè)過程是一個(gè)信息逐漸抽象化的過程,即網(wǎng)絡(luò)學(xué)習(xí)到的信息逐漸由低級(jí)的幾何信息轉(zhuǎn)變?yōu)楦呒?jí)的語義信息,這個(gè)feature map的大小可以是3×3,5×5,7×7,9×9等等,k太大會(huì)增加后續(xù)的計(jì)算量且信息抽象層次不夠高,影響網(wǎng)絡(luò)性能,k太小會(huì)造成非常嚴(yán)重的信息丟失,如原始分辨率映射到最后一層的feature map有效區(qū)域可能不到一個(gè)像素點(diǎn),使得訓(xùn)練無法收斂。
在ImageNet分類任務(wù)中,通常設(shè)置的5次下采樣,并且考慮到其原始圖像大多數(shù)在300分辨率左右,所以把最后一個(gè)卷積特征大小設(shè)定為7×7,將輸入尺寸固定為224×224×3。在目標(biāo)檢測(cè)任務(wù)中,很多采用的是416×416×3的輸入尺寸,當(dāng)然由于很多目標(biāo)檢測(cè)模型是全卷積的結(jié)構(gòu),通常可以使用多尺寸訓(xùn)練的方式,即每次輸入只需要保證是32×的圖像尺寸大小就行,不固定具體數(shù)值。但這種多尺度訓(xùn)練的方式在圖像分類當(dāng)中是不通用的,因?yàn)榉诸惸P妥詈笠粚邮侨B接結(jié)構(gòu),即矩陣乘法,需要固定輸入數(shù)據(jù)的維度。
深度(Depth)
神經(jīng)網(wǎng)絡(luò)的深度決定了網(wǎng)絡(luò)的表達(dá)能力,它有兩種計(jì)算方法,早期的backbone設(shè)計(jì)都是直接使用卷積層堆疊的方式,它的深度即神經(jīng)網(wǎng)絡(luò)的層數(shù),后來的backbone設(shè)計(jì)采用了更高效的module(或block)堆疊的方式,每個(gè)module是由多個(gè)卷積層組成,它的深度也可以指module的個(gè)數(shù),這種說法在神經(jīng)架構(gòu)搜索(NAS)中出現(xiàn)的更為頻繁。通常而言網(wǎng)絡(luò)越深表達(dá)能力越強(qiáng),但深度大于某個(gè)值可能會(huì)帶來相反的效果,所以它的具體設(shè)定需要不斷調(diào)參得到。
寬度(Width)
寬度決定了網(wǎng)絡(luò)在某一層學(xué)到的信息量,但網(wǎng)絡(luò)的寬度時(shí)指的是卷積神經(jīng)網(wǎng)絡(luò)中最大的通道數(shù),由卷積核數(shù)量最多的層決定。通常的結(jié)構(gòu)設(shè)計(jì)中卷積核的數(shù)量隨著層數(shù)越來越多的,直到最后一層feature map達(dá)到最大,這是因?yàn)樵降缴顚樱琭eature map的分辨率越小,所包含的信息越高級(jí),所以需要更多的卷積核來進(jìn)行學(xué)習(xí)。通道越多效果越好,但帶來的計(jì)算量也會(huì)大大增加,所以具體設(shè)定也是一個(gè)調(diào)參的過程,并且各層通道數(shù)會(huì)按照8×的倍數(shù)來確定,這樣有利于GPU的并行計(jì)算。

下采樣(Down-Sample)
下采樣層有兩個(gè)作用,一是減少計(jì)算量,防止過擬合,二是增大感受野,使得后面的卷積核能夠?qū)W到更加全局的信息。下采樣的設(shè)計(jì)有兩種:
采用stride為2的池化層,如Max-pooling或Average-pooling,目前通常使用Max-pooling,因?yàn)樗?jì)算簡(jiǎn)單且最大響應(yīng)能更好保留紋理特征; 采用stride為2的卷積層,下采樣的過程是一個(gè)信息損失的過程,而池化層是不可學(xué)習(xí)的,用stride為2的可學(xué)習(xí)卷積層來代替pooling可以得到更好的效果,當(dāng)然同時(shí)也增加了一定的計(jì)算量。
(突然想到為啥不使用雙線性插值,向下插值來代替Pooling,這個(gè)雖然比MaxPooling計(jì)算量更大,但是保留的信息應(yīng)該更豐富才是)
上采樣(Up-Sampling)
在卷積神經(jīng)網(wǎng)絡(luò)中,由于輸入圖像通過卷積神經(jīng)網(wǎng)絡(luò)(CNN)提取特征后,輸出的尺寸往往會(huì)變小,而有時(shí)我們需要將圖像恢復(fù)到原來的尺寸以便進(jìn)行進(jìn)一步的計(jì)算(如圖像的語義分割),這個(gè)使圖像由小分辨率映射到大分辨率的操作,叫做上采樣,它的實(shí)現(xiàn)一般有三種方式:
插值,一般使用的是雙線性插值,因?yàn)樾Ч詈?,雖然計(jì)算上比其他插值方式復(fù)雜,但是相對(duì)于卷積計(jì)算可以說不值一提; 轉(zhuǎn)置卷積又或是說反卷積,通過對(duì)輸入feature map間隔填充0,再進(jìn)行標(biāo)準(zhǔn)的卷積計(jì)算,可以使得輸出feature map的尺寸比輸入更大; Max Unpooling,在對(duì)稱的max pooling位置記錄最大值的索引位置,然后在unpooling階段時(shí)將對(duì)應(yīng)的值放置到原先最大值位置,其余位置補(bǔ)0;

參數(shù)量(Params)
參數(shù)量指的網(wǎng)絡(luò)中可學(xué)習(xí)變量的數(shù)量,包括卷積核的權(quán)重weight,批歸一化(BN)的縮放系數(shù)γ,偏移系數(shù)β,有些沒有BN的層可能有偏置bias,這些都是可學(xué)習(xí)的參數(shù) ,即在模型訓(xùn)練開始前被賦予初值,在訓(xùn)練過程根據(jù)鏈?zhǔn)椒▌t中不斷迭代更新,整個(gè)模型的參數(shù)量主要由卷積核的權(quán)重weight的數(shù)量決定,參數(shù)量越大,則該結(jié)構(gòu)對(duì)運(yùn)行平臺(tái)的內(nèi)存要求越高,參數(shù)量的大小是輕量化網(wǎng)絡(luò)設(shè)計(jì)的一個(gè)重要評(píng)價(jià)指標(biāo)。
計(jì)算量(FLOPs)
神經(jīng)網(wǎng)絡(luò)的前向推理過程基本上都是乘累加計(jì)算,所以它的計(jì)算量也是指的前向推理過程中乘加運(yùn)算的次數(shù),通常用FLOPs來表示,即floating point operations(浮點(diǎn)運(yùn)算數(shù))。計(jì)算量越大,在同一平臺(tái)上模型運(yùn)行延時(shí)越長,尤其是在移動(dòng)端/嵌入式這種資源受限的平臺(tái)上想要達(dá)到實(shí)時(shí)性的要求就必須要求模型的計(jì)算量盡可能地低,但這個(gè)不是嚴(yán)格成正比關(guān)系,也跟具體算子的計(jì)算密集程度(即計(jì)算時(shí)間與IO時(shí)間占比)和該算子底層優(yōu)化的程度有關(guān)。
卷積計(jì)算類型
標(biāo)準(zhǔn)卷積 (Convolution)
在神經(jīng)網(wǎng)絡(luò)架構(gòu)設(shè)計(jì)中,標(biāo)準(zhǔn)卷積是最常見的結(jié)構(gòu),假設(shè)其輸入feature map的維度是(1, iC, iH, iW),每個(gè)卷積核的維度是(1, iC, k, k),一次卷積濾波得到一層feature map的維度為(1,1, oH, oW),一共有oC個(gè)卷積核,則輸出feature map的維度是(1, oC, oH, oW),計(jì)算量為iC×k×k×oC×oH×oW,計(jì)算過程如下圖所示,由于太過基礎(chǔ),故不贅述。

深度卷積 (Depthwise Convolution)
深度卷積與標(biāo)準(zhǔn)卷積相比,顧名思義是在深度上做了文章,而這里的深度跟網(wǎng)絡(luò)的深度無關(guān),它指的通道,標(biāo)準(zhǔn)卷積中每個(gè)卷積核都需要與feature map的所有層進(jìn)行計(jì)算,所以每個(gè)卷積核的通道數(shù)等于輸入feature map的通道數(shù),通過設(shè)定卷積核的數(shù)量可以控制輸出feature map的通道數(shù)。而深度卷積每個(gè)卷積核都是單通道的,維度為(1,1,k,k) ,卷積核的個(gè)數(shù)為iC,即第i個(gè)卷積核與feature map第i個(gè)通道進(jìn)行二維的卷積計(jì)算,最后輸出維度為(1,iC,oH,oW),它不能改變輸出feature map的通道數(shù),所以通常會(huì)在深度卷積后面接上一個(gè)(oC,iC,1,1)的標(biāo)準(zhǔn)卷積來代替3×3或更大尺寸的標(biāo)準(zhǔn)卷積,總的計(jì)算量為iC×k×k×oH×oW+iC×oH×oW×oC,是普通卷積的1/oC+1/(k×k),大大減少了計(jì)算量和參數(shù)量,又可以達(dá)到相同的效果,這種結(jié)構(gòu)被稱為深度可分離卷積(Depthwise Separable Convolution),在MobileNet V1被提出,后來漸漸成為輕量化結(jié)構(gòu)設(shè)計(jì)的標(biāo)配。

深卷積之前一直被吐槽在GPU上運(yùn)行速度還不如一般的標(biāo)準(zhǔn)卷積,因?yàn)閐epthwise 的卷積核復(fù)用率比普通卷積要小很多,計(jì)算和內(nèi)存訪問的比值比普通卷積更小,因此會(huì)花更多時(shí)間在內(nèi)存開銷上,而且per-channel的矩陣計(jì)算很小不容易并行導(dǎo)致的更慢,但理論上計(jì)算量和參數(shù)量都是大大減少的,只是底層優(yōu)化的問題。
分組卷積 (Group Convolution)
分組卷積最早在AlexNet中出現(xiàn),當(dāng)時(shí)作者在訓(xùn)練模型時(shí)為了減少顯存占用而將feature map分組然后給多個(gè)GPU進(jìn)行處理,最后把多個(gè)輸出進(jìn)行融合。具體計(jì)算過程是,分組卷積首先將輸入feature map分成g個(gè)組,每個(gè)組的大小為(1, iC/g, iH, iW),對(duì)應(yīng)每組中一個(gè)卷積核的大小是(1,iC/g,k,k),每組有oC/g個(gè)卷積核,所以每組輸出feature map的尺寸為(1,oC/g,oH,oW),最終g組輸出拼接得到一個(gè)(1,oC,oH,oW)的大feature map,總的計(jì)算量為iC/g×k×k×oC×oH×oW,是標(biāo)準(zhǔn)卷積的1/g,參數(shù)量也是標(biāo)準(zhǔn)卷積的1/g。

但由于feature map組與組之間相互獨(dú)立,存在信息的阻隔,所以ShuffleNet提出對(duì)輸出的feature map做一次channel shuffle的操作,即通道混洗,打亂原先的順序,使得各個(gè)組之間的信息能夠交互起來。
空洞卷積 (Dilated Convolution)
空洞卷積是針對(duì)圖像語義分割問題中下采樣會(huì)降低圖像分辨率、丟失信息而提出的一種卷積思路。通過間隔取值擴(kuò)大感受野,讓原本3x3的卷積核,在相同參數(shù)量和計(jì)算量下?lián)碛懈蟮母惺芤?。這里面有個(gè)擴(kuò)張率(dilation rate)的系數(shù),這個(gè)系數(shù)定義了這個(gè)間隔的大小,標(biāo)準(zhǔn)卷積相當(dāng)于dilation rate為1的空洞卷積,下圖展示的是dilation rate為2的空洞卷積計(jì)算過程,可以看出3×3的卷積核可以感知標(biāo)準(zhǔn)的5×5卷積核的范圍,還有一種理解思路就是先對(duì)3×3的卷積核間隔補(bǔ)0,使它變成5×5的卷積,然后再執(zhí)行標(biāo)準(zhǔn)卷積的操作。

轉(zhuǎn)置卷積 (Transposed Convolutions)
轉(zhuǎn)置卷積又稱反卷積(Deconvolution),它和空洞卷積的思路正好相反,是為上采樣而生,也應(yīng)用于語義分割當(dāng)中,而且他的計(jì)算也和空洞卷積正好相反,先對(duì)輸入的feature map間隔補(bǔ)0,卷積核不變,然后使用標(biāo)準(zhǔn)的卷積進(jìn)行計(jì)算,得到更大尺寸的feature map。

可變形卷積 (deformable convolution)
以上的卷積計(jì)算都是固定的,每次輸入不同的圖像數(shù)據(jù),卷積計(jì)算的位置都是完全固定不變,即使是空洞卷積/轉(zhuǎn)置卷積,0填充的位置也都是事先確定的。而可變性卷積是指卷積核上對(duì)每一個(gè)元素額外增加了一個(gè)h和w方向上偏移的參數(shù),然后根據(jù)這個(gè)偏移在feature map上動(dòng)態(tài)取點(diǎn)來進(jìn)行卷積計(jì)算,這樣卷積核就能在訓(xùn)練過程中擴(kuò)展到很大的范圍。而顯而易見的是可變性卷積雖然比其他卷積方式更加靈活,可以根據(jù)每張輸入圖片感知不同位置的信息,類似于注意力,從而達(dá)到更好的效果,但是它比可行變卷積在增加了很多計(jì)算量和實(shí)現(xiàn)難度,目前感覺只在GPU上優(yōu)化的很好,在其他平臺(tái)上還沒有見到部署。

其他算子
池化(pooling)
池化這個(gè)操作比較簡(jiǎn)單,一般在上采樣和下采樣的時(shí)候用到,沒有參數(shù),不可學(xué)習(xí),但操作極為簡(jiǎn)單,和depthwise卷積類似,只是把乘累加操作替換成取最大/取平均操作。
最大池化和平均池化

全局平均池化 全局平均池化的操作是對(duì)一個(gè)維度為(C,H,W)的feature map,在HW方向整個(gè)取平均,然后輸出一個(gè)長度為C的向量,這個(gè)操作一般在分類模型的最后一個(gè)feature map之后出現(xiàn),然后接一個(gè)全連接層就可以完成分類結(jié)果的輸出了。早期的分類模型都是把最后一個(gè)feature map直接拉平成C×H×W的向量,然后再接全連接層,但是顯然可以看出來這個(gè)計(jì)算量極大,甚至有的模型最后一個(gè)全連接層占了整個(gè)模型計(jì)算量的50%以上,之后由研究人員發(fā)現(xiàn)對(duì)這個(gè)feature map做一個(gè)全局平均池化,然后再加全連接層可以達(dá)到相似的效果,且計(jì)算量降低到了原來的1/HW。 最大向上池化 這個(gè)操作在前面基本概念一節(jié)上采樣段落中有描述,故不贅述。 全連接計(jì)算(Full Connected)
這個(gè)本質(zhì)其實(shí)就是矩陣乘法,輸入一個(gè)(B, iC)的數(shù)據(jù),權(quán)重為(iC, oC),那么輸出為(B, oC),在多層感知機(jī)和分類模型最后一層常常見到。

Addition / Concatenate分支
Addition和Concatenate分支操作統(tǒng)稱為shortcut,如下圖所示,操作極為簡(jiǎn)單。Addition是在ResNet中提出,兩個(gè)相同維度的feature map相同位置點(diǎn)的值直接相加,得到新的相同維度feature map,這個(gè)操作可以融合之前的特征,增加信息的表達(dá),Concatenate操作是在Inception中首次使用,被DenseNet發(fā)揚(yáng)光大,和addition不同的是,它只要求兩個(gè)feature map的HW相同,通道數(shù)可以不同,然后兩個(gè)feature map在通道上直接拼接,得到一個(gè)更大的feature map,它保留了一些原始的特征,增加了特征的數(shù)量,使得有效的信息流繼續(xù)向后傳遞。

Channel shuffle
channel shuffle是ShuffleNet中首次提出,主要是針對(duì)分組卷積中不同組之間信息不流通,對(duì)不同組的feature map進(jìn)行混洗的一個(gè)操作,如下圖所示,假設(shè)原始的feature map維度為(1,9,H,W),被分成了3個(gè)組,每個(gè)組有三個(gè)通道,那么首先將這個(gè)feature map進(jìn)行reshape操作,得到(1,3,3,H,W),然后對(duì)中間的兩個(gè)大小為3的維度進(jìn)行轉(zhuǎn)置,依然是(1,3,3,H,W),最后將通道拉平,變回(1,9,H,W),就完成了通道混洗,使得不同組的feature map間隔保存,增強(qiáng)了信息的交互。

常用激活函數(shù)
激活函數(shù)的非線性是神經(jīng)網(wǎng)絡(luò)發(fā)揮作用最重要的因素之一,而對(duì)于實(shí)際部署,激活函數(shù)的實(shí)現(xiàn)也是很重要的一個(gè)方面,實(shí)現(xiàn)的不好對(duì)加速效果影響很大,這里主要講幾個(gè)部署當(dāng)中常見的激活函數(shù)。
ReLU系列
這里主要指常用的ReLU,ReLU6和leaky ReLU。ReLU比較好部署,小于0的部分為0,大于0的部分為原始值,只需要判斷一下符號(hào)位就行;ReLU6與ReLU相比也只是在正向部分多了個(gè)閾值,大于6的值等于6,在實(shí)現(xiàn)時(shí)多了個(gè)比較也不算麻煩;而leaky ReLU和ReLU正向部分一樣,都是大于0等于原始值,但負(fù)向部分卻是等于原始值的1/10,浮點(diǎn)運(yùn)算的話乘個(gè)0.1就好了,如果因?yàn)榱炕獙?shí)現(xiàn)整數(shù)運(yùn)算,這塊可以做個(gè)近似,如0.1用13>>7來代替,具體實(shí)現(xiàn)方法多種多樣 ,還算簡(jiǎn)單。

Sigmoid系列
這里主要指sigmoid,還有和他相關(guān)的swish:
可以看出,如果按照公式來實(shí)現(xiàn)sigmoid對(duì)低性能的硬件來說非常不友好,因?yàn)樯婕暗酱罅康膃xp指數(shù)運(yùn)算和除法運(yùn)算,于是有研究人員針對(duì)此專門設(shè)計(jì)了近似的硬件友好的函數(shù)h-sigmoid和h-swish函數(shù),這里的h指的就是hardware的意思:
可視化的對(duì)比如下圖所示,可以看出在保證精度的同時(shí)又能大大方便硬件的實(shí)現(xiàn),當(dāng)然要直接實(shí)現(xiàn)sigmoid也是可以的,畢竟sigmoid是有限輸出,當(dāng)輸入小于-8或大于8的時(shí)候,輸出基本上接近于-1和1,可以根據(jù)這個(gè)特點(diǎn)設(shè)計(jì)一個(gè)查找表,速度也超快,且我們實(shí)測(cè)對(duì)精度沒啥影響。

經(jīng)典輕量化模型
早期比較經(jīng)典的卷積神經(jīng)網(wǎng)絡(luò),如AlexNet,VGG,GoogleNet(或Inception),ResNet,DenseNet都是以提升模型在ImageNet數(shù)據(jù)集上的分類精度為主了,很少考慮參數(shù)量和計(jì)算量的問題,他們的主要結(jié)構(gòu)解析起來也比較簡(jiǎn)單,基本都是由標(biāo)準(zhǔn)卷積(7×7,5×5,3×3和1×1),Pooling和shortcut操作(Addition / Concatenate)構(gòu)成,而且以3×3及其以上的卷積核為主,通道數(shù)也是動(dòng)輒上千,所以參數(shù)量和計(jì)算量巨大。后續(xù)研究人員慢慢發(fā)現(xiàn)兩個(gè)3×3卷積可以代替一個(gè)5×5卷積的效果,三個(gè)3×3卷積可以代替一個(gè)7×7卷積的效果,大量使用1×1卷積,使用3×3 depthwise conv + pointwise conv(1×1標(biāo)準(zhǔn)卷積)可以代替3×3普通卷積......一系列操作可以減少參數(shù)量和計(jì)算量,所以下面講述一下一些輕量級(jí)神經(jīng)網(wǎng)絡(luò)發(fā)展的歷史,因?yàn)檫@塊很多人都講過,所以我會(huì)簡(jiǎn)單一些,挑重點(diǎn)說說。
SqueezeNet
SqueezeNet是公認(rèn)的輕量級(jí)模型設(shè)計(jì)最早期的工作之一,作者提出了三種策略來實(shí)現(xiàn)在保持精度的情況下大大減少當(dāng)時(shí)主流模型(以AlexNet為例)的計(jì)算量和參數(shù)量:
將模型中一部分的3×3卷積用1×1來代替,1×1卷積是3×3參數(shù)量和計(jì)算量的1/9,所以可以大大減少參數(shù)量和計(jì)算量; 減少3×3卷積的輸入通道數(shù),這個(gè)可以通過在進(jìn)入3×3卷積之前加一個(gè)1×1卷積來實(shí)現(xiàn)通道數(shù)量的減少; 將下采樣層的位置往后推,使得模型可以在更大的feature map上進(jìn)行更多的學(xué)習(xí),這一步雖然會(huì)在增加計(jì)算量,但是和上面兩個(gè)策略結(jié)合可以在維持模型精度的情況下仍大大減少參數(shù)量和計(jì)算量;

根據(jù)上面的策略,作者提出了fire module的子結(jié)構(gòu),如下圖所示,然后整個(gè)模型由這樣的子結(jié)構(gòu)堆疊而成。這個(gè)fire module由squeeze部分和expand部分構(gòu)成,squeeze部分是1×1的卷積層,而expand部分是1×1的卷積和3×3的卷積拼接起來的,每次feature map輸入這個(gè)fire module會(huì)在squeeze層降低通道數(shù),然后在expand通道增加通道數(shù),從而在參數(shù)量更少的情況下仍然可以得到充分的學(xué)習(xí)。最后結(jié)合一些模型壓縮的方法可以使得SqueezeNet在達(dá)到AlexNet同等精度的情況下,參數(shù)量減少到后者的1/50,計(jì)算量減少到后者的1/510。
這篇論文使用大量1×1的卷積核代替3×3卷積,并且利用1×1卷積改變大尺度卷積層輸入feature map的通道數(shù)從而減少計(jì)算量的思想是非常有意義的,后續(xù)的很多輕量級(jí)網(wǎng)路的論文都沿用了這種套路。
MobileNet系列
MobileNet系列一共有V1,V2和V3三篇論文,簡(jiǎn)要的講:
MobileNet V1主要思想是提出了一種新的結(jié)構(gòu)—深度可分離卷積(Depthwise Separable Convolution)來代替標(biāo)準(zhǔn)3×3卷積,從而大大減少模型的參數(shù)量和計(jì)算量; MobileNet V2在V1的基礎(chǔ)上提出了一種倒置殘差的模塊,這個(gè)模塊有三個(gè)卷積,第一個(gè)部分是一個(gè)1×1標(biāo)準(zhǔn)卷積,用來升維,第二個(gè)部分是由3×3深度卷積+1×1標(biāo)準(zhǔn)卷積構(gòu)成的深度分離卷積,用來學(xué)習(xí)特征和降維,模塊的輸出和輸入再進(jìn)行一個(gè)Addition的操作,由于和ResNet中維度升降方式相反,所以稱為倒置殘差。中間升維的作用是讓深度可分離卷積得到更充分的學(xué)習(xí),計(jì)算量相對(duì)于標(biāo)準(zhǔn)卷積來說也不大,而且這種升降維的方式非常靈活,可以大大減少計(jì)算量。本文還從流形學(xué)的角度探究了輸入深度可分離卷積上一層的ReLU6對(duì)信息傳遞的影響,理論證明去掉上一個(gè)1×1標(biāo)準(zhǔn)卷積的ReLU激活函數(shù)能更有利于后面的深度可分離卷積對(duì)特征的學(xué)習(xí)。

MobileNet V3感覺相對(duì)于前兩篇沒有那么大的結(jié)構(gòu)創(chuàng)新了,主要思想是神經(jīng)架構(gòu)搜索(NAS)和硬件友好結(jié)構(gòu),總的來看V3的結(jié)構(gòu)是在V2的基礎(chǔ)上進(jìn)行了一些修改,如增加了SE block這種已被提出的注意力機(jī)制,激活函數(shù)換成了H-swish,last stage減少了幾層計(jì)算,針對(duì)語義分割提出了Lite R-ASPP的head(不在討論之列),整個(gè)論文看著像是堆tricks,重點(diǎn)不是很突出,有點(diǎn)年底沖業(yè)績(jī)的嫌疑。

根據(jù)我自己的比賽和項(xiàng)目經(jīng)驗(yàn)來看,還是MobileNet V1和V2的結(jié)構(gòu)比較實(shí)用,參數(shù)量和計(jì)算量小,可拓展性好,SE block這種模塊對(duì)延時(shí)影響還是不小,而且我們發(fā)現(xiàn)其他各種花里胡哨的激活函數(shù)跟ReLU/ReLU6相比都差不多,對(duì)精度沒有很大的影響,還不如直接部署ReLU/ReLU6來的方便。
ShuffleNet系列 曠視出品的ShuffleNet系列有兩篇論文,且后一篇在打前一篇的臉,很有意思。
ShuffleNet V1是在MobileNet V1后MobileNet V2前提出的,說實(shí)話結(jié)構(gòu)上和MobileNet V2還挺像,大家可以上下兩張圖片對(duì)比一下。兩者都想到了學(xué)習(xí)ResNet的殘差結(jié)構(gòu),區(qū)別在于ShuffleNet V1覺得block當(dāng)中的1×1標(biāo)準(zhǔn)卷積也非常耗時(shí),于是用1×1的分組卷積外加channel shuffle的操作給替換了,然后MobileNet V2會(huì)先升維讓深度可分離卷積得到充分的學(xué)習(xí)再降維回來,ShuffleNet V1中stride為2的模塊也有自己的特色,雖然看著MobileNet V2的結(jié)構(gòu)更簡(jiǎn)潔一些,但ShuffleNet V1創(chuàng)新也是不少,尤其那個(gè)用channel shuffle增強(qiáng)不同組之間信息交互的操作。

ShuffleNet ?V2論文是一篇誠意滿滿之作,作者通過分析ShuffleNet v1與MobileNet v2這兩個(gè)移動(dòng)端網(wǎng)絡(luò)在GPU/ARM兩種平臺(tái)下的時(shí)間消耗分布,看出Conv等計(jì)算密集型操作占了絕大多數(shù)時(shí)間,但其它像Elemwise和IO等內(nèi)存讀寫密集型操作也占了相當(dāng)比例的時(shí)間,因此像以往那樣僅以FLOPs來作為指導(dǎo)準(zhǔn)則來設(shè)計(jì)CNN網(wǎng)絡(luò)是不完備的,雖然它可以反映出占大比例時(shí)間的Conv操作,但不夠準(zhǔn)確。于是作者提出了高效網(wǎng)絡(luò)設(shè)計(jì)的四個(gè)指導(dǎo)原則:
當(dāng)輸入和輸出的通道數(shù)相同時(shí),conv計(jì)算所需的MAC(memory access cost)最小; 大量的分組卷積會(huì)增加MAC開銷; 網(wǎng)絡(luò)結(jié)構(gòu)的碎片化會(huì)減少其可并行優(yōu)化的程度,GoogleNet系列和NASNet中很多分支進(jìn)行不同的卷積/pool計(jì)算非常碎片,對(duì)硬件運(yùn)行很不友好; Element-wise操作不可忽視,對(duì)延時(shí)影響很大,包括ReLU,Addition,AddBias等,主要是因?yàn)檫@些操作計(jì)算與內(nèi)存訪問的占比太?。?/section>
基于此,作者提出了ShuffleNet V2的blocks,如下所示,與V1相比,去掉了分組卷積的操作,去掉了Add操作,換成了Concat,stride為2的block的旁路把平均池化換成了深度可分離卷積,為了繼續(xù)延續(xù)channel shuffle的操作,作者在block進(jìn)去的地方做了個(gè)split的操作,最后再concat+channel shuffle,這里是為了替換掉之前的Add,同時(shí)也可以減少計(jì)算量。

Shift: A Zero FLOP, Zero Parameter Alternative to Spatial Convolutions
這是一篇很有意思的論文,主要是提出了一種無參數(shù),無計(jì)算的移位算子來代替ResNet中計(jì)算量占比很高的3×3卷積,這種算子稱為shift kernel,如下圖所示,只需要根據(jù)kernel上的shift信息對(duì)feature map進(jìn)行位置上的上下左右偏移即可得到新的feature map,沒有計(jì)算,僅僅是訪存操作。詳細(xì)一點(diǎn)說就是如下面Shift框里面的第一個(gè)卷積核,它只在黃色的區(qū)域?yàn)?,其他白色的區(qū)域?yàn)?,在做卷積計(jì)算的時(shí)候其實(shí)就相當(dāng)于把輸入feature map中間偏左邊的那個(gè)點(diǎn)的值平移到輸出feature map中間的地方,正如作者標(biāo)注的向右的箭頭所示。而且這個(gè)操作都是per-channel的,所以每個(gè)卷積核只有k×k種可能性,當(dāng)通道數(shù)大于k×k時(shí),就需要將所有通道分成iC/(k×k)組,剩下的channel設(shè)置為center,即中間為1,其余為0,然后怎么去選取每個(gè)卷積核的類型呢,論文在兩個(gè)shift kernel中間夾了一個(gè)1×1的標(biāo)準(zhǔn)卷積,要保證第二次shift操作之后數(shù)據(jù)與第一次輸入shift kernel之前順序一致,并且這個(gè)shift操作可以通過SGD的方式進(jìn)行端到端訓(xùn)練,再具體的細(xì)節(jié)論文其實(shí)也沒有闡述的很清楚,而且我目前也沒有看到作者公布源代碼,不過這篇論文看起來還是很有意思的,論文中還分析了depthwise計(jì)算不高效的原因在于計(jì)算/IO時(shí)間導(dǎo)致運(yùn)行更慢的問題,其實(shí)這個(gè)shift kernel的作用并沒有產(chǎn)生新的信息或者去進(jìn)行特征的學(xué)習(xí)(畢竟連參數(shù)都沒有),而是對(duì)feature map空域的信息做了個(gè)混洗,使得與他相接的1×1卷積可以學(xué)到更豐富的特征,在我看來有點(diǎn)類似于在網(wǎng)絡(luò)內(nèi)部做數(shù)據(jù)增強(qiáng)的感覺。

GhostNet
GhostNet也是一篇很有意思且簡(jiǎn)潔的架構(gòu)設(shè)計(jì)的論文,作者在可視化一些訓(xùn)練好的神經(jīng)網(wǎng)絡(luò)中間feature map時(shí)發(fā)現(xiàn)它們通常會(huì)包含一些相似且冗余的特征圖,使得神經(jīng)網(wǎng)絡(luò)能得到更充分的學(xué)習(xí)?;谶@個(gè)想法,作者通過設(shè)定一系列廉價(jià)的線性運(yùn)算操作來代替部分卷積計(jì)算,以此來產(chǎn)生更多的特征圖,僅僅這么一個(gè)簡(jiǎn)單的操作就可以減少模型的參數(shù)量和計(jì)算量,而且在幾個(gè)視覺公開數(shù)據(jù)集上取得了很不錯(cuò)的效果,甚至超越了MobileNet V3,感覺非常的大道至簡(jiǎn),這也是我比較喜歡的原因。

基于特定硬件的神經(jīng)架構(gòu)搜索
另見 :https://zhuanlan.zhihu.com/p/320290820
設(shè)計(jì)方法總結(jié)
接下來我將結(jié)合自己看過的論文,還有這一年多的項(xiàng)目比賽經(jīng)歷談一談我所理解的圖像分類和目標(biāo)檢測(cè)相關(guān)輕量級(jí)模型設(shè)計(jì),本文思想還比較淺薄,主要是給自己的工作做個(gè)總結(jié),有不正確的地方希望大家能共同討論。
設(shè)計(jì)之前
通常我們都是基于已有的硬件架構(gòu)去進(jìn)行模型的部署,這個(gè)時(shí)候就需要確定這個(gè)架構(gòu)下能部署什么算子,可以通過已有的接口自己拓展哪些算子,并且哪些算子不是很高效。就拿我去年參加的某視覺加速比賽來說,當(dāng)時(shí)初出茅廬,不太懂硬件底層,頭鐵要在Xilinx ultra96 V1板子 + 我們組自研的硬件架構(gòu)上部署當(dāng)時(shí)最新,準(zhǔn)確率最高的EfficientNet,因?yàn)闇?zhǔn)確率確實(shí)高,老板就欽定必須使用這個(gè)模型,并且選擇了比較合適的EfficientNet-B4,輸入分辨率由384改成256。后來一頓開搞發(fā)現(xiàn)有很多h-sigmoid操作,這個(gè)雖然之前還沒有經(jīng)驗(yàn),但是還好很快想到用查找表去實(shí)現(xiàn)了,并且還發(fā)現(xiàn)我們的架構(gòu)尚且不能實(shí)現(xiàn)全連接層(勿噴,之前都是在搞全卷積網(wǎng)絡(luò)),所以里面的SE block還有最后一層都無法用我們的架構(gòu)部署,然后博士師兄就想到了利用ultra96板子上的ARM+NEON加速技術(shù)去實(shí)現(xiàn)這一部分,每次PS和PL交互數(shù)據(jù),當(dāng)時(shí)只有一個(gè)月的開發(fā)時(shí)間,因?yàn)檫@個(gè)模型比較大且當(dāng)時(shí)我們開發(fā)模式的問題,連續(xù)熬夜差點(diǎn)沒把整個(gè)組人的命搭進(jìn)去,最后上板跑幀率也只有6幀(師兄最開始預(yù)估能達(dá)到80幀,所以大家一直不停的往下做hhhhh),在ImageNet驗(yàn)證集上純浮點(diǎn)準(zhǔn)確率是0.805,INT8準(zhǔn)確率是0.793,幀率低的原因有兩點(diǎn),一個(gè)是模型確實(shí)很大,另一個(gè)是因?yàn)镾E block在每一個(gè)stride為1的module中都出現(xiàn)了,整個(gè)模型PS和PL交互十分頻繁,而我們當(dāng)時(shí)間很緊剛剛完成一版就必須提交了,所以這塊也根本沒有優(yōu)化,導(dǎo)致了延時(shí)很高,并且當(dāng)時(shí)我們的架構(gòu)只跑了100M的頻率,更高頻率會(huì)有一些bug(貌似是板子的問題),所以幀率非常低,這個(gè)真的是血的教訓(xùn):一定要量力而行,仔細(xì)研究評(píng)價(jià)指標(biāo),在硬件友好程度和精度上做一個(gè)trade-off,一味片面地追求精度真的要命呀。
輕量級(jí)CNN架構(gòu)設(shè)計(jì)
總的思路:選定合適結(jié)構(gòu) + 通道剪枝 + 量化
訓(xùn)練 :ImageNet pretrain model + Data Normalization(統(tǒng)計(jì)自己數(shù)據(jù)集的均值和方差) + Batch Normlization + 大batch size + 一堆數(shù)據(jù)增強(qiáng)tricks + 嘗試各種花里胡哨的loss function和optimizer
(再次說明這部分只討論圖像分類和目標(biāo)檢測(cè)兩種任務(wù),目前的視覺加速比賽基本都是基于這兩個(gè)任務(wù)做的,按照計(jì)算資源和內(nèi)存從小到大排列,不用問,沒有劃分原則)
1.絕對(duì)貧窮人口
輸入分辨率要小,如128,160,192或256; 下采樣使用MaxPooling; 特征學(xué)習(xí)層使用Depthwise Separable Convolution,即一層3×3的Depthwise + 一層pointwise(1×1標(biāo)準(zhǔn)卷積)堆疊; 激活函數(shù)用ReLU;
另外這里推薦看看MCUNet,感覺非常呦西,MIT韓松團(tuán)隊(duì)yyds!
2. 相對(duì)貧窮人口
輸入分辨率依舊要小,記住分辨率對(duì)計(jì)算量的影響都是翻倍的; 下采樣可以使用MaxPooling或者stride為2的Depthwise Separable Convolution; 特征學(xué)習(xí)層使用Depthwise Separable Convolution,或者M(jìn)obileNet V2的倒置殘差結(jié)構(gòu),又或是ShuffleNet V2的unit,1×1的Group convolution能處理的比較好的話其實(shí)也推薦使用(主要是計(jì)算/訪存); 激活函數(shù)用ReLU或者ReLU6;
3. 低收入人口
輸入數(shù)據(jù)選用小分辨率,如果對(duì)精度要求高一些可以適當(dāng)增大; 下采樣可以使用MaxPooling或者stride為2的Depthwise Separable Convolution; 特征學(xué)習(xí)層可以使用MobileNet V2的倒置殘差結(jié)構(gòu),又或是ShuffleNet V2的unit,也可以使用通道數(shù)小一點(diǎn)的3×3標(biāo)準(zhǔn)卷積; 激活函數(shù)用ReLU,ReLU6或者leaky ReLU,看效果了;
4.一般收入人口
輸入數(shù)據(jù)可以稍微大一些,288,320,384啥的可以考慮上了; 下采樣使用stride為2的Depthwise Separable Convolution或者stride為2的3×3卷積; 特征學(xué)習(xí)層既可以使用上述的,也可以使用3×3標(biāo)準(zhǔn)卷積 + 1×1標(biāo)準(zhǔn)卷積的堆疊形式,SE block這種硬件支持的還不錯(cuò)的可以嘗試加上; 激活函數(shù)除了上述的可以試試H-sigmoid和H-swish,不過據(jù)我經(jīng)驗(yàn)效果基本和ReLU差不多;
5.高收入人口
輸入數(shù)據(jù)的分辨率可以往500-600靠攏了; 下采樣和上述一樣; 特征學(xué)習(xí)層可以上ResNet + SE block的配置,ResNet是真的牛逼,5×5的卷積啥的也可以整上,第一層直接上7×7的標(biāo)準(zhǔn)卷積也不是不可以,資源再多了可以增加通道數(shù)和深度 或者 上多核并行計(jì)算; 激活函數(shù)可以用H-swish;
番外
目標(biāo)檢測(cè)任務(wù)中感覺Tiny YOLO V3非常受歡迎,建議嘗試!計(jì)算量太大可以換更輕量的backbone或者改輸入分辨率,輕量級(jí)的backbone+FPN的結(jié)構(gòu)也很棒,且推薦使用商湯開源的mmdetection,訓(xùn)練調(diào)參當(dāng)場(chǎng)起飛。
另外之前閱讀MIT HAN lab基于特定硬件的神經(jīng)架構(gòu)搜索相關(guān)文章時(shí)發(fā)現(xiàn)他們?cè)O(shè)計(jì)模型常用的一個(gè)子結(jié)構(gòu):MobileNetV2的倒置殘差模塊 + SE block + H-swish,看他們?cè)诤芏嗨惴铀俦荣惿夏昧斯谲?,感覺百試不爽呀,且根據(jù)硬件資源進(jìn)行拓展的靈活度也很高,具體可以參見他們今年發(fā)表的OnceForAll論文中的模型,源代碼都在Github上能找到,MIT HAN lab真學(xué)術(shù)界良心,再喊一句MIT韓松團(tuán)隊(duì)yyds!
最后總結(jié)
過去的一年被導(dǎo)師安排著參加各種比賽,去年啥也不懂的時(shí)候還能拿幾個(gè)不錯(cuò)的獎(jiǎng),今年感覺學(xué)了很多懂了很多,使用的模型也都對(duì)硬件比較友好,量化后幾乎無損(一個(gè)點(diǎn)以內(nèi)),反倒連連受挫,心情非常沮喪,而且總被奇奇怪怪的模型打敗,總有一種自己學(xué)了一身正派功夫,最后反倒被野路子出招一擊即潰的感覺,然后論文也被拒了,沒心思改投,回想一下碰上疫情的這一年真的好失落,可能還是我太菜了吧。
馬上也要開始投入找實(shí)習(xí)(希望老板能放我)刷題找工作的階段了,最近也在培養(yǎng)下一屆,把工作慢慢移交給他們,一想到找工作,整個(gè)人的心態(tài)都不一樣了,無心科研,這篇文章就算是對(duì)我過去一年多的工作做個(gè)總結(jié)吧,同時(shí)也希望我們課題組能夠發(fā)展的越來越好,多多拿比賽大獎(jiǎng),多多發(fā)論文。
END
