如何根據(jù)網(wǎng)絡(luò)圖寫網(wǎng)絡(luò)代碼(Keras)

如何根據(jù)網(wǎng)絡(luò)圖寫網(wǎng)絡(luò)代碼(Keras)


有時(shí)候,出于某種目的,我們想要自己一步步搭建網(wǎng)絡(luò),不是簡單的調(diào)用現(xiàn)成的模型,

  • 封裝的太厲害,都快忘記內(nèi)部結(jié)構(gòu)了
  • 自己有一個(gè)小點(diǎn)子,想加到網(wǎng)絡(luò)結(jié)構(gòu)中,萬一效果好了呢
  • 有很多專門的場合,我們有一定的先驗(yàn)知識(shí),加到網(wǎng)絡(luò)中會(huì)更好
  • 成就感爆棚,即使是實(shí)現(xiàn)現(xiàn)有的網(wǎng)絡(luò)結(jié)構(gòu)
cmd-markdown-logo

寫在前面的話

因?yàn)橐彩莿偨佑|到深度學(xué)習(xí)這塊,并且在項(xiàng)目(傳統(tǒng)機(jī)器視覺項(xiàng)目)中也遇到了這方面的問題。項(xiàng)目主要是對相似度很高的圖像進(jìn)行分類,有點(diǎn)像細(xì)粒度方面的分類。模型采用預(yù)訓(xùn)練模型,接著進(jìn)行fine-tune,但模型一直過擬合,表現(xiàn)形式是:訓(xùn)練的loss和準(zhǔn)確率都很高,驗(yàn)證集的準(zhǔn)確率和loss卻很高,且與訓(xùn)練集的差距較大,例如訓(xùn)練精度90%以上,此時(shí)的驗(yàn)證準(zhǔn)確率也僅僅70%+。因?yàn)?,想要自己改一下網(wǎng)絡(luò),增加一些防止過擬合的手段,或者把先驗(yàn)知識(shí)加進(jìn)去。因此,研究了下如何寫網(wǎng)絡(luò)代碼,更深一層理解。

什么是層[1]

Keras中的層對象,輸入一個(gè)張量,輸出一個(gè)張量。

層對象有哪些方法
  • layer.input
  • layer.output
  • layer.input_shape
  • layer.output_shape

如果該層有多個(gè)計(jì)算節(jié)點(diǎn),使用下面的方法

  • layer.get_input_at(node_index)
  • layer.get_output_at(node_index)
  • layer.get_input_shape_at(node_index)
  • layer.get_output_shape_at(node_index)

寫經(jīng)典網(wǎng)絡(luò)代碼

VGG
vgg16

這里我們看下VGG經(jīng)典網(wǎng)絡(luò)結(jié)構(gòu)圖。[2]

優(yōu)點(diǎn)
  • 結(jié)構(gòu)簡潔,整個(gè)網(wǎng)絡(luò)都使用了同樣大小的卷積核尺寸,且核尺寸較?。?x3)。
  • 采用小卷積核比采用大的卷積核更具有優(yōu)勢,因?yàn)槎鄬臃蔷€性層可以增加網(wǎng)絡(luò)深度來保證學(xué)習(xí)更復(fù)雜的模式,而且參數(shù)更少。
缺點(diǎn)
  • 耗費(fèi)更多計(jì)算資源,更多的內(nèi)存占用(140M)。其中絕大多數(shù)的參數(shù)都是來自于第一個(gè)全連接層。

對于上面的缺點(diǎn),我們當(dāng)然可以根據(jù)自己的需求去修改,有的文章稱這些全連接層即使被去除,對于性能也沒有什么影響,也可以把全連接層替換成1X1的卷積層,這些都可以試試。

