面試官:“簡(jiǎn)述Xception中的深度可分離卷積”

極市導(dǎo)讀
本文詳細(xì)介紹了Xception網(wǎng)絡(luò)的相關(guān)結(jié)構(gòu)及特點(diǎn)。 >>加入極市CV技術(shù)交流群,走在計(jì)算機(jī)視覺(jué)的最前沿
Xception 網(wǎng)絡(luò)
在 2017 年谷歌也是在 Inception- 的基礎(chǔ)上推出 Xception,在性能上超越了原有的 Inception-V3。下面我們帶大家見(jiàn)識(shí)一下 Xception 的廬山真面目吧!
簡(jiǎn)介
在 ception 中作者主要提出了以下一些亮點(diǎn):
作者從 Inception- 的假設(shè)出發(fā),解塊通道相關(guān)性和空間相關(guān)性,進(jìn)行簡(jiǎn)化網(wǎng)絡(luò),推導(dǎo)出深度可分離卷積。 提出了一個(gè)新的 Xception 網(wǎng)絡(luò)。
相信小伙伴們看到這里一定會(huì)發(fā)出驚呼,納尼,深度可分離卷積不是在 中提出的么? 在這里需要注意的是,在 ception 中提出的深度可分離卷積和 MobileNet 中是有差異的, 具體我們會(huì)在下文中聊到閣。
Xception的進(jìn)化之路
在前面我們說(shuō)過(guò) Xception 是 Google 繼 Inception 后提出的對(duì) Inception- 的另一種改進(jìn),作 者認(rèn)為跨通道相關(guān)性和空間相關(guān)性應(yīng)充分解塊(獨(dú)立互不相關(guān)),因此最好不要將它們共同映射處理,應(yīng)分而治之。具體是怎么做呢?
1、先使用 的卷積核,將特征圖各個(gè)通道映射到一個(gè)新空間,學(xué)習(xí)通道間相關(guān)性。
2、再使用 或 卷積核,同時(shí)學(xué)習(xí)空間相關(guān)性和通道間相關(guān)性。
進(jìn)化1
在Inception- 中使用了如下圖 所示的多個(gè)這樣的模塊堆疊而成,能夠用較小的參數(shù)學(xué)習(xí)到更豐富的信息。

進(jìn)化2
在原論文中作者對(duì)于圖 1 中的模塊進(jìn)行了簡(jiǎn)化, 去除 Inception-v3 中的 Pool 后, 輸入的下一步操作就都是 卷積,如下圖 2 所示:

進(jìn)化3
更進(jìn)一步,作者對(duì)于簡(jiǎn)化后的 Inception- 模塊中的所有 卷積進(jìn)行合并,什么意思呢?就是將 Inception- 模塊重新構(gòu)造為 卷積,再進(jìn)行空間卷積 是標(biāo)準(zhǔn)的那種多通道的卷 積),相當(dāng)于把 卷積后的輸出拼接起來(lái)為一個(gè)整體,然后進(jìn)行分組卷積。如下圖 3 所示:

經(jīng)過(guò)進(jìn)化3這種操作后,自然會(huì)有以下問(wèn)題:分組數(shù)及大小會(huì)產(chǎn)生什么影響?是否有更一般的假設(shè)?空間關(guān)系映射和通道關(guān)系映射是否能夠完全解耦呢?
進(jìn)化4
基于進(jìn)化 3 中提出的問(wèn)題, 作者提出了"extreme"版本的 Inception 模塊,如下圖 4 所示。從圖4 中我們可以看出,所謂的" 版本其實(shí)就是首先使用 卷積來(lái)映射跨通道相關(guān)性,然后分別映射每個(gè)輸出通道的空間相關(guān)性,即對(duì)每個(gè)通道分別做 卷積。

