GoogLeNet Structure

2014年的Imagenet不太尋常孝情,GoogLeNet(我們這兒先來討論GoogLeNet Incepetion V1)與VGG一道成為當(dāng)年的冠軍更卒。當(dāng)然了,他們都做到了more deeper(Alexnet只有8層)吨娜,但是也有一些不同的地方问拘,VGG貌似更為直接的繼承了AlexNet的框架,但是GoogLeNet卻做了更加大膽的嘗試压鉴,不僅僅做到了more deeper崖咨,而且more wider,雖然層數(shù)也只有22層油吭,但是相對(duì)于AlexNet與VGG而言击蹲,在大小上還是小了很多署拟。下面我們來看看它是怎么go deeper and wider but more smaller的。
說點(diǎn)題外話歌豺,雖然GoogLeNet取名為“GoogLeNet”而非“GoogleNet”推穷,是向LeNet致敬,但不得不承認(rèn)的一點(diǎn)就是網(wǎng)絡(luò)結(jié)構(gòu)里很難看到LeNet的影子类咧。:)


我們大致清楚馒铃,增加網(wǎng)絡(luò)的深度和寬度是直接提升網(wǎng)絡(luò)性能的兩個(gè)方法,而文章中也提出:獲得高質(zhì)量模型最保險(xiǎn)的做法就是增加模型的深度(層數(shù))或者是其寬度(層核或者神經(jīng)元數(shù))轮听。但是不管哪一種方法帶來的都是參數(shù)的增加骗露,帶來的后果就是計(jì)算量的增加,而且復(fù)雜的模型也將容易過擬合血巍、難以優(yōu)化萧锉。
我們先來將GoogLeNet的結(jié)構(gòu)可視化一把:

GoogLeNet Structure

不好意思這個(gè)有點(diǎn)長,但是我也沒辦法笆龉选(誰叫它本身就張那樣)柿隙,不過請(qǐng)大家注意了,整個(gè)網(wǎng)絡(luò)是由很多個(gè)紅框框這樣的就夠重復(fù)組合而成的鲫凶,現(xiàn)在再回去看一波禀崖,是不是對(duì)這個(gè)結(jié)構(gòu)了就一目了然了O(∩_∩)O。
我們把紅色方框的部分抽離出來螟炫,另外波附,再給它起個(gè)名字(當(dāng)然只有Szegedy才有資格咯):Incepetion

Incepetion Structure

可以看到Inception里有四個(gè)并行的線路。

  1. 單個(gè) 1×1卷積昼钻。
  2. 1×1 卷積接上 3×3 卷積掸屡。通常前者的通道數(shù)少于輸入通道,這樣減少后者的計(jì)算量然评。后者加上了padding=1使得輸出的長寬的輸入一致(看不懂仅财?沒關(guān)系的,我在后面說明一下讓你秒懂)
  3. 同2碗淌,但換成了 5×5 卷積
  4. 和1類似盏求,但卷積前用了最大池化層

最后將這四個(gè)并行線路的結(jié)果在通道這個(gè)維度上Concat(就是矩陣拼接)在一起。

大家可能就會(huì)有疑問了亿眠,為何要在input出來的時(shí)候加個(gè)1×1卷積碎罚,1×1的kennel去卷積不是啥事兒都沒做嘛?不急纳像,聽我慢慢分析魂莫。我們先來做個(gè)假設(shè),假設(shè)這樣干:

Sample Incepetion Structure