def KerasVGG():
    """
    模型采用VGG16 的結(jié)構(gòu):
        1使用固定尺寸的小卷積核 (3x3)
        2以2的冪次遞增的卷積核數(shù)量 (64, 128, 256)
        3兩層卷積搭配一層池化
        4全連接層沒有采用 VGG16 龐大的三層結(jié)構(gòu),避免運(yùn)算量過大,僅使用 128 個(gè)節(jié)點(diǎn)的單個(gè)FC
        5權(quán)重初始化采用He Normal
    :return:
    """
    inputs = Input(shape=(32, 32, 3))
    net = inputs
    # (32, 32, 3)-->(32, 32, 64)
    net = Convolution2D(filters=64, kernel_size=3, strides=1,
                        padding='same', activation='relu',
                        kernel_initializer='he_normal')(net)
    # (32, 32, 64)-->(32, 32, 64)
    net = Convolution2D(filters=64, kernel_size=3, strides=1,
                        padding='same', activation='relu',
                        kernel_initializer='he_normal')(net)
    # (32, 32, 64)-->(16, 16, 64)
    net = MaxPooling2D(pool_size=2, strides=2, padding='valid')(net)

    # (16, 16, 64)-->(16, 16, 128)
    net = Convolution2D(filters=128, kernel_size=3, strides=1,
                        padding='same', activation='relu',
                        kernel_initializer='he_normal')(net)
    # (16, 16, 64)-->(16, 16, 128)
    net = Convolution2D(filters=128, kernel_size=3, strides=1,
                        padding='same', activation='relu',
                        kernel_initializer='he_normal')(net)
    # (16, 16, 128)-->(8, 8, 128)
    net = MaxPooling2D(pool_size=2, strides=2, padding='valid')(net)

    # (8, 8, 128)-->(8, 8, 256)
    net = Convolution2D(filters=256, kernel_size=3, strides=1,
                        padding='same', activation='relu',
                        kernel_initializer='he_normal')(net)
    # (8, 8, 256)-->(8, 8, 256)
    net = Convolution2D(filters=256, kernel_size=3, strides=1,
                        padding='same', activation='relu',
                        kernel_initializer='he_normal')(net)
    # (8, 8, 256)-->(4, 4, 256)
    net = MaxPooling2D(pool_size=2, strides=2, padding='valid')(net)

    # (4, 4, 256) --> 4*4*256=4096
    net = Flatten()(net)
    # 4096 --> 128
    net = Dense(units=128, activation='relu',
                kernel_initializer='he_normal')(net)
    # Dropout
    net = Dropout(0.5)(net)
    # 128 --> 10
    net = Dense(units=config.nb_classes, activation='softmax',
                kernel_initializer='he_normal')(net)
    return inputs, net

如果您想看一下tensorflow版本的vgg16程序,請點(diǎn)這里。[3]

Inception

inception的詳細(xì)結(jié)構(gòu)參見Google的這篇論文:Inception

inception_v1
from keras.layers import Conv2D, MaxPooling2D, Input

input_img = Input(shape=(256, 256, 3))

tower_1 = Conv2D(64, (1, 1), padding='same', activation='relu')(input_img)
tower_1 = Conv2D(64, (3, 3), padding='same', activation='relu')(tower_1)

tower_2 = Conv2D(64, (1, 1), padding='same', activation='relu')(input_img)
tower_2 = Conv2D(64, (5, 5), padding='same', activation='relu')(tower_2)

tower_3 = MaxPooling2D((3, 3), strides=(1, 1), padding='same')(input_img)
tower_3 = Conv2D(64, (1, 1), padding='same', activation='relu')(tower_3)

output = keras.layers.concatenate([tower_1, tower_2, tower_3], axis=1)

這里可以看出,1X1的卷積其實(shí)在很多地方都有用,至于究竟為什么會(huì)這樣,以及這些網(wǎng)絡(luò)的背后深層原因,還需要花費(fèi)更多的時(shí)間去理解,去悟,后續(xù)再見。


再一次感謝您花費(fèi)時(shí)間閱讀,祝您在這里記錄、閱讀、分享愉快!


  1. https://keras-cn.readthedocs.io/en/latest/layers/about_layer/ ?

  2. https://www.cs.toronto.edu/~frossard/post/vgg16/ ?

  3. https://www.cs.toronto.edu/~frossard/vgg16/vgg16.py ?

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容