在此作者也說(shuō)明了這種 Inception 模塊的"extreme"版本幾乎與深度可分離卷積相同,但是依然是存在以下區(qū)別的:
1、通常實(shí)現(xiàn)的深度可分離卷積(如 MobileNet 中) 首先執(zhí)行通道空間卷積 卷積),然后執(zhí)行 卷積,而 ception 首先執(zhí)行 卷積。
2、第一次操作后是否加 , Inception 中 2 個(gè)操作后都加入 。其中"extreme"版本的Inception 模塊為:
而普通的深度可分離卷積結(jié)構(gòu)為:
而作者認(rèn)為第一個(gè)區(qū)別不大,因?yàn)檫@些操作都是堆疊在一起的; 但第二個(gè)影響很大,他發(fā)現(xiàn)在"extreme"版本的 Inception 中 與 之間不用 收敘更快、準(zhǔn)確率更高,這個(gè)作者是做了實(shí)驗(yàn)得到的結(jié)論,后面我們會(huì)介紹。
Xception網(wǎng)絡(luò)結(jié)構(gòu)
在提出了上面新的模塊結(jié)構(gòu)后,認(rèn)識(shí)卷積神經(jīng)網(wǎng)絡(luò)的特征圖中跨通道相關(guān)性和空間相關(guān)性的映射是可以完全解塊的。因?yàn)榻Y(jié)構(gòu)是由 Inception 體系結(jié)構(gòu)得到的"extreme"版本,所以將這種新的模塊結(jié)構(gòu)命名為 Xception, 表示"Extreme Inception"。并且作者還結(jié)合了 ResNet 的殘差思想,給出了如下圖 5 所示的基于 Xception 的網(wǎng)絡(luò)結(jié)構(gòu):

實(shí)驗(yàn)評(píng)估
在訓(xùn)練驗(yàn)證階段,作者使用了 ImageNet 和 這兩個(gè)數(shù)據(jù)集做驗(yàn)證。精度和參數(shù)量對(duì)比如下圖所示,從圖中可以看到,在精度上 Xception 在 ImageNet領(lǐng)先較小,但在 上領(lǐng)先很多; 在參數(shù)量和推理速度上,Xception 參數(shù)量少于 Inception, 但速度更快。
圖6 ImageNet數(shù)據(jù)集上精度對(duì)比


如下圖所示,除此之外,作者還比較了是否使用 Residual 殘差結(jié)構(gòu)、是否在 Xception 模塊中兩個(gè)操作 卷積和 卷積)之間加入 下的訓(xùn)練收玫速度和精度。從圖中可以看出,在使 用了 Residual 殘差結(jié)構(gòu)和去掉 Xception 模塊中兩個(gè)操作之間的 激活函數(shù)下訓(xùn)練收玫的速度更快,精度更高。