就是先把那個(gè)1×1卷積給他抹掉爹耗,那么就是直接使用1×1耙考、3×3以及5×5的卷積核對(duì)input進(jìn)行操作,但是這樣仍然會(huì)帶來巨大的計(jì)算量(還不明白潭兽?接著看)倦始。我們最開始提到過,GoogLeNet取名為“GoogLeNet”而非“GoogleNet”山卦,是向LeNet致敬鞋邑,但不得不承認(rèn)的一點(diǎn)就是網(wǎng)絡(luò)結(jié)構(gòu)里很難看到LeNet的影子,其實(shí)它是Draw lessons from NIN账蓉,具體就是采用1×1卷積核來進(jìn)行降維枚碗,這樣,1x1的卷積核起到了降低feature map厚度铸本、減少計(jì)算量的作用肮雨。
大家可能還是不太明白吧,沒關(guān)系箱玷,咋來舉個(gè)例子:
我們以3×3這個(gè) path 為例怨规,假設(shè) input(也就是上層的 output)為128×100×100(channel×height×width,batch size略去锡足,沒寫波丰,事實(shí)上,batch size是不影響計(jì)算的):

  • 不使用1×1的卷積舶得,那么經(jīng)過 kennel = 3×3掰烟,channel = 256,stride=1沐批,pad=1 的卷積之后纫骑,其 output:256×100×100,那么其參數(shù)數(shù)量128×256×3×3
  • 若是先將 output 經(jīng)過 kennel = 1×1珠插,channel = 64惧磺,的卷積經(jīng)之后,再將 1×1 Conv 的 output 拋進(jìn) 3×3 卷積層捻撑,還是設(shè)3×3 Conv 的kennel = 3×3磨隘,channel = 256,stride=1顾患,pad=1番捂。但參數(shù)數(shù)量將減少為128×64×1×1+64×256×3×3,參數(shù)將近減少了一半江解,而你把這個(gè)放到5×5 的那條path上面去推算一下设预,可能會(huì)更明顯!你說膩害不膩害

現(xiàn)在大家明白了這個(gè)1×1的卷積層是拿來干啥的了吧
大家都 get 到這個(gè) point 以后犁河,我們現(xiàn)在再來對(duì)這個(gè) “Incepetion模塊” 進(jìn)行一波總結(jié):

  1. 采用了1×1鳖枕、3×3以及5×5的不同的kennel魄梯,那么神經(jīng)元將看到不同尺度的信息,最后的 concat 也就將不同尺度的features加以結(jié)合了宾符;
  2. 1×1 卷積接上 3×3 卷積酿秸。將前者的通道數(shù)設(shè)置為少于輸入通道,這樣減少后者的計(jì)算量魏烫。而后者加上了padding=1使得輸出的長寬與輸入一致辣苏,5×5 的那個(gè)是一樣的道理,padding=2 而已哄褒。輸出的長寬與輸入一致確保最后能 concat 在一起
  3. 文章說很多地方都表明pooling挺有效稀蟋,所以Inception里面也嵌入了。至于pooling嘛呐赡,原文解釋得不是很詳細(xì)退客,只說了效果好,所以放上去了 罚舱,大家有什么看法也可以留言交流
  4. 最后井辜,網(wǎng)絡(luò)使用的是average pooling,而不是全連接管闷,結(jié)果當(dāng)然要好不然人家也不這么干粥脚,而在最后它還是使用linear線性層,這么干是為了方便fine-tuning模型包个。

