如何根據(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

這里我們看下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

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í)間閱讀,祝您在這里記錄、閱讀、分享愉快!
