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

          綜述:輕量級(jí)CNN架構(gòu)設(shè)計(jì)

          共 14505字,需瀏覽 30分鐘

           ·

          2020-12-12 01:06

          ↑ 點(diǎn)擊藍(lán)字?關(guān)注極市平臺(tái)

          作者丨Ironboy
          來(lái)源丨GiantPandaCV
          編輯丨極市平臺(tái)

          極市導(dǎo)讀

          ?

          本文作者結(jié)合論文和項(xiàng)目比賽的經(jīng)驗(yàn),講述了輕量級(jí)CNN的發(fā)展以及設(shè)計(jì)總結(jié)。內(nèi)容包含基本概念、卷積計(jì)算類型、其他算子、常用激活函數(shù)、經(jīng)典輕量化模型等。>>加入極市CV技術(shù)交流群,走在計(jì)算機(jī)視覺(jué)的最前沿


          卷積神經(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)來(lái)確定一個(gè)網(wǎng)絡(luò)結(jié)構(gòu)的輸入圖像分辨率,深度,每一層寬度,拓?fù)浣Y(jié)構(gòu)等細(xì)節(jié)。

          公開(kāi)發(fā)表的論文大多都是基于ImageNet這種大型的公開(kāi)數(shù)據(jù)集來(lái)進(jìn)行的通用結(jié)構(gòu)設(shè)計(jì),早期只以其分類精度來(lái)證明設(shè)計(jì)的優(yōu)劣,后來(lái)也慢慢開(kāi)始對(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í)通常是基于已公開(kāi)發(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ì)算資源的超額要求使得根本無(wú)法在上面部署且達(dá)到實(shí)時(shí)性的要求。雖然可以通過(guò)知識(shí)蒸餾,通道剪枝,低比特量化等一系列手段來(lái)降低模型參數(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í)更為全局,語(yǔ)義層次更高的特征信息,相反,范圍越小則表示其所包含的特征越趨向局部和細(xì)節(jié)。因此感受野的范圍可以用來(lái)大致判斷每一層的抽象層次,并且我們可以很明顯地知道網(wǎng)絡(luò)越深,神經(jīng)元的感受野越大。

          感受野
          • 分辨率(Resolution)

          分辨率指的是輸入模型的圖像尺寸,即長(zhǎng)寬大小。通常情況會(huì)根據(jù)模型下采樣次數(shù)n和最后一次下采樣后feature map的分辨率k×k來(lái)決定輸入分辨率的大小,即:

          從輸入r×r到最后一個(gè)卷積特征feature map的k×k,整個(gè)過(guò)程是一個(gè)信息逐漸抽象化的過(guò)程,即網(wǎng)絡(luò)學(xué)習(xí)到的信息逐漸由低級(jí)的幾何信息轉(zhuǎn)變?yōu)楦呒?jí)的語(yǔ)義信息,這個(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)練無(wú)法收斂。

          在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ù),后來(lái)的backbone設(shè)計(jì)采用了更高效的module(或block)堆疊的方式,每個(gè)module是由多個(gè)卷積層組成,它的深度也可以指module的個(gè)數(shù),這種說(shuō)法在神經(jīng)架構(gòu)搜索(NAS)中出現(xiàn)的更為頻繁。通常而言網(wǎng)絡(luò)越深表達(dá)能力越強(qiáng),但深度大于某個(gè)值可能會(huì)帶來(lái)相反的效果,所以它的具體設(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ù)越來(lái)越多的,直到最后一層feature map達(dá)到最大,這是因?yàn)樵降缴顚?,feature map的分辨率越小,所包含的信息越高級(jí),所以需要更多的卷積核來(lái)進(jìn)行學(xué)習(xí)。通道越多效果越好,但帶來(lái)的計(jì)算量也會(huì)大大增加,所以具體設(shè)定也是一個(gè)調(diào)參的過(guò)程,并且各層通道數(shù)會(huì)按照8×的倍數(shù)來(lái)確定,這樣有利于GPU的并行計(jì)算。

          width,depth and resolution
          • 下采樣(Down-Sample)

          下采樣層有兩個(gè)作用,一是減少計(jì)算量,防止過(guò)擬合,二是增大感受野,使得后面的卷積核能夠?qū)W到更加全局的信息。下采樣的設(shè)計(jì)有兩種:

          1.采用stride為2的池化層,如Max-pooling或Average-pooling,目前通常使用Max-pooling,因?yàn)樗?jì)算簡(jiǎn)單且最大響應(yīng)能更好保留紋理特征;

          2.采用stride為2的卷積層,下采樣的過(guò)程是一個(gè)信息損失的過(guò)程,而池化層是不可學(xué)習(xí)的,用stride為2的可學(xué)習(xí)卷積層來(lái)代替pooling可以得到更好的效果,當(dāng)然同時(shí)也增加了一定的計(jì)算量。

          (突然想到為啥不使用雙線性插值,向下插值來(lái)代替Pooling,這個(gè)雖然比MaxPooling計(jì)算量更大,但是保留的信息應(yīng)該更豐富才是)

          • 上采樣(Up-Sampling)

          在卷積神經(jīng)網(wǎng)絡(luò)中,由于輸入圖像通過(guò)卷積神經(jīng)網(wǎng)絡(luò)(CNN)提取特征后,輸出的尺寸往往會(huì)變小,而有時(shí)我們需要將圖像恢復(fù)到原來(lái)的尺寸以便進(jìn)行進(jìn)一步的計(jì)算(如圖像的語(yǔ)義分割),這個(gè)使圖像由小分辨率映射到大分辨率的操作,叫做上采樣,它的實(shí)現(xiàn)一般有三種方式:

          • 插值,一般使用的是雙線性插值,因?yàn)樾Ч詈?,雖然計(jì)算上比其他插值方式復(fù)雜,但是相對(duì)于卷積計(jì)算可以說(shuō)不值一提;
          • 轉(zhuǎn)置卷積又或是說(shuō)反卷積,通過(guò)對(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;
          Max Unpooling
          • 參數(shù)量(Params)

          參數(shù)量指的網(wǎng)絡(luò)中可學(xué)習(xí)變量的數(shù)量,包括卷積核的權(quán)重weight,批歸一化(BN)的縮放系數(shù)γ,偏移系數(shù)β,有些沒(méi)有BN的層可能有偏置bias,這些都是可學(xué)習(xí)的參數(shù) ,即在模型訓(xùn)練開(kāi)始前被賦予初值,在訓(xùn)練過(guò)程根據(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ò)的前向推理過(guò)程基本上都是乘累加計(jì)算,所以它的計(jì)算量也是指的前向推理過(guò)程中乘加運(yùn)算的次數(shù),通常用FLOPs來(lái)表示,即floating point operations(浮點(diǎn)運(yùn)算數(shù))。計(jì)算量越大,在同一平臺(tái)上模型運(yùn)行延時(shí)越長(zhǎng),尤其是在移動(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à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ì)算過(guò)程如下圖所示,由于太過(guò)基礎(chǔ),故不贅述。

          標(biāo)準(zhǔn)卷積
          • 深度卷積 (Depthwise Convolution)

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

          深度可分離卷積

          深度卷積之前一直被吐槽在GPU上運(yùn)行速度還不如一般的標(biāo)準(zhǔn)卷積,因?yàn)閐epthwise 的卷積核復(fù)用率比普通卷積要小很多,計(jì)算和內(nèi)存訪問(wèn)的比值比普通卷積更小,因此會(huì)花更多時(shí)間在內(nèi)存開(kāi)銷上,而且per-channel的矩陣計(jì)算很小不容易并行導(dǎo)致的更慢,但理論上計(jì)算量和參數(shù)量都是大大減少的,只是底層優(yōu)化的問(wèn)題。

          • 分組卷積 (Group Convolution)

          分組卷積最早在AlexNet中出現(xiàn),當(dāng)時(shí)作者在訓(xùn)練模型時(shí)為了減少顯存占用而將feature map分組然后給多個(gè)GPU進(jìn)行處理,最后把多個(gè)輸出進(jìn)行融合。具體計(jì)算過(guò)程是,分組卷積首先將輸入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è)組之間的信息能夠交互起來(lái)。

          • 空洞卷積 (Dilated Convolution)

          空洞卷積是針對(duì)圖像語(yǔ)義分割問(wèn)題中下采樣會(huì)降低圖像分辨率、丟失信息而提出的一種卷積思路。通過(guò)間隔取值擴(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ì)算過(guò)程,可以看出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)用于語(yǔ)義分割當(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)來(lái)進(jìn)行卷積計(jì)算,這樣卷積核就能在訓(xùn)練過(guò)程中擴(kuò)展到很大的范圍。而顯而易見(jiàn)的是可變性卷積雖然比其他卷積方式更加靈活,可以根據(jù)每張輸入圖片感知不同位置的信息,類似于注意力,從而達(dá)到更好的效果,但是它比可行變卷積在增加了很多計(jì)算量和實(shí)現(xiàn)難度,目前感覺(jué)只在GPU上優(yōu)化的很好,在其他平臺(tái)上還沒(méi)有見(jiàn)到部署。

          其他算子

          • 池化(pooling)

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

          • 最大池化和平均池化
          最大池化和平均池化
          • 全局平均池化

          全局平均池化的操作是對(duì)一個(gè)維度為(C,H,W)的feature map,在HW方向整個(gè)取平均,然后輸出一個(gè)長(zhǎng)度為C的向量,這個(gè)操作一般在分類模型的最后一個(gè)feature map之后出現(xiàn),然后接一個(gè)全連接層就可以完成分類結(jié)果的輸出了。早期的分類模型都是把最后一個(gè)feature map直接拉平成C×H×W的向量,然后再接全連接層,但是顯然可以看出來(lái)這個(gè)計(jì)算量極大,甚至有的模型最后一個(gè)全連接層占了整個(gè)模型計(jì)算量的50%以上,之后由研究人員發(fā)現(xiàn)對(duì)這個(gè)feature map做一個(gè)全局平均池化,然后再加全連接層可以達(dá)到相似的效果,且計(jì)算量降低到了原來(lái)的1/HW。

          • 最大向上池化

          這個(gè)操作在前面基本概念一節(jié)上采樣段落中有描述,故不贅述。

          • 全連接計(jì)算(Full Connected)

          這個(gè)本質(zhì)其實(shí)就是矩陣乘法,輸入一個(gè)(B, iC)的數(shù)據(jù),權(quán)重為(iC, oC),那么輸出為(B, oC),在多層感知機(jī)和分類模型最后一層常常見(jiàn)到。

          全連接結(jié)構(gòu)
          • Addition / Concatenate分支

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

          Add &amp; Concat
          • 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)了信息的交互。

          channel shuffle

          常用激活函數(shù)

          激活函數(shù)的非線性是神經(jīng)網(wǎng)絡(luò)發(fā)揮作用最重要的因素之一,而對(duì)于實(shí)際部署,激活函數(shù)的實(shí)現(xiàn)也是很重要的一個(gè)方面,實(shí)現(xiàn)的不好對(duì)加速效果影響很大,這里主要講幾個(gè)部署當(dāng)中常見(jiàn)的激活函數(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來(lái)代替,具體實(shí)現(xiàn)方法多種多樣 ,還算簡(jiǎn)單。

          ReLU &amp; LeakyReLU
          • Sigmoid系列

          這里主要指sigmoid,還有和他相關(guān)的swish:

          可以看出,如果按照公式來(lái)實(shí)現(xiàn)sigmoid對(duì)低性能的硬件來(lái)說(shuō)非常不友好,因?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ì)精度沒(méi)啥影響。

          經(jīng)典輕量化模型

          早期比較經(jīng)典的卷積神經(jīng)網(wǎng)絡(luò),如AlexNet,VGG,GoogleNet(或Inception),ResNet,DenseNet都是以提升模型在ImageNet數(shù)據(jù)集上的分類精度為主了,很少考慮參數(shù)量和計(jì)算量的問(wèn)題,他們的主要結(jié)構(gòu)解析起來(lái)也比較簡(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)檫@塊很多人都講過(guò),所以我會(huì)簡(jiǎn)單一些,挑重點(diǎn)說(shuō)說(shuō)。

          • SqueezeNet

          SqueezeNet是公認(rèn)的輕量級(jí)模型設(shè)計(jì)最早期的工作之一,作者提出了三種策略來(lái)實(shí)現(xiàn)在保持精度的情況下大大減少當(dāng)時(shí)主流模型(以AlexNet為例)的計(jì)算量和參數(shù)量:

          1.將模型中一部分的3×3卷積用1×1來(lái)代替,1×1卷積是3×3參數(shù)量和計(jì)算量的1/9,所以可以大大減少參數(shù)量和計(jì)算量;

          2.減少3×3卷積的輸入通道數(shù),這個(gè)可以通過(guò)在進(jìn)入3×3卷積之前加一個(gè)1×1卷積來(lái)實(shí)現(xiàn)通道數(shù)量的減少;

          3.將下采樣層的位置往后推,使得模型可以在更大的feature map上進(jìn)行更多的學(xué)習(xí),這一步雖然會(huì)在增加計(jì)算量,但是和上面兩個(gè)策略結(jié)合可以在維持模型精度的情況下仍大大減少參數(shù)量和計(jì)算量;

          fire module

          根據(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的卷積拼接起來(lái)的,每次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)要的講:

          1.MobileNet V1主要思想是提出了一種新的結(jié)構(gòu)—深度可分離卷積(Depthwise Separable Convolution)來(lái)代替標(biāo)準(zhǔn)3×3卷積,從而大大減少模型的參數(shù)量和計(jì)算量;

          2.MobileNet V2在V1的基礎(chǔ)上提出了一種倒置殘差的模塊,這個(gè)模塊有三個(gè)卷積,第一個(gè)部分是一個(gè)1×1標(biāo)準(zhǔn)卷積,用來(lái)升維,第二個(gè)部分是由3×3深度卷積+1×1標(biāo)準(zhǔn)卷積構(gòu)成的深度分離卷積,用來(lái)學(xué)習(xí)特征和降維,模塊的輸出和輸入再進(jìn)行一個(gè)Addition的操作,由于和ResNet中維度升降方式相反,所以稱為倒置殘差。中間升維的作用是讓深度可分離卷積得到更充分的學(xué)習(xí),計(jì)算量相對(duì)于標(biāo)準(zhǔn)卷積來(lái)說(shuō)也不大,而且這種升降維的方式非常靈活,可以大大減少計(jì)算量。本文還從流形學(xué)的角度探究了輸入深度可分離卷積上一層的ReLU6對(duì)信息傳遞的影響,理論證明去掉上一個(gè)1×1標(biāo)準(zhǔn)卷積的ReLU激活函數(shù)能更有利于后面的深度可分離卷積對(duì)特征的學(xué)習(xí)。

          MobileNet V2

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

          MobileNet V3

          根據(jù)我自己的比賽和項(xiàng)目經(jīng)驗(yàn)來(lái)看,還是MobileNet V1和V2的結(jié)構(gòu)比較實(shí)用,參數(shù)量和計(jì)算量小,可拓展性好,SE block這種模塊對(duì)延時(shí)影響還是不小,而且我們發(fā)現(xiàn)其他各種花里胡哨的激活函數(shù)跟ReLU/ReLU6相比都差不多,對(duì)精度沒(méi)有很大的影響,還不如直接部署ReLU/ReLU6來(lái)的方便。

          • ShuffleNet系列

          曠視出品的ShuffleNet系列有兩篇論文,且后一篇在打前一篇的臉,很有意思。

          1.ShuffleNet V1是在MobileNet V1后MobileNet V2前提出的,說(shuō)實(shí)話結(jié)構(gòu)上和MobileNet V2還挺像,大家可以上下兩張圖片對(duì)比一下。兩者都想到了學(xué)習(xí)ResNet的殘差結(jié)構(gòu),區(qū)別在于ShuffleNet V1覺(jué)得block當(dāng)中的1×1標(biāo)準(zhǔn)卷積也非常耗時(shí),于是用1×1的分組卷積外加channel shuffle的操作給替換了,然后MobileNet V2會(huì)先升維讓深度可分離卷積得到充分的學(xué)習(xí)再降維回來(lái),ShuffleNet V1中stride為2的模塊也有自己的特色,雖然看著MobileNet V2的結(jié)構(gòu)更簡(jiǎn)潔一些,但ShuffleNet V1創(chuàng)新也是不少,尤其那個(gè)用channel shuffle增強(qiáng)不同組之間信息交互的操作。

          ShuffleNet V1

          2. ShuffleNet V2論文是一篇誠(chéng)意滿滿之作,作者通過(guò)分析ShuffleNet v1與MobileNet v2這兩個(gè)移動(dòng)端網(wǎng)絡(luò)在GPU/ARM兩種平臺(tái)下的時(shí)間消耗分布,看出Conv等計(jì)算密集型操作占了絕大多數(shù)時(shí)間,但其它像Elemwise和IO等內(nèi)存讀寫(xiě)密集型操作也占了相當(dāng)比例的時(shí)間,因此像以往那樣僅以FLOPs來(lái)作為指導(dǎo)準(zhǔn)則來(lái)設(shè)計(jì)CNN網(wǎng)絡(luò)是不完備的,雖然它可以反映出占大比例時(shí)間的Conv操作,但不夠準(zhǔn)確。于是作者提出了高效網(wǎng)絡(luò)設(shè)計(jì)的四個(gè)指導(dǎo)原則:

          1. 當(dāng)輸入和輸出的通道數(shù)相同時(shí),conv計(jì)算所需的MAC(memory access cost)最??;
          2. 大量的分組卷積會(huì)增加MAC開(kāi)銷;
          3. 網(wǎng)絡(luò)結(jié)構(gòu)的碎片化會(huì)減少其可并行優(yōu)化的程度,GoogleNet系列和NASNet中很多分支進(jìn)行不同的卷積/pool計(jì)算非常碎片,對(duì)硬件運(yùn)行很不友好;
          4. Element-wise操作不可忽視,對(duì)延時(shí)影響很大,包括ReLU,Addition,AddBias等,主要是因?yàn)檫@些操作計(jì)算與內(nèi)存訪問(wèn)的占比太??;

          基于此,作者提出了ShuffleNet V2的blocks,如下所示,與V1相比,去掉了分組卷積的操作,去掉了Add操作,換成了Concat,stride為2的block的旁路把平均池化換成了深度可分離卷積,為了繼續(xù)延續(xù)channel shuffle的操作,作者在block進(jìn)去的地方做了個(gè)split的操作,最后再concat+channel shuffle,這里是為了替換掉之前的Add,同時(shí)也可以減少計(jì)算量。

          ShuffleNet V2
          • Shift: A Zero FLOP, Zero Parameter Alternative to Spatial Convolutions

          這是一篇很有意思的論文,主要是提出了一種無(wú)參數(shù),無(wú)計(jì)算的移位算子來(lái)代替ResNet中計(jì)算量占比很高的3×3卷積,這種算子稱為shift kernel,如下圖所示,只需要根據(jù)kernel上的shift信息對(duì)feature map進(jìn)行位置上的上下左右偏移即可得到新的feature map,沒(méi)有計(jì)算,僅僅是訪存操作。詳細(xì)一點(diǎn)說(shuō)就是如下面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操作可以通過(guò)SGD的方式進(jìn)行端到端訓(xùn)練,再具體的細(xì)節(jié)論文其實(shí)也沒(méi)有闡述的很清楚,而且我目前也沒(méi)有看到作者公布源代碼,不過(guò)這篇論文看起來(lái)還是很有意思的,論文中還分析了depthwise計(jì)算不高效的原因在于計(jì)算/IO時(shí)間導(dǎo)致運(yùn)行更慢的問(wèn)題,其實(shí)這個(gè)shift kernel的作用并沒(méi)有產(chǎn)生新的信息或者去進(jìn)行特征的學(xué)習(xí)(畢竟連參數(shù)都沒(méi)有),而是對(duì)feature map空域的信息做了個(gè)混洗,使得與他相接的1×1卷積可以學(xué)到更豐富的特征,在我看來(lái)有點(diǎn)類似于在網(wǎng)絡(luò)內(nèi)部做數(shù)據(jù)增強(qiáng)的感覺(jué)。

          Shift
          • 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è)想法,作者通過(guò)設(shè)定一系列廉價(jià)的線性運(yùn)算操作來(lái)代替部分卷積計(jì)算,以此來(lái)產(chǎn)生更多的特征圖,僅僅這么一個(gè)簡(jiǎn)單的操作就可以減少模型的參數(shù)量和計(jì)算量,而且在幾個(gè)視覺(jué)公開(kāi)數(shù)據(jù)集上取得了很不錯(cuò)的效果,甚至超越了MobileNet V3,感覺(jué)非常的大道至簡(jiǎn),這也是我比較喜歡的原因。

          GhostNet

          基于特定硬件的神經(jīng)架構(gòu)搜索

          基于特定硬件的神經(jīng)架構(gòu)搜索(MIT HAN Lab論文總結(jié)
          https://zhuanlan.zhihu.com/p/320290820)

          設(shè)計(jì)方法總結(jié)

          接下來(lái)我將結(jié)合自己看過(guò)的論文,還有這一年多的項(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)下能部署什么算子,可以通過(guò)已有的接口自己拓展哪些算子,并且哪些算子不是很高效。就拿我去年參加的某視覺(jué)加速比賽來(lái)說(shuō),當(dāng)時(shí)初出茅廬,不太懂硬件底層,頭鐵要在Xilinx ultra96 V1板子 + 我們組自研的硬件架構(gòu)上部署當(dāng)時(shí)最新,準(zhǔn)確率最高的EfficientNet,因?yàn)闇?zhǔn)確率確實(shí)高,老板就欽定必須使用這個(gè)模型,并且選擇了比較合適的EfficientNet-B4,輸入分辨率由384改成256。后來(lái)一頓開(kāi)搞發(fā)現(xiàn)有很多swish操作,這個(gè)雖然之前還沒(méi)有經(jīng)驗(yàn),但是還好很快想到用查找表去實(shí)現(xiàn)了,并且還發(fā)現(xiàn)我們的架構(gòu)尚且不能實(shí)現(xiàn)全連接層(勿噴,之前都是在搞全卷積網(wǎng)絡(luò)),所以里面的SE block還有最后一層都無(wú)法用我們的架構(gòu)部署,然后博士師兄就想到了利用ultra96板子上的ARM+NEON加速技術(shù)去實(shí)現(xiàn)這一部分,每次PS和PL交互數(shù)據(jù),當(dāng)時(shí)只有一個(gè)月的開(kāi)發(fā)時(shí)間,因?yàn)檫@個(gè)模型比較大且當(dāng)時(shí)我們開(kāi)發(fā)模式的問(wèn)題,連續(xù)熬夜差點(diǎn)沒(méi)把整個(gè)組人的命搭進(jìn)去,最后上板跑幀率也只有6幀(師兄最開(kāi)始預(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í)間很緊剛剛完成一版就必須提交了,所以這塊也根本沒(méi)有優(yōu)化,導(dǎo)致了延時(shí)很高,并且當(dāng)時(shí)我們的架構(gòu)只跑了100M的頻率,更高頻率會(huì)有一些bug(貌似是板子的問(wèn)題),所以幀率非常低,這個(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

          (再次說(shuō)明這部分只討論圖像分類和目標(biāo)檢測(cè)兩種任務(wù),目前的視覺(jué)加速比賽基本都是基于這兩個(gè)任務(wù)做的,按照計(jì)算資源和內(nèi)存從小到大排列,不用問(wèn),沒(mé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,感覺(jué)非常呦西,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,不過(guò)據(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ù)中感覺(jué)Tiny YOLO V3非常受歡迎,建議嘗試!計(jì)算量太大可以換更輕量的backbone或者改輸入分辨率,輕量級(jí)的backbone+FPN的結(jié)構(gòu)也很棒,且推薦使用商湯開(kāi)源的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è)诤芏嗨惴铀俦荣惿夏昧斯谲?,感覺(jué)百試不爽呀,且根據(jù)硬件資源進(jìn)行拓展的靈活度也很高,具體可以參見(jiàn)他們今年發(fā)表的OnceForAll論文中的模型,源代碼都在Github上能找到,MIT HAN lab真學(xué)術(shù)界良心,再喊一句MIT韓松團(tuán)隊(duì)yyds!

          最后總結(jié)

          過(guò)去的一年被導(dǎo)師安排著參加各種比賽,去年啥也不懂的時(shí)候還能拿幾個(gè)不錯(cuò)的獎(jiǎng),今年感覺(jué)學(xué)了很多懂了很多,使用的模型也都對(duì)硬件比較友好,量化后幾乎無(wú)損(一個(gè)點(diǎn)以內(nèi)),反倒連連受挫,心情非常沮喪,而且總被奇奇怪怪的模型打敗,總有一種自己學(xué)了一身正派功夫,最后反倒被野路子出招一擊即潰的感覺(jué),然后論文也被拒了,沒(méi)心思改投,回想一下碰上疫情的這一年真的好失落,可能還是我太菜了吧。

          馬上也要開(kāi)始投入找實(shí)習(xí)(希望老板能放我)刷題找工作的階段了,最近也在培養(yǎng)下一屆,把工作慢慢移交給他們,一想到找工作,整個(gè)人的心態(tài)都不一樣了,無(wú)心科研,這篇文章就算是對(duì)我過(guò)去一年多的工作做個(gè)總結(jié)吧,同時(shí)也希望我們課題組能夠發(fā)展的越來(lái)越好,多多拿比賽大獎(jiǎng),多多發(fā)論文。


          推薦閱讀


          添加極市小助手微信(ID : cvmart2),備注:姓名-學(xué)校/公司-研究方向-城市(如:小極-北大-目標(biāo)檢測(cè)-深圳),即可申請(qǐng)加入極市目標(biāo)檢測(cè)/圖像分割/工業(yè)檢測(cè)/人臉/醫(yī)學(xué)影像/3D/SLAM/自動(dòng)駕駛/超分辨率/姿態(tài)估計(jì)/ReID/GAN/圖像增強(qiáng)/OCR/視頻理解等技術(shù)交流群:月大咖直播分享、真實(shí)項(xiàng)目需求對(duì)接、求職內(nèi)推、算法競(jìng)賽、干貨資訊匯總、與?10000+來(lái)自港科大、北大、清華、中科院、CMU、騰訊、百度等名校名企視覺(jué)開(kāi)發(fā)者互動(dòng)交流~

          △長(zhǎng)按添加極市小助手

          △長(zhǎng)按關(guān)注極市平臺(tái),獲取最新CV干貨

          覺(jué)得有用麻煩給個(gè)在看啦~??
          瀏覽 74
          點(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>
                  成人网大香蕉视频 | 九色91视频 | 午夜黄色毛片 | 亚洲性爱专区 | 亚洲天堂二区 |