VGGNet详述
簡(jiǎn)介
縱觀如今DeepLearning的研究領(lǐng)域,主要的研究領(lǐng)域還是CV和NLP及其衍生領(lǐng)域。CV的常見神經(jīng)網(wǎng)絡(luò)中,VGGNet在卷積神經(jīng)網(wǎng)絡(luò)的發(fā)展過程有著舉足輕重的作用,它作為著LeNet與Resnet的承接者,直到今天類VGG結(jié)構(gòu)仍在圖像領(lǐng)域發(fā)揮著巨大的作用。由于最近的課題設(shè)計(jì)到VGGNet和Resnet的研究,在本項(xiàng)目著重實(shí)現(xiàn)每一個(gè)版本的VGGNet兼以近年的優(yōu)化方式優(yōu)化VGGNet。
-
論文標(biāo)題
Very deep convolutional networks for large-scale image recognition
-
論文地址
https://arxiv.org/abs/1409.1556
-
論文源碼
https://github.com/pytorch/vision/blob/master/torchvision/models/vgg.py(PyTorch實(shí)現(xiàn))
網(wǎng)絡(luò)說明
設(shè)計(jì)背景
VGGNet的基本模型主要由牛津大學(xué)的幾何視覺組(Visual Geometry Group)于2014年提出,這也是網(wǎng)絡(luò)名稱的由來,其獲得了2014年ILSVRC競(jìng)賽的分類任務(wù)的第二名和定位任務(wù)的第一名,其最偉大之處在于證明使用3*3的小卷積核通過多層堆疊可以有效提高模型性能及泛化能力,這也是后面較長(zhǎng)時(shí)間CNN傾向于小卷積核的原因之一。
結(jié)構(gòu)說明
如圖所示,共有6種網(wǎng)絡(luò)配置,其實(shí)按照層數(shù)來說只有11層、13層、16層、19層四種,主要區(qū)別在于11層網(wǎng)絡(luò)嘗試了使用Local Response Normalisation(LRN),結(jié)果并沒有提高網(wǎng)絡(luò)性能,另一個(gè)區(qū)別就是16層(這就是著名的VGG16)結(jié)構(gòu)在最后三個(gè)block使用不同的卷積核大小。網(wǎng)絡(luò)上可以找到很多概念結(jié)構(gòu)圖,上面列舉了一個(gè)很經(jīng)典的。
主要貢獻(xiàn)
使用3*3的小卷積核堆疊。
為什么使用3*3的小卷積核?這主要基于兩個(gè)考慮,不過解釋之前必須明確一個(gè)概念,兩個(gè)3*3卷積核可以獲得一個(gè)5*5的卷積核視野,三個(gè)3*3的卷積核堆疊可以獲得7*7的感受野。(注意,之間不能有池化層)
- 第一,三次卷積會(huì)進(jìn)行三次非線性變換。這種非線性變換會(huì)有效提高不同信息的判別能力(即對(duì)差異的識(shí)別能力)。
- 第二,利用三個(gè)3*3代替一個(gè)7*7可以減少參數(shù)數(shù)量。(過多的參數(shù)是神經(jīng)網(wǎng)絡(luò)的通有的問題)假設(shè)對(duì)于3通道,三個(gè)3*3卷積核的參數(shù)量為3×(32C2)=27C23\times (3^2C^2)=27C^23×(32C2)=27C2,而一個(gè)7*7卷積核參數(shù)量為72C2=49C27^2C^2=49C^272C2=49C2。
真正提高了網(wǎng)絡(luò)的深度。
- 更深的模型的好處就是可以進(jìn)行更多的非線性映射次數(shù),從而提高網(wǎng)絡(luò)的信息判別能力。這樣做的前提是參數(shù)量不會(huì)增加太多,這是基于小卷積核做到的。
- 使用1*1小卷積核也是為了增加非線性變換次數(shù)。
代碼實(shí)現(xiàn)
由于代碼過多,只列舉VGG16和VGG19的實(shí)現(xiàn)代碼,其余見文末Github。
def VGG16D(input_shape=(224, 224, 3), n_classes=1000):"""實(shí)現(xiàn)VGG16D的網(wǎng)絡(luò)結(jié)構(gòu)(著名的VGG16)沒有使用Dropout和BN:param input_shape::param n_classes::return:"""# input layerinput_layer = Input(shape=input_shape)# block1x = Conv2D(filters=64, kernel_size=(3, 3), strides=(1, 1), padding='same', activation='relu')(input_layer)x = Conv2D(64, (3, 3), strides=1, padding='same', activation='relu')(x)x = MaxPooling2D(2, 2, padding='same')(x)# block2x = Conv2D(128, (3, 3), strides=1, padding='same', activation='relu')(x)x = Conv2D(128, (3, 3), strides=1, padding='same', activation='relu')(x)x = MaxPooling2D(2, 2, padding='same')(x)# block3x = Conv2D(256, (3, 3), strides=1, padding='same', activation='relu')(x)x = Conv2D(256, (3, 3), strides=1, padding='same', activation='relu')(x)x = Conv2D(256, (3, 3), strides=1, padding='same', activation='relu')(x)x = MaxPooling2D(2, 2, padding='same')(x)# block4x = Conv2D(512, (3, 3), strides=1, padding='same', activation='relu')(x)x = Conv2D(512, (3, 3), strides=1, padding='same', activation='relu')(x)x = Conv2D(512, (3, 3), strides=1, padding='same', activation='relu')(x)x = MaxPooling2D(2, 2, padding='same')(x)x = BatchNormalization()(x)# block5x = Conv2D(512, (3, 3), strides=1, padding='same', activation='relu')(x)x = Conv2D(512, (3, 3), strides=1, padding='same', activation='relu')(x)x = Conv2D(512, (3, 3), strides=1, padding='same', activation='relu')(x)x = MaxPooling2D(2, 2, padding='same')(x)x = BatchNormalization()(x)# fcx = Flatten()(x)x = Dense(4096, activation='relu')(x)x = Dropout(rate=0.5)(x)x = Dense(4096, activation='relu')(x)x = Dropout(rate=0.5)(x)output_layer = Dense(n_classes, activation='softmax')(x)model = Model(inputs=input_layer, outputs=output_layer)return modeldef VGG19(input_shape=(224, 224, 3), n_classes=1000):"""實(shí)現(xiàn)VGG16C的網(wǎng)絡(luò)結(jié)構(gòu)(著名的VGG16)沒有使用Dropout和BN:param input_shape::param n_classes::return:"""# input layerinput_layer = Input(shape=input_shape)# block1x = Conv2D(filters=64, kernel_size=(3, 3), strides=(1, 1), padding='same', activation='relu')(input_layer)x = Conv2D(64, (3, 3), strides=1, padding='same', activation='relu')(x)x = MaxPooling2D(2, 2, padding='same')(x)# block2x = Conv2D(128, (3, 3), strides=1, padding='same', activation='relu')(x)x = Conv2D(128, (3, 3), strides=1, padding='same', activation='relu')(x)x = MaxPooling2D(2, 2, padding='same')(x)# block3x = Conv2D(256, (3, 3), strides=1, padding='same', activation='relu')(x)x = Conv2D(256, (3, 3), strides=1, padding='same', activation='relu')(x)x = Conv2D(256, (3, 3), strides=1, padding='same', activation='relu')(x)x = Conv2D(256, (3, 3), strides=1, padding='same', activation='relu')(x)x = MaxPooling2D(2, 2, padding='same')(x)# block4x = Conv2D(512, (3, 3), strides=1, padding='same', activation='relu')(x)x = Conv2D(512, (3, 3), strides=1, padding='same', activation='relu')(x)x = Conv2D(512, (3, 3), strides=1, padding='same', activation='relu')(x)x = Conv2D(512, (3, 3), strides=1, padding='same', activation='relu')(x)x = MaxPooling2D(2, 2, padding='same')(x)x = BatchNormalization()(x)# block5x = Conv2D(512, (3, 3), strides=1, padding='same', activation='relu')(x)x = Conv2D(512, (3, 3), strides=1, padding='same', activation='relu')(x)x = Conv2D(512, (3, 3), strides=1, padding='same', activation='relu')(x)x = Conv2D(512, (3, 3), strides=1, padding='same', activation='relu')(x)x = MaxPooling2D(2, 2, padding='same')(x)x = BatchNormalization()(x)# fcx = Flatten()(x)x = Dense(4096, activation='relu')(x)x = Dropout(rate=0.5)(x)x = Dense(4096, activation='relu')(x)x = Dropout(rate=0.5)(x)output_layer = Dense(n_classes, activation='softmax')(x)model = Model(inputs=input_layer, outputs=output_layer)return model為了編寫效率,均使用Function API。(事實(shí)上Keras的構(gòu)建精髓正是Function API)
模型的訓(xùn)練及測(cè)試均在Caltech101數(shù)據(jù)集上進(jìn)行(該數(shù)據(jù)集由李飛飛整理,含一個(gè)干擾項(xiàng))。為了比較模型性能,不進(jìn)行數(shù)據(jù)增廣,采用同樣的優(yōu)化函數(shù)Adam。模型訓(xùn)練選取適中batch_size,為128,使用了BN和Dropout等訓(xùn)練技巧(這不影響核心網(wǎng)絡(luò)結(jié)構(gòu))。后面的深層模型如VGG16和VGG19不使用Dropout或者BN難以訓(xùn)練,每個(gè)block輸出時(shí)使用BN層。
訓(xùn)練結(jié)果
損失圖像
從上圖可以看出,隨著模型深度加深,訓(xùn)練集上損失收斂速度變慢,驗(yàn)證集上損失收斂波動(dòng)大。
準(zhǔn)確率圖像
從上圖可以看出,隨著模型深度加深,訓(xùn)練集上準(zhǔn)確率上升變慢,在同樣的epoch下,到達(dá)的最終驗(yàn)證集準(zhǔn)確率變低。
整體看來,隨著模型加深,需要更多的訓(xùn)練控制如Dropout和BN這樣的中間層來提高訓(xùn)練效果。
關(guān)鍵提示
當(dāng)使用VGGNet時(shí)一般使用的并非上述任何一種網(wǎng)絡(luò)模型,每個(gè)block的卷積層數(shù)目、是否使用Dropout、是否使用BN等完全依據(jù)當(dāng)前任務(wù)修改即可。VGG最偉大之處絕對(duì)不是這個(gè)VGG模型而是小卷積核多層疊加的思想,這也是后來的卷積網(wǎng)絡(luò)的大部分采用的思路。
補(bǔ)充說明
本項(xiàng)目實(shí)現(xiàn)基于Keras2(TensorFlow后端)以及Python3。具體代碼已經(jīng)開源于我的Github,歡迎star或者fork。訓(xùn)練過程在ipynb文件內(nèi)可見。如有疏漏,歡迎評(píng)論指出。
總結(jié)
- 上一篇: 卷积神经网络结构可视化工具PlotNeu
- 下一篇: ResNet详述