介紹
Inception 又叫Googlenet是Google于2014年為參加ILSVRC大賽而提出的CNN分類模型。它發(fā)表于2014年的CVPR上面。在深度學(xué)習(xí)領(lǐng)域Google出品幾乎必為精品,Inception也不例外。
它乍看上去像是蠻復(fù)雜的,但細(xì)看其結(jié)構(gòu)就會(huì)發(fā)現(xiàn)它其實(shí)就是用一個(gè)個(gè)Inception module給堆起來的。它的設(shè)計(jì)充滿了科學(xué)理論與工程實(shí)踐的結(jié)合,是一個(gè)典型的data scientist與軟件工程師結(jié)合搞出來的東東。
在此之前經(jīng)典的CNN模型像LeNet/Alexnet/VGG等無不是一個(gè)模子即使用Conv/Pool/Normalization/Activation等層來不斷累積而成。模型對(duì)數(shù)據(jù)集概率分布的表達(dá)能力則往往通過單純?cè)黾幽P偷纳疃龋▽訑?shù))或?qū)挾龋▽拥腸hannels數(shù))來提高(當(dāng)然這也亦是當(dāng)下深度學(xué)習(xí)領(lǐng)域的共識(shí))。但這樣進(jìn)行網(wǎng)絡(luò)設(shè)計(jì)一般會(huì)等來巨量的計(jì)算開銷,因?yàn)槊恳粚觕hannels數(shù)目的增加都會(huì)隨著層深而指數(shù)級(jí)增加,這大大地限制了模型的實(shí)際應(yīng)用。
GoogleNet團(tuán)隊(duì)在考慮網(wǎng)絡(luò)設(shè)計(jì)時(shí)不只注重增加模型的分類精度,同時(shí)也考慮了其可能的計(jì)算與內(nèi)存使用開銷。他們借鑒了諸多前人的觀點(diǎn)與經(jīng)驗(yàn)(尤其是Network in Network中使用1x1 conv及AvgPool的idea),想通過一種spared layer architecture來實(shí)現(xiàn)較優(yōu)的多維度特征表達(dá),然后通過對(duì)這種結(jié)構(gòu)進(jìn)行疊加,中間不時(shí)再插入一些MaxPool層以減少參數(shù)數(shù)目(從而節(jié)省內(nèi)存與計(jì)算開銷),最終就行成了Inception v1分類模型。它作為2014年ILSVRC圖像分類大賽中的最優(yōu)選手,取得了非常大的成功。后來GoogleNet團(tuán)隊(duì)再接再厲接連提出了融入更新思想,同時(shí)分類精度也更高的Inception v2/Inception v3/Inception v4及Inception-Resnet等模型,從而將Inception的思想推至了當(dāng)下的巔峰。此是后話,欲知Inception系列模型的淵源還是須從這個(gè)最早的Inception v1開始。
Inception模塊設(shè)計(jì)
傳統(tǒng)的CNN模型設(shè)計(jì),其能力增加往往通過增加層數(shù)及增寬層的通道數(shù)來實(shí)現(xiàn)。但這會(huì)帶來兩個(gè)問題,首先這兩種設(shè)計(jì)思路都是在高密度計(jì)算的單元上(如FC層/Conv層)實(shí)現(xiàn)的,它會(huì)帶來大量的訓(xùn)練參數(shù)增加,而過多的參數(shù)往往意味著容易出現(xiàn)過擬合;其次單純?cè)用芗?jì)算單元的層數(shù)或每層寬度都會(huì)招至后須擴(kuò)展的指數(shù)級(jí)的計(jì)算量增加。
顯然通過使用一種稀疏的層次結(jié)構(gòu)而非使用像FC/Conv這樣的全級(jí)聯(lián)式的結(jié)構(gòu)有助于計(jì)算開銷的降低。而且一旦這種稀疏的結(jié)構(gòu)設(shè)計(jì)良好可以有效地?cái)U(kuò)大表達(dá)特征的范圍,從而更有效地對(duì)圖片信息進(jìn)行表達(dá)??蛇^于稀疏的結(jié)構(gòu)計(jì)算一般都不大高效(當(dāng)下用于CPU/GPU上的一些高效加速庫(kù)多是在密集計(jì)算上進(jìn)行優(yōu)化的),同時(shí)也會(huì)帶來較多的cache miss及內(nèi)存地址非連續(xù)搜索的overhead。最終GoogleNet團(tuán)隊(duì)選擇了中間路線即使用由密集計(jì)算子結(jié)構(gòu)組合而成的稀疏模塊來用于特征提取及表達(dá),這就是用于構(gòu)建Inception v1的Inception module如下圖中a所示。
其中1x1/3x3/5x5這三種Conv kernels的選擇決定是基于方便(因?yàn)檫@幾種kernels用的多啊,而且比較容易對(duì)齊,padding)來定的(汗)。
圖a的這個(gè)基本module顯然在計(jì)算開銷上隱藏著重大問題即它的輸出將每個(gè)不同尺度的conv的輸出級(jí)連起來用于下一個(gè)module的輸入。這勢(shì)必會(huì)招至計(jì)算量的指數(shù)級(jí)增加。因此作者借鑒Network in Network中的idea,在每個(gè)子conv層里使用了1x1的conv來作上一層的輸入feature maps的channels數(shù)縮減、歸總。如此每個(gè)Inception module里的計(jì)算都由各自的1x1 conv來隔離,從而不會(huì)像傳統(tǒng)CNN深度模型那樣隨著深度增加其計(jì)算量也指數(shù)級(jí)增加。這就是最終用于構(gòu)建Inception 網(wǎng)絡(luò)的基礎(chǔ)模塊inception即圖b。
GoogleNet
上表即為GoogleNet的網(wǎng)絡(luò)結(jié)構(gòu)設(shè)計(jì)概況。可以看出并非整個(gè)網(wǎng)絡(luò)都是由Inception module來組成。它的前面幾層采用了類似于經(jīng)典網(wǎng)絡(luò)的那種單尺度Conv/Pool/ReLu的設(shè)計(jì),這主要是出于用于進(jìn)行模型計(jì)算的系統(tǒng)架構(gòu)的實(shí)際考慮。
作者表明我們可以靈活地根據(jù)自己所有的硬件/軟件/系統(tǒng)等情況來選擇Inception網(wǎng)絡(luò)中各模塊的使用(modules數(shù)目及其上的conv的channels數(shù))。而上表所列的這個(gè)有著22個(gè)參數(shù)層的GoogleNet只是在作者他們實(shí)驗(yàn)所用的機(jī)器上得到的較優(yōu)網(wǎng)絡(luò)。因此我們不必過于拘泥于它的具體實(shí)現(xiàn)細(xì)節(jié),只需了解它的本質(zhì)設(shè)計(jì)思想即可。
模型的最后會(huì)選通過一個(gè)AvgPool層來處理最終的feature maps,然后再由FC層匯總生成1000個(gè)輸出,進(jìn)而由Softmax來得到1000類的概率分布。隨著CNN模型的加深,它最終表達(dá)的特征也愈加地抽象,只使用最后層次的特征可能會(huì)招至對(duì)小尺度目標(biāo)的忽略,因此作者分別在中間及較靠后層的地方插入了兩個(gè)獨(dú)立的分類層以在訓(xùn)練時(shí)協(xié)同發(fā)揮影響。下圖即為最終的GoogleNet模型。
模型訓(xùn)練
這算是當(dāng)時(shí)最為復(fù)雜的模型了,多達(dá)22層。它的訓(xùn)練難度顯然也是空前的。作者使用他們內(nèi)部的DistBelief分布式系統(tǒng)對(duì)模型進(jìn)行訓(xùn)練,中間使用了模型并行與數(shù)據(jù)并行兩種多節(jié)點(diǎn)并行方式(這個(gè)難度其實(shí)還是蠻高的,玩過多節(jié)點(diǎn)訓(xùn)練的人都懂?。A硗馑麄冞€使用了Async sgd的方式進(jìn)行模型參數(shù)更新(這使得模型的訓(xùn)練難度更是增加了,沒辦法估計(jì)他們當(dāng)時(shí)也是覺著訓(xùn)練時(shí)間實(shí)在太久了,所以才會(huì)選擇使用Async sgd這種加速收斂的方式吧)。
此外作者使用了集成多個(gè)模型(6個(gè)結(jié)構(gòu)相同,1個(gè)略不同;相用相同的初始化,只是不同的shuffle過的數(shù)據(jù)集)來提高分類準(zhǔn)確率的做法。同時(shí)也使用了像resize/不同scales/鏡像及color distortation等多種數(shù)據(jù)增強(qiáng)的方式。
實(shí)驗(yàn)結(jié)果
下表中即為GoogleNet網(wǎng)絡(luò)與其它模型的結(jié)果對(duì)比。
代碼分析
當(dāng)下大多數(shù)的經(jīng)典模型都已經(jīng)在Intel caffe里面有了良好實(shí)現(xiàn)。我們甚至不需要GPU,單單用自己家datacenter里面的CPUs也能玩轉(zhuǎn)下模型訓(xùn)練及推理。
下面為data layer層,與VGG等的并無差別。
layer {
name: "data"
type: "Data"
top: "data"
top: "label"
include {
phase: TRAIN
}
transform_param {
mirror: true
crop_size: 224
mean_value: 104
mean_value: 117
mean_value: 123
}
data_param {
source: "examples/imagenet/ilsvrc12_train_lmdb"
batch_size: 32
backend: LMDB
}
}
以下數(shù)層則為網(wǎng)絡(luò)中inception_3a 模塊的組成情況。
layer {
name: "inception_3a/1x1"
type: "Convolution"
bottom: "pool2/3x3_s2"
top: "inception_3a/1x1"
param {
lr_mult: 1
decay_mult: 1
}
param {
lr_mult: 2
decay_mult: 0
}
convolution_param {
num_output: 64
kernel_size: 1
weight_filler {
type: "xavier"
}
bias_filler {
type: "constant"
value: 0.2
}
}
}
layer {
name: "inception_3a/relu_1x1"
type: "ReLU"
bottom: "inception_3a/1x1"
top: "inception_3a/1x1"
}
layer {
name: "inception_3a/3x3_reduce"
type: "Convolution"
bottom: "pool2/3x3_s2"
top: "inception_3a/3x3_reduce"
param {
lr_mult: 1
decay_mult: 1
}
param {
lr_mult: 2
decay_mult: 0
}
convolution_param {
num_output: 96
kernel_size: 1
weight_filler {
type: "xavier"
}
bias_filler {
type: "constant"
value: 0.2
}
}
}
layer {
name: "inception_3a/relu_3x3_reduce"
type: "ReLU"
bottom: "inception_3a/3x3_reduce"
top: "inception_3a/3x3_reduce"
}
layer {
name: "inception_3a/3x3"
type: "Convolution"
bottom: "inception_3a/3x3_reduce"
top: "inception_3a/3x3"
param {
lr_mult: 1
decay_mult: 1
}
param {
lr_mult: 2
decay_mult: 0
}
convolution_param {
num_output: 128
pad: 1
kernel_size: 3
weight_filler {
type: "xavier"
}
bias_filler {
type: "constant"
value: 0.2
}
}
}
layer {
name: "inception_3a/relu_3x3"
type: "ReLU"
bottom: "inception_3a/3x3"
top: "inception_3a/3x3"
}
layer {
name: "inception_3a/5x5_reduce"
type: "Convolution"
bottom: "pool2/3x3_s2"
top: "inception_3a/5x5_reduce"
param {
lr_mult: 1
decay_mult: 1
}
param {
lr_mult: 2
decay_mult: 0
}
convolution_param {
num_output: 16
kernel_size: 1
weight_filler {
type: "xavier"
}
bias_filler {
type: "constant"
value: 0.2
}
}
}
layer {
name: "inception_3a/relu_5x5_reduce"
type: "ReLU"
bottom: "inception_3a/5x5_reduce"
top: "inception_3a/5x5_reduce"
}
layer {
name: "inception_3a/5x5"
type: "Convolution"
bottom: "inception_3a/5x5_reduce"
top: "inception_3a/5x5"
param {
lr_mult: 1
decay_mult: 1
}
param {
lr_mult: 2
decay_mult: 0
}
convolution_param {
num_output: 32
pad: 2
kernel_size: 5
weight_filler {
type: "xavier"
}
bias_filler {
type: "constant"
value: 0.2
}
}
}
layer {
name: "inception_3a/relu_5x5"
type: "ReLU"
bottom: "inception_3a/5x5"
top: "inception_3a/5x5"
}
layer {
name: "inception_3a/pool"
type: "Pooling"
bottom: "pool2/3x3_s2"
top: "inception_3a/pool"
pooling_param {
pool: MAX
kernel_size: 3
stride: 1
pad: 1
}
}
layer {
name: "inception_3a/pool_proj"
type: "Convolution"
bottom: "inception_3a/pool"
top: "inception_3a/pool_proj"
param {
lr_mult: 1
decay_mult: 1
}
param {
lr_mult: 2
decay_mult: 0
}
convolution_param {
num_output: 32
kernel_size: 1
weight_filler {
type: "xavier"
}
bias_filler {
type: "constant"
value: 0.2
}
}
}
layer {
name: "inception_3a/relu_pool_proj"
type: "ReLU"
bottom: "inception_3a/pool_proj"
top: "inception_3a/pool_proj"
}
layer {
name: "inception_3a/output"
type: "Concat"
bottom: "inception_3a/1x1"
bottom: "inception_3a/3x3"
bottom: "inception_3a/5x5"
bottom: "inception_3a/pool_proj"
top: "inception_3a/output"
}
最后則是其AvgPool/DropOut/FC的使用。及最終所生成的loss與accuracy top-1/top-5實(shí)現(xiàn)。
layer {
name: "pool5/7x7_s1"
type: "Pooling"
bottom: "inception_5b/output"
top: "pool5/7x7_s1"
pooling_param {
pool: AVE
kernel_size: 7
stride: 1
}
}
layer {
name: "pool5/drop_7x7_s1"
type: "Dropout"
bottom: "pool5/7x7_s1"
top: "pool5/7x7_s1"
dropout_param {
dropout_ratio: 0.4
}
}
layer {
name: "loss3/classifier"
type: "InnerProduct"
bottom: "pool5/7x7_s1"
top: "loss3/classifier"
param {
lr_mult: 1
decay_mult: 1
}
param {
lr_mult: 2
decay_mult: 0
}
inner_product_param {
num_output: 1000
weight_filler {
type: "xavier"
}
bias_filler {
type: "constant"
value: 0
}
}
}
layer {
name: "loss3/loss3"
type: "SoftmaxWithLoss"
bottom: "loss3/classifier"
bottom: "label"
top: "loss3/loss3"
loss_weight: 1
}
layer {
name: "loss3/top-1"
type: "Accuracy"
bottom: "loss3/classifier"
bottom: "label"
top: "loss3/top-1"
include {
phase: TEST
}
}
layer {
name: "loss3/top-5"
type: "Accuracy"
bottom: "loss3/classifier"
bottom: "label"
top: "loss3/top-5"
include {
phase: TEST
}
accuracy_param {
top_k: 5
}
}
參考文獻(xiàn)
- Going deeper with convolutions, Christian-Szegedy, 2014
- https://github.com/intel/caffe