MobileNet 系列:從V1到V3
轉自:輕量級神經網絡“巡禮”(二)—— MobileNet,從V1到V3
自從2017年由谷歌公司提出,MobileNet可謂是輕量級網絡中的Inception,經歷了一代又一代的更新。成為了學習輕量級網絡的必經之路。
MobileNet V1
其實介紹MobileNetV1(以下簡稱V1)只有一句話,MobileNetV1就是把VGG中的標準卷積層換成深度可分離卷積就可以了。
那么,這個深度可分離卷積是什么?
深度可分離卷積
深度可分離卷積(depthwise separable convolution),根據史料記載,可追溯到2012年的論文Simplifying ConvNets for Fast Learning,作者提出了可分離卷積的概念(下圖(a)):
Laurent Sifre博士2013年在谷歌實習期間,將可分離卷積拓展到了深度(depth),并且在他的博士論文Rigid-motion scattering for image classification中有詳細的描寫,感興趣的同學可以去看看論文
可分離卷積主要有兩種類型:空間可分離卷積和深度可分離卷積。
空間可分離,顧名思義,空間可分離就是將一個大的卷積核變成兩個小的卷積核,比如將一個 3×33\times 33×3 的核分成一個 3×13\times 13×1和一個 1×31\times 31×3 的核:
[123000246]=[102]×[123]\left[ \begin{matrix} 1 & 2 & 3\\ 0 & 0 & 0\\ 2 & 4 & 6\\ \end{matrix} \right] =\left[ \begin{matrix} 1 \\ 0 \\ 2 \\ \end{matrix} \right] \times \left[ \begin{matrix} 1 & 2 & 3\\ \end{matrix} \right] ???102?204?306????=???102????×[1?2?3?]
由于空間可分離卷積不在MobileNet的范圍內,就不說了。
深度可分離卷積就是將普通卷積拆分成為一個深度卷積和一個逐點卷積。
標準卷積
我們先來看一下標準的卷積操作:
輸入一個 12×12×312\times 12\times 312×12×3的一個輸入特征圖,經過 5×5×35\times 5\times 35×5×3的卷積核卷積得到一個 8×8×18\times 8\times 18×8×1 的輸出特征圖。如果此時我們有 256 個特征圖,我們將會得到一個8×8×2568\times 8\times 2568×8×256 的輸出特征圖。
以上就是標準卷積所干的活。那深度卷積和逐點卷積呢?
深度卷積
與標準卷積網絡不一樣的是,我們將卷積核拆分成為但單通道形式,在不改變輸入特征圖像的深度的情況下,對每一通道進行卷積操作,這樣就得到了和輸入特征圖通道數一致的輸出特征圖。如上圖:輸入 12×12×312\times 12\times 312×12×3 的特征圖,經過 5×5×1×35\times 5\times 1\times 35×5×1×3 的深度卷積之后,得到了8×8×3的輸出特征圖。輸入個輸出的維度是不變的 3。這樣就會有一個問題,通道數太少,特征圖的維度太少,能獲取到足夠的有效信息嗎?
逐點卷積
逐點卷積就是1×1卷積。主要作用就是對特征圖進行升維和降維,如下圖:
在深度卷積的過程中,我們得到了 8×8×38\times 8\times 38×8×3 的輸出特征圖,我們用 256256256 個 1×1×31\times 1\times 31×1×3 的卷積核對輸入特征圖進行卷積操作,輸出的特征圖和標準的卷積操作一樣都是 8×8×2568\times 8\times 2568×8×256 了。
標準卷積與深度可分離卷積的過程對比如下:
為什么要深度可分離卷積?
這個問題很好回答,如果有一個方法能讓你用更少的參數,更少的運算,但是能達到差的不是很多的結果,你會使用嗎?
深度可分離卷積就是這樣的一個方法。我們首先來計算一下標準卷積的參數量與計算量(只考慮MAdd):
標準卷積/深度可分離卷積參數量/計算量對比
標準卷積的參數量
卷積核的尺寸是 Dk×Dk×MD_k\times D_k\times MDk?×Dk?×M,一共有 NNN 個,所以標準卷積的參數量是:
DK×DK×M×ND_K\times D_K\times M\times N DK?×DK?×M×N
標準卷積的計算量
卷積核的尺寸是 Dk×Dk×MD_k\times D_k\times MDk?×Dk?×M,一共有 NNN 個,每一個都要進行 DW×DHD_W\times D_HDW?×DH? 次運算,所以標準卷積的計算量是:
DK×DK×M×N×DW×DHD_K\times D_K\times M\times N\times D_W\times D_H DK?×DK?×M×N×DW?×DH?
標準卷積算完了,我們接下來計算深度可分離卷積的參數量和計算量:
深度可分離卷積的參數量
深度可分離卷積的參數量由深度卷積和逐點卷積兩部分組成:
深度卷積的卷積核尺寸 DK×DK×MD_K\times D_K\times MDK?×DK?×M;逐點卷積的卷積核尺寸為 1×1×M1\times 1\times M1×1×M,一共有 NNN 個,所以深度可分離卷積的參數量是:
DK×DK×M+M×ND_K\times D_K\times M+M\times N DK?×DK?×M+M×N
深度可分離卷積的計算量
深度可分離卷積的計算量也是由深度卷積和逐點卷積兩部分組成:
深度卷積的卷積核尺寸 DK×DK×MD_K\times D_K\times MDK?×DK?×M,一共要做 DW×DHD_W\times D_HDW?×DH?次乘加運算;逐點卷積的卷積核尺寸為 1×1×M1\times 1\times M1×1×M,有 NNN 個,一共要做 DW×DHD_W\times D_HDW?×DH?次乘加運算,所以深度可分離卷積的計算量是:
DK×DK×M×DW×DH+M×N×DW×DHD_K\times D_K\times M\times D_W\times D_H+M\times N\times D_W\times D_H DK?×DK?×M×DW?×DH?+M×N×DW?×DH?
深度可分離卷積與標準卷積的參數量/計算量之比
參數量:
DK×DK×M+M×NDK×DK×M×N=1N+1DK2\frac{D_K\times D_K\times M+M\times N}{D_K\times D_K\times M\times N}=\frac{1}{N}+\frac{1}{D_K^2} DK?×DK?×M×NDK?×DK?×M+M×N?=N1?+DK2?1?
計算量:
DK×DK×M×DW×DH+M×N×DW×DHDK×DK×M×N×DW×DH=1N+1DK2\frac{D_K\times D_K\times M\times D_W\times D_H+M\times N\times D_W\times D_H}{D_K\times D_K\times M\times N\times D_W\times D_H}=\frac{1}{N}+\frac{1}{D_K^2} DK?×DK?×M×N×DW?×DH?DK?×DK?×M×DW?×DH?+M×N×DW?×DH??=N1?+DK2?1?
可以看到參數數量和乘加操作的運算量均下降為原來的1N+1DK2\frac{1}{N}+\frac{1}{D_K^2}N1?+DK2?1?,我們通常所使用的是3×3的卷積核,也就是會下降到原來的九分之一到八分之一。
V1卷積層
上圖左邊是標準卷積層,右邊是V1的卷積層,虛線處是不相同點。V1的卷積層,首先使用3×3的深度卷積提取特征,接著是一個BN層,隨后是一個ReLU層,在之后就會逐點卷積,最后就是BN和ReLU了。這也很符合深度可分離卷積,將左邊的標準卷積拆分成右邊的一個深度卷積和一個逐點卷積。
等等,我們發現有什么東西混了進來???ReLU6是什么?
ReLU6
上圖左邊是普通的ReLU,對于大于0的值不進行處理,右邊是ReLU6,當輸入的值大于6的時候,返回6,relu6“具有一個邊界”。作者認為ReLU6作為非線性激活函數,在低精度計算下具有更強的魯棒性。(這里所說的“低精度”,我看到有人說不是指的float16,而是指的定點運算(fixed-point arithmetic))
現在就有一個問題,標準卷積核深度可分離卷積層到底對結果有什么樣的影響呢?
上實驗。
可以看到使用深度可分離卷積與標準卷積,參數和計算量能下降為后者的九分之一到八分之一左右。但是準確率只有下降極小的1%。
V1網絡結構
MobileNet的網絡結構如上圖所示。首先是一個 3×33\times 33×3 的標準卷積,s2進行下采樣。然后就是堆積深度可分離卷積,并且其中的部分深度卷積會利用s2進行下采樣。然后采用平均池化層將feature變成 1×11\times 11×1,根據預測類別大小加上全連接層,最后是一個softmax層。整個網絡有28層,其中深度卷積層有13層。
實驗結果
分類、檢測、分割定量結果略。
MobileNet V2
MobileNetV2: Inverted Residuals and Linear Bottlenecks 論文地址:https://arxiv.org/abs/1704.04861 收錄:CVPR2018
MobileNetV1(以下簡稱:V1)過后,我們就要討論討論MobileNetV2(以下簡稱:V2)了。為了能更好地討論V2,我們首先再回顧一下V1:
回顧MobileNet V1
V1核心思想是采用 深度可分離卷積 操作。在相同的權值參數數量的情況下,相較標準卷積操作,可以減少數倍的計算量,從而達到提升網絡運算速度的目的。
V1的block如下圖所示:
首先利用 3×33\times 33×3 的深度可分離卷積提取特征,然后利用 1×11\times 11×1 的卷積來擴張通道。用這樣的block堆疊起來的MobileNetV1既能較少不小的參數量、計算量,提高網絡運算速度,又能的得到一個接近于標準卷積的還不錯的結果,看起來是很美好的。
但是!
有人在實際使用的時候, 發現深度卷積部分的卷積核比較容易訓廢掉:訓完之后發現深度卷積訓出來的卷積核有不少是空的:
這是為什么?
作者認為這是ReLU這個濃眉大眼的激活函數的鍋。(沒想到你個濃眉大眼的ReLU激活函數也叛變革命了???)
ReLU做了些啥?
V2的論文中,作者也有這樣的一個解釋。(論文中的實在不是很好懂,我就根據一些解讀結合我的想法簡單說說吧。有說的不正確的地方,還請各位大佬指出,感謝!)
這是將低維流形的ReLU變換embedded到高維空間中的的例子。
我們在這里拋棄掉流形這個概念,通俗理解一下。
假設在2維空間有一組由 mmm 個點組成的螺旋線 XmX_mXm? 數據(如input),利用隨機矩陣 TTT 映射到 nnn 維空間上并進行ReLU運算,即:
y=ReLU(T?Xm)y=ReLU(T\cdot X_m) y=ReLU(T?Xm?)
其中,XmX_mXm? 被隨機矩陣T映射到了 nnn 維空間(T?XmT\cdot X_mT?Xm?),再利用隨機矩陣 TTT 的逆矩陣 T?1T^{-1}T?1,將 yyy 映射回2維空間當中:
Xm′=T?1?yX'_m=T^{-1}\cdot y Xm′?=T?1?y
全過程如下表示:
Xm′=T?1?ReLU(T?Xm)X'_m=T^{-1}\cdot ReLU(T\cdot X_m) Xm′?=T?1?ReLU(T?Xm?)
換句話說,就是對一個 nnn 維空間中的一個“東西”做ReLU運算,然后(利用T的逆矩陣 T?1T^{-1}T?1恢復)對比ReLU之后的結果與Input的結果相差有多大。
可以看到:
當 n=2,3n = 2,3n=2,3 時,與Input相比有很大一部分的信息已經丟失了。而當 n=15n = 15n=15 到 303030 ,還是有相當多的地方被保留了下來。
也就是說,對低維度做ReLU運算,很容易造成信息的丟失。而在高維度進行ReLU運算的話,信息的丟失則會很少。
這就解釋了為什么深度卷積的卷積核有不少是空。發現了問題,我們就能更好地解決問題。針對這個問題,可以這樣解決:既然是ReLU導致的信息損耗,將ReLU替換成線性激活函數。
Linear bottleneck
我們當然不能把所有的激活層都換成線性的啊,所以我們就悄咪咪的把最后的那個ReLU6換成Linear。(至于為什么換最后一個ReLU6而不換第一個和第二個ReLU6,看到后面就知道了。)
Separable with linear bottleneck
作者將這個部分稱之為linear bottleneck。對,就是論文名中的那個linear bottleneck。
Expansion layer
現在還有個問題是,深度卷積本身沒有改變通道的能力,來的是多少通道輸出就是多少通道。如果來的通道很少的話,DW深度卷積只能在低維度上工作,這樣效果并不會很好,所以我們要“擴張”通道。既然我們已經知道PW逐點卷積也就是1×1卷積可以用來升維和降維,那就可以在DW深度卷積之前使用PW卷積進行升維(升維倍數為t,t=6),再在一個更高維的空間中進行卷積操作來提取特征:
也就是說,不管輸入通道數是多少,經過第一個PW逐點卷積升維之后,深度卷積都是在相對的更高6倍維度上進行工作。
Inverted residuals
回顧V1的網絡結構,我們發現V1很像是一個直筒型的VGG網絡。我們想像 ResNet 一樣復用我們的特征,所以我們引入了shortcut結構,這樣V2的block就是如下圖形式:
對比一下 ResNet 和 V2:
可以發現,都采用了 1×1 -> 3 ×3 -> 1 × 1 的模式,以及都使用Shortcut結構。但是不同點呢:
- ResNet 先降維 (0.25倍)、卷積、再升維。
- MobileNetV2 則是 先升維 (6倍)、卷積、再降維。
剛好V2的block剛好與Resnet的block相反,作者將其命名為Inverted residuals。就是論文名中的Inverted residuals。
V2的block
至此,V2的最大的創新點就結束了,我們再總結一下V2的block:
我們將V1和V2的block進行一下對比:
左邊是v1的block,沒有Shortcut并且帶最后的ReLU6。
右邊是v2的加入了1×1升維,引入Shortcut并且去掉了最后的ReLU,改為Linear。步長為1時,先進行1×1卷積升維,再進行深度卷積提取特征,再通過Linear的逐點卷積降維。將input與output相加,形成殘差結構。步長為2時,因為input與output的尺寸不符,因此不添加shortcut結構,其余均一致。
V2的網絡結構
28×28×32那一層的步長為2的話,輸出應該是14×14,應該是一處錯誤。按照作者論文里的說法,自己修改了一下:
實驗結果
分類、檢測、分割定量實驗略。
V1 VS V2
可以看到,雖然V2的層數比V1的要多很多,但是FLOPs,參數以及CPU耗時都是比V1要好的。
V1V2在google Pixel 1手機上在Image Classification任務的對比:
MobileNetV2 模型在整體速度范圍內可以更快實現相同的準確性。
目標檢測和語義分割的結果:
綜上,MobileNetV2 提供了一個非常高效的面向移動設備的模型,可以用作許多視覺識別任務的基礎。
但是!
在我實際應用V1V2時,V1的效果都要稍微好一點。上一張gluonCV的結果圖,和我的實現也差不多:
不知道為什么。
MobileNet V3
V1,V2都看完了,現在就來到了MobileNetV3(以下簡稱V3)。
Searching for MobileNetV3 論文地址:https://arxiv.org/pdf/1905.02244.pdf
MobileNetV3,是谷歌在2019年3月21日提出的網絡架構。首先,引入眼簾的是這篇文章的標題,“searching”一詞就把V3的論文的核心觀點展示了出來——用**神經結構搜索(NAS)**來完成V3。雖然本人沒有接觸過NAS,但是我已經聞到了金錢的味道。
“抱歉,有錢真的可以為…”
由于真的沒有接觸過NAS,所以V3就講講其他的,除NAS之外的東西吧。
先上結果:
可以看到,在同一大小的計算量下,V3在ImageNet上的結果都是最好的。
我們先來看看V3做了什么?
MobileNetV3的相關技術
- 0.網絡的架構基于NAS實現的MnasNet(效果比MobileNetV2好)
- 1.引入MobileNetV1的深度可分離卷積
- 2.引入MobileNetV2的具有線性瓶頸的倒殘差結構
- 3.引入基于squeeze and excitation結構的輕量級注意力模型(SE)
- 4.使用了一種新的激活函數h-swish(x)
- 5.網絡結構搜索中,結合兩種技術:資源受限的NAS(platform-aware NAS)與NetAdapt
- 6.修改了MobileNetV2網絡端部最后階段
第0點,關于MnasNet也是基于NAS的,也不是很了解。大家感興趣的話,可以參考曲曉峰老師的這個回答如何評價 Google 最新的模型 MnasNet? - 曲曉峰的回答 - 知乎,寫的很棒!所以我們只要認為MnasNet是一個比MobileNet精度和實時性更高的模型就行了。
第1,2點在前面的MobileNetV1和V2上有討論,在這里就不贅述了。
第3點引入SE模塊,主要為了利用結合特征通道的關系來加強網絡的學習能力。先不仔細討論,之后在【深度回顧經典網絡】系列的時候再詳細討論吧,感興趣的同學,可以看看這一篇文章。
激活函數h-swish
swish
h-swish是基于swish的改進,swish最早是在谷歌大腦2017的論文Searching for Activation functions所提出(又是Searching for!!!)。
swish論文的作者認為,Swish具備無上界有下界、平滑、非單調的特性。并且Swish在深層模型上的效果優于ReLU。僅僅使用Swish單元替換ReLU就能把MobileNet,NASNetA在 ImageNet上的top-1分類準確率提高0.9%,Inception-ResNet-v的分類準確率提高0.6%。
V3也利用swish當作為ReLU的替代時,它可以顯著提高神經網絡的精度。但是呢,作者認為這種非線性激活函數雖然提高了精度,但在嵌入式環境中,是有不少的成本的。原因就是在移動設備上計算sigmoid函數是非常明智的選擇。所以提出了h-swish。
h-swish
可以用一個近似函數來逼急這個swish,讓swish變得硬(hard)。作者選擇的是基于ReLU6,作者認為幾乎所有的軟件和硬件框架上都可以使用ReLU6的優化實現。其次,它能在特定模式下消除了由于近似sigmoid的不同實現而帶來的潛在的數值精度損失。
下圖是Sigmoid和swish的hard、soft形式:
我們可以簡單的認為,hard形式是soft形式的低精度化。作者認為swish的表現和其他非線性相比,能夠將過濾器的數量減少到16個的同時保持與使用ReLU或swish的32個過濾器相同的精度,這節省了3毫秒的時間和1000萬MAdds的計算量。
并且同時,作者認為隨著網絡的深入,應用非線性激活函數的成本會降低,能夠更好的減少參數量。作者發現swish的大多數好處都是通過在更深的層中使用它們實現的。因此,在V3的架構中,只在模型的后半部分使用h-swish(HS)。
網絡結構搜索NAS
由于不熟,就簡單寫一點吧。
主要結合兩種技術:資源受限的NAS(platform-aware NAS)與NetAdapt。
資源受限的NAS,用于在計算和參數量受限的前提下搜索網絡來優化各個塊(block),所以稱之為模塊級搜索(Block-wise Search) 。
NetAdapt,用于對各個模塊確定之后網絡層的微調每一層的卷積核數量,所以稱之為層級搜索(Layer-wise Search)。
一旦通過體系結構搜索找到模型,我們就會發現最后一些層以及一些早期層計算代價比較高昂。于是作者決定對這些架構進行一些修改,以減少這些慢層(slow layers)的延遲,同時保持準確性。這些修改顯然超出了當前搜索的范圍。
對V2最后階段的修改
作者認為,當前模型是基于V2模型中的倒殘差結構和相應的變體(如下圖)。使用1×1卷積來構建最后層,這樣可以便于拓展到更高維的特征空間。這樣做的好處是,在預測時,有更多更豐富的特征來滿足預測,但是同時也引入了額外的計算成本與延時。
所以,需要改進的地方就是要保留高維特征的前提下減小延時。首先,還是將1×1層放在到最終平均池之后。這樣的話最后一組特征現在不是7x7(下圖V2結構紅框),而是以1x1計算(下圖V3結構黃框)。
這樣的好處是,在計算和延遲方面,特征的計算幾乎是免費的。最終,重新設計完的結構如下:
在不會造成精度損失的同時,減少10ms耗時,提速15%,減小了30m的MAdd操作。
V3的block
綜合以上,V3的block結構如下所示:
與V2的block相比較:
MobileNetV3的網絡結構
MobileNetV3定義了兩個模型: MobileNetV3-Large和MobileNetV3-Small。V3-Large是針對高資源情況下的使用,相應的,V3-small就是針對低資源情況下的使用。兩者都是基于之前的簡單討論的NAS。
MobileNetV3-Large
MobileNetV3-Small
就像之前所說的:只有在更深層次使用h-swish才能得到比較大的好處。所以在上面的網絡模型中,不論大小,作者只在模型的后半部分使用h-swish。
用谷歌pixel 1/2/3來對大小V3進行測試的結果。
實驗結果
分類、檢測、分割定量結果略。
為什么MobileNet會這么快?
在寫這篇文章的時候看到了一篇文章Why MobileNet and Its Variants (e.g. ShuffleNet) Are Fast?,這也讓我有了一樣的一個問題,這篇文章主要是從結構方面進行了討論,從深度可分離卷積到組卷積的參數計算量等,因為之前的文章都有寫過,在這里就不贅述了,感興趣的同學可以翻閱下之前的文章。
在這里換一個的角度。我們直接從用時多少的角度去討論下這個問題。
下圖來自Caffe作者賈揚清的博士論文:
該圖是AlexNet網絡中不同層的GPU和CPU的時間消耗,我們可以清晰的看到,不管是在GPU還是在CPU運行,最重要的“耗時殺手”就是conv,卷積層。也就是說,想要提高網絡的運行速度,就得到提高卷積層的計算效率。
我們以MobileNetV1為主,看看MobileNet的資源分布情況:
可以看到,MobileNet的95%的計算都花費在了1×1的卷積上,那1×1卷積有什么好處嗎?
我們都知道,卷積操作就是如下圖所示的乘加運算:
在計算機操作時,需要將其存入內存當中再操作(按照“行先序”):
這樣一來,特征圖y11,y12,y21,y22的計算如下所示:
按照卷積計算,實線標注出卷積計算中的訪存過程(對應數據相乘),我們可以看到這一過程是非常散亂和混亂的。直接用卷積的計算方式是比較愚蠢的。
這時候就要用到im2col操作。
im2col
一句話來介紹im2col操作的話,就是通過犧牲空間的手段(約擴增K×K倍),將特征圖轉換成龐大的矩陣來進行卷積計算。
其實思路非常簡單:
把每一次循環所需要的數據都排列成列向量,然后逐一堆疊起來形成矩陣(按通道順序在列方向上拼接矩陣)。比如Ci×Wi×Hi大小的輸入特征圖,K×K大小的卷積核,輸出大小為Co×Wo×Ho,輸入特征圖將按需求被轉換成(K?K)×(Ci?Wo?Ho)的矩陣,卷積核將被轉換成Co×(K?K)的矩陣,
然后調用GEMM(矩陣乘矩陣)庫加速兩矩陣相乘也就完成了卷積計算。由于按照計算需求排布了數據順序,每次計算過程中總是能夠依次訪問特征圖數據,極大地提高了計算卷積的速度。 (不光有GEMM,還有FFT(快速傅氏變換))
換一種表示方法能更好地理解,圖片來自High Performance Convolutional Neural Networks for Document Processing:
這樣可以更清楚的看到卷積的定義進行卷積操作(上圖上半部分),內存訪問會非常不規律,以至于性能會非常糟糕。而Im2col()以一種內存訪問規則的方式排列數據,雖然Im2col操作增加了很多數據冗余,但使用Gemm的性能優勢超過了這個數據冗余的劣勢。
所以標準卷積運算大概就是這樣的一個過程:
那我們現在回到1×1的卷積上來,有點特殊。按照我們之前所說的,1×1的卷積的原始儲存結構和進行im2col的結構如下圖所示:
可以看到矩陣是完全相同的。標準卷積運算和1×1卷積運算對比如下圖:
也就是說,1x1卷積不需要im2col的過程,所以底層可以有更快的實現,拿起來就能直接算,大大節省了數據重排列的時間和空間。
當然,這些也不是那么絕對的,因為畢竟MobileNet速度快不快,與CONV1x1運算的優化程度密切相關。如果使用了定制化的硬件(比如用FPGA直接實現3x3的卷積運算單元),那么im2col就失去了意義而且反而增加了開銷。
回到之前的MobileNet的資源分布,95%的1×1卷積和優化的網絡結構就是MobileNet能如此快的原因了。
Reference
MobileNets: Efficient Convolutional Neural Networks for Mobile Vision Applications
MobileNetV2: Inverted Residuals and Linear Bottlenecks
Searching for MobileNetV3
Xception: Deep Learning with Depthwise Separable Convolutions
Simplifying ConvNets for Fast Learning
a-basic-introduction-to-separable-convolution
CNN模型之MobileNet
網絡解析(二):MoblieNets詳解
輕量級網絡–MobileNet論文解讀
https://mp.weixin.qq.com/s/O2Bhn66cWCN_87P52jj8hQ
http://machinethink.net/blog/mobilenet-v2/
如何評價 Google 最新的模型 MnasNet? - 曲曉峰的回答 - 知乎
Learning Semantic Image Representations at a Large Scale 賈揚清博士論文
im2col的原理和實現
在 Caffe 中如何計算卷積? - 賈揚清的回答 - 知乎
漫談卷積層
High Performance Convolutional Neural Networks for Document Processing
Why MobileNet and Its Variants (e.g. ShuffleNet) Are Fast