這樣說大家就不會(huì)打我臉了吧(●ˇ?ˇ●)
我們?cè)賮砘貧w原點(diǎn)刷允,討論整個(gè)網(wǎng)絡(luò)的思路go more deeper,go more wider:

  1. 深度碧囊,層數(shù)更深树灶,文章采用了22層,為了避免上述提到的梯度消失問題(在反向傳播更新參數(shù)時(shí)糯而,越靠近輸入梯度越刑焱ā),GoogLeNet 巧妙的在不同深度處增加了兩個(gè)loss來保證梯度回傳消失的現(xiàn)象熄驼。
  2. 寬度像寒,增加了多種核1x1,3x3瓜贾,5x5诺祸,還有直接max pooling的。
    但是如果簡單的將這些應(yīng)用到feature map上的話祭芦,concat起來的feature map厚度將會(huì)很大筷笨,所以在googlenet中為了避免這一現(xiàn)象提出的inception具有如下結(jié)構(gòu),在3x3前,5x5前胃夏,max pooling后分別加上了1x1的卷積核起到了降低feature map厚度的作用
    以上我們其實(shí)都是介紹的是more wider轴或,那么這兒再來說說如何解決more deeper的一些問題权烧,我們看到GoogLeNet一共堆砌了多個(gè)Incepetion模塊使得網(wǎng)絡(luò)加深挣输,因此在BP(Back Propagation )的時(shí)候梯度彌散的情況是存在的,而GoogLeNet里面的softmax0、softmax1就是來解決這個(gè)問題的具體就是在訓(xùn)練的時(shí)候悼瘾,他們的損失誤差乘以一個(gè)權(quán)值(GoogLeNet里設(shè)置為0.3)加到整體損失中。在應(yīng)用的時(shí)候审胸,這兩個(gè)輔助分類器會(huì)被丟掉亥宿。GoogLeNet的實(shí)驗(yàn)表明,只需要一個(gè)輔助分類器就可以達(dá)到同樣的效果(提升0.5%)砂沛。

補(bǔ)充一下烫扼,以后我還會(huì)接著介紹它的其他幾個(gè)版本

下面我們就來看看大家最關(guān)心的實(shí)踐吧(Mxnet+Gluon)O(∩_∩)O

首先我們定義Inception模塊

from mxnet.gluon import nn
from mxnet import nd

class Inception(nn.Block):
    def __init__(self, n1_1, n2_1, n2_3, n3_1, n3_5, n4_1, **kwargs):
    # n*_* : the output of every path,  for exzample
    # n2_1 is the output of Conv 1*1 of path 2 & n2_3 is the output of Conv 3*3 of path 2
        super(Inception, self).__init__(**kwargs)
        # path 1
        self.p1_conv_1 = nn.Conv2D(n1_1, kernel_size=1,
                                   activation='relu')
        # path 2
        self.p2_conv_1 = nn.Conv2D(n2_1, kernel_size=1,
                                   activation='relu')
        self.p2_conv_3 = nn.Conv2D(n2_3, kernel_size=3, padding=1,
                                   activation='relu')
        # path 3
        self.p3_conv_1 = nn.Conv2D(n3_1, kernel_size=1,
                                   activation='relu')
        self.p3_conv_5 = nn.Conv2D(n3_5, kernel_size=5, padding=2,
                                   activation='relu')
        # path 4
        self.p4_pool_3 = nn.MaxPool2D(pool_size=3, padding=1,
                                      strides=1)
        self.p4_conv_1 = nn.Conv2D(n4_1, kernel_size=1,
                                   activation='relu')

    # define the forward propagation
    def forward(self, x):
        p1 = self.p1_conv_1(x)
        p2 = self.p2_conv_3(self.p2_conv_1(x))
        p3 = self.p3_conv_5(self.p3_conv_1(x))
        p4 = self.p4_conv_1(self.p4_pool_3(x))
        # concatenate the output of four paths together at the first dimension (channel)
        return nd.concat(p1, p2, p3, p4, dim=1)

接著,我們就可以用這個(gè)Inception模塊去構(gòu)造GoogLeNet了