總結(jié)
在 Xception 網(wǎng)絡(luò)中作者解塊通道相關(guān)性和空間相關(guān)性,提出了"extreme"版本的 Inception 模塊,結(jié)合 的殘差思想設(shè)計(jì)了新的 ception 網(wǎng)絡(luò)結(jié)構(gòu),相比于之前的 Inception-V3 獲得更高的精度和使用了更少的參數(shù)量。
這里給出 Keras 代碼實(shí)現(xiàn):
from keras.models import Modelfrom keras import layersfrom keras.layers import Dense, Input, BatchNormalization, Activationfrom keras.layers import Conv2D, SeparableConv2D, MaxPooling2D, GlobalAveragePooling2D, GlobalMaxPooling2Dfrom keras.applications.imagenet_utils import _obtain_input_shapefrom keras.utils.data_utils import get_fileWEIGHTS_PATH = 'https://github.com/fchollet/deep-learning-models/releases/download/v0.4/xception_weights_tf_dim_ordering_tf_kernels.h5'def Xception():# Determine proper input shapeinput_shape = _obtain_input_shape(None, default_size=299, min_size=71, data_format='channels_last', include_top=False)img_input = Input(shape=input_shape)# Block 1x = Conv2D(32, (3, 3), strides=(2, 2), use_bias=False)(img_input)x = BatchNormalization()(x)x = Activation('relu')(x)x = Conv2D(64, (3, 3), use_bias=False)(x)x = BatchNormalization()(x)x = Activation('relu')(x)residual = Conv2D(128, (1, 1), strides=(2, 2), padding='same', use_bias=False)(x)residual = BatchNormalization()(residual)# Block 2x = SeparableConv2D(128, (3, 3), padding='same', use_bias=False)(x)x = BatchNormalization()(x)x = Activation('relu')(x)x = SeparableConv2D(128, (3, 3), padding='same', use_bias=False)(x)x = BatchNormalization()(x)# Block 2 Poolx = MaxPooling2D((3, 3), strides=(2, 2), padding='same')(x)x = layers.add([x, residual])residual = Conv2D(256, (1, 1), strides=(2, 2), padding='same', use_bias=False)(x)residual = BatchNormalization()(residual)# Block 3x = Activation('relu')(x)x = SeparableConv2D(256, (3, 3), padding='same', use_bias=False)(x)x = BatchNormalization()(x)x = Activation('relu')(x)x = SeparableConv2D(256, (3, 3), padding='same', use_bias=False)(x)x = BatchNormalization()(x)# Block 3 Poolx = MaxPooling2D((3, 3), strides=(2, 2), padding='same')(x)x = layers.add([x, residual])residual = Conv2D(728, (1, 1), strides=(2, 2), padding='same', use_bias=False)(x)residual = BatchNormalization()(residual)# Block 4x = Activation('relu')(x)x = SeparableConv2D(728, (3, 3), padding='same', use_bias=False)(x)x = BatchNormalization()(x)x = Activation('relu')(x)x = SeparableConv2D(728, (3, 3), padding='same', use_bias=False)(x)x = BatchNormalization()(x)x = MaxPooling2D((3, 3), strides=(2, 2), padding='same')(x)x = layers.add([x, residual])# Block 5 - 12for i in range(8):residual = xx = Activation('relu')(x)x = SeparableConv2D(728, (3, 3), padding='same', use_bias=False)(x)x = BatchNormalization()(x)x = Activation('relu')(x)x = SeparableConv2D(728, (3, 3), padding='same', use_bias=False)(x)x = BatchNormalization()(x)x = Activation('relu')(x)x = SeparableConv2D(728, (3, 3), padding='same', use_bias=False)(x)x = BatchNormalization()(x)x = layers.add([x, residual])residual = Conv2D(1024, (1, 1), strides=(2, 2), padding='same', use_bias=False)(x)residual = BatchNormalization()(residual)# Block 13x = Activation('relu')(x)x = SeparableConv2D(728, (3, 3), padding='same', use_bias=False)(x)x = BatchNormalization()(x)x = Activation('relu')(x)x = SeparableConv2D(1024, (3, 3), padding='same', use_bias=False)(x)x = BatchNormalization()(x)# Block 13 Poolx = MaxPooling2D((3, 3), strides=(2, 2), padding='same')(x)x = layers.add([x, residual])# Block 14x = SeparableConv2D(1536, (3, 3), padding='same', use_bias=False)(x)x = BatchNormalization()(x)x = Activation('relu')(x)# Block 14 part 2x = SeparableConv2D(2048, (3, 3), padding='same', use_bias=False)(x)x = BatchNormalization()(x)x = Activation('relu')(x)# Fully Connected Layerx = GlobalAveragePooling2D()(x)x = Dense(1000, activation='softmax')(x)inputs = img_input# Create modelmodel = Model(inputs, x, name='xception')# Download and cache the Xception weights fileweights_path = get_file('xception_weights.h5', WEIGHTS_PATH, cache_subdir='models')# load weightsmodel.load_weights(weights_path)return model
引用
https://arxiv.org/abs/1610.02357 https://zhuanlan.zhihu.com/p/127042277 https://blog.csdn.net/u014380165/article/details/75142710 https://blog.csdn.net/lk3030/article/details/84847879 https://blog.csdn.net/qq_38807688/article/details/84590459
如果覺(jué)得有用,就請(qǐng)分享到朋友圈吧!
公眾號(hào)后臺(tái)回復(fù)“目標(biāo)檢測(cè)競(jìng)賽”獲取目標(biāo)檢測(cè)競(jìng)賽經(jīng)驗(yàn)資源~

# CV技術(shù)社群邀請(qǐng)函 #
備注:姓名-學(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)交流~