class GoogLeNet(nn.Block):
    def __init__(self, num_classes, verbose=False, **kwargs):
        super(GoogLeNet, self).__init__(**kwargs)
        self.verbose = verbose
        # add name_scope on the outer most Sequential
        with self.name_scope():
            # block 1
            b1 = nn.Sequential()
            b1.add(
                nn.Conv2D(64, kernel_size=7, strides=2,
                          padding=3, activation='relu'),
                nn.MaxPool2D(pool_size=3, strides=2)
            )
            # block 2
            b2 = nn.Sequential()
            b2.add(
                nn.Conv2D(64, kernel_size=1),
                nn.Conv2D(192, kernel_size=3, padding=1),
                nn.MaxPool2D(pool_size=3, strides=2)
            )

            # block 3
            b3 = nn.Sequential()
            b3.add(
                Inception(64, 96, 128, 16,32, 32),
                Inception(128, 128, 192, 32, 96, 64),
                nn.MaxPool2D(pool_size=3, strides=2)
            )

            # block 4
            b4 = nn.Sequential()
            b4.add(
                Inception(192, 96, 208, 16, 48, 64),
                Inception(160, 112, 224, 24, 64, 64),
                Inception(128, 128, 256, 24, 64, 64),
                Inception(112, 144, 288, 32, 64, 64),
                Inception(256, 160, 320, 32, 128, 128),
                nn.MaxPool2D(pool_size=3, strides=2)
            )

            # block 5
            b5 = nn.Sequential()
            b5.add(
                Inception(256, 160, 320, 32, 128, 128),
                Inception(384, 192, 384, 48, 128, 128),
                nn.AvgPool2D(pool_size=2)
            )
            # block 6
            b6 = nn.Sequential()
            b6.add(
                nn.Flatten(),
                nn.Dense(num_classes)
            )
            # chain blocks together
            self.net = nn.Sequential()
            self.net.add(b1, b2, b3, b4, b5, b6)
    
    # define the forward propagation, 
    def forward(self, x):
        out = x
        for i, b in enumerate(self.net):
            out = b(out)
            if self.verbose:
                print('Block %d output: %s'%(i+1, out.shape))
        return out

這就是整個(gè)GoogLeNet的Structure了

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末碍庵,一起剝皮案震驚了整個(gè)濱河市映企,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌静浴,老刑警劉巖堰氓,帶你破解...
    沈念sama閱讀 216,997評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異苹享,居然都是意外死亡双絮,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,603評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門得问,熙熙樓的掌柜王于貴愁眉苦臉地迎上來囤攀,“玉大人,你說我怎么就攤上這事宫纬》倌樱” “怎么了?”我有些...
    開封第一講書人閱讀 163,359評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵漓骚,是天一觀的道長蝌衔。 經(jīng)常有香客問我,道長认境,這世上最難降的妖魔是什么胚委? 我笑而不...
    開封第一講書人閱讀 58,309評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮叉信,結(jié)果婚禮上亩冬,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好硅急,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,346評(píng)論 6 390
  • 文/花漫 我一把揭開白布覆享。 她就那樣靜靜地躺著,像睡著了一般营袜。 火紅的嫁衣襯著肌膚如雪撒顿。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,258評(píng)論 1 300
  • 那天荚板,我揣著相機(jī)與錄音凤壁,去河邊找鬼。 笑死跪另,一個(gè)胖子當(dāng)著我的面吹牛拧抖,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播免绿,決...
    沈念sama閱讀 40,122評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼唧席,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了嘲驾?” 一聲冷哼從身側(cè)響起淌哟,我...
    開封第一講書人閱讀 38,970評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎辽故,沒想到半個(gè)月后徒仓,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,403評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡榕暇,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,596評(píng)論 3 334
  • 正文 我和宋清朗相戀三年蓬衡,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片彤枢。...
    茶點(diǎn)故事閱讀 39,769評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡狰晚,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出缴啡,到底是詐尸還是另有隱情壁晒,我是刑警寧澤,帶...
    沈念sama閱讀 35,464評(píng)論 5 344
  • 正文 年R本政府宣布业栅,位于F島的核電站秒咐,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏碘裕。R本人自食惡果不足惜携取,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,075評(píng)論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望帮孔。 院中可真熱鬧雷滋,春花似錦不撑、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,705評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至澳泵,卻和暖如春实愚,著一層夾襖步出監(jiān)牢的瞬間兔辅,已是汗流浹背腊敲。 一陣腳步聲響...
    開封第一講書人閱讀 32,848評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留幢妄,地道東北人兔仰。 一個(gè)月前我還...
    沈念sama閱讀 47,831評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像蕉鸳,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子忍法,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,678評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容