VGG论文笔记
VGG:Very Deep Convollutional Networks for Large-Scale Image Recognition
摘要:本文研究了卷积网络的深度对于图像识别任务的准确率的影响。本文的主要贡献:通过堆叠3x3卷积层增加网络深度,系统地研究了网络深度增加到16-19层的过程中性能的提升。上面的研究基于14年ImageNet比赛提交的模型(分类第一名,定位第二名)。另外,我们的模型泛化能力很好,在其它数据集上也取得了state of art。我们开源了两个性能最好的网络,以方便大家在计算机视觉上的进一步研究。
关键点:网络深度,性能
文章总结
系统研究了网络深度对性能的影响。顺便研究了LRN层对性能的影响。另外,VGG大量使用了3x3小卷积。
1. 简介
VGG为了研究了网络深度对性能的影响,在固定架构的其它参数的情况下,通过增加卷积层来逐渐增加网络的深度(整个网络使用的都是3x3卷积核)。作者也提到了,提取到的高层特征也可以使用SVM分类
2. 卷积网络配置
为了衡量深度带来的性能提升,所有的卷积网络层的配置完全一致。
输入:224x224x3
预处理:减去mean RGB值
网络可用组件:3x3卷积层;1x1卷积层;卷积的stride为1;卷积的padding为same以保证conv后分辨率不变;卷积的channel以2的倍数增加(从64开始,最高512);池化选择ksize为2x2stride为2的max-pooling。卷积后接一个三层FC:4096-4096-1000+softmax。整个网络使用ReLU**函数。有一个网络版本含有LRN层。
下图是本文使用的网络的配置:
本文一共构建了6个模型(A-E):
A:(11层)8层conv,3层FC
A-LRN:(11层)在A上,增加1个LRN(放在第一个conv后)。
B:(13层)在B上,增加2层3x3 conv
C:(16层)在C上,增加3层1x1 conv
D:(16层)在B上,增加3层3x3 conv
E:(19层)在C上,增加3层3x3 conv
讨论:
VGG在更深的情况下,以较少的参数量取得了比大卷积核浅层网络更好的性能。VGG的第一层不同于AlexNet和ZFNet(AlexNet:11x11 stride 2)(ZFNet:7x7 stride 2),VGG整个网络采用3x3 stride 1卷积。在没有池化时,两个3x3 filter的感受野等效于一个5x5 filter的感受野,3个3x3 filter可以等效1个7x7 filter的感受野。用小卷积核代替大卷积核有两个作用:1.增加了ReLU的个数,从而增加了模型非线性能力;2.减少了参数量;作者认为用3个3x3 conv代替1个7x7 conv,可以看做是对7x7 conv进行了正则。
在模型C中,使用了1x1卷积,它在不改变感受野大小的情况下,增加了模型的非线性。
3.网络在分类任务上的配置
训练
优化算法:mini-batch GD with momentum(0.9)
损失函数:Multinomial Logistic Regression损失函数推荐阅读内容
batch size:256
weight decay rate:5x
FC前两层的dropout rate:0.5
学习速率:开始设置为,当验证集上的误差停止下降时将学习速率降低为当前的十分之一。
在ImageNet上,训练过程中学习速率下降了3次,迭代了370k次(74epochs)
模型参数的初始化很重要,VGG使用训练好浅层网络的参数初始化更深网络部分层的参数,当然也可以使用Glorot & Bengio (2010)提出的Xavier参数初始化方法。
模型输入的224x224图像从rescaled的图像随机裁剪而来,并进行随机的水平翻转和随机RGB颜色变化。
rescale就是将图像重新调整大小
VGG的TensorFlow实现
#coding:utf-8
'''
下面对VGG文章中的A,A-LRN,B,C,D,E模型进行了实现。
通过更改inference的version参数就可以得到文中的不同深度及配置的模型。
'''
import tensorflow as tf
relu = tf.nn.relu
def print_activation(x):
print(x.op.name, x.get_shape().as_list())
def inference(inputs,
num_classes=1000,
is_training=True,
dropout_keep_prob=0.5,
version='A'):
'''
inputs: a tensor of images
num_classes: the num of category.
is_training: set ture when it used for training
dropout_keep_prob: the rate of dropout during training
version: ['A','A-LRN','B','C','D','E']
'''
x = inputs
print_activation(x)
with tf.variable_scope('unit_1'):
x = tf.layers.Conv2D(64, [3,3], padding='SAME', activation=relu)(x)
print_activation(x)
if version=='A-LRN':
x = tf.nn.local_response_normalization(x, name='lrn')
print_activation(x)
elif version in ['B','C','D','E']:
x = tf.layers.Conv2D(64, [3,3], padding='SAME', activation=relu)(x)
print_activation(x)
x = tf.layers.MaxPooling2D([2,2], [2,2], padding='SAME')(x)
print_activation(x)
with tf.variable_scope('unit_2'):
x = tf.layers.Conv2D(128, [3,3], padding='SAME', activation=relu)(x)
print_activation(x)
if version in ['B','C','D','E']:
x = tf.layers.Conv2D(128, [3,3], padding='SAME', activation=relu)(x)
print_activation(x)
x = tf.layers.MaxPooling2D([2,2], [2,2], padding='SAME')(x)
print_activation(x)
with tf.variable_scope('unit_3'):
x = tf.layers.Conv2D(256, [3,3], padding='SAME', activation=relu)(x)
print_activation(x)
x = tf.layers.Conv2D(256, [3,3], padding='SAME', activation=relu)(x)
print_activation(x)
if version=='C':
x = tf.layers.Conv2D(256, [1,1], padding='SAME', activation=relu)(x)
print_activation(x)
if version in ['D','E']:
x = tf.layers.Conv2D(256, [3,3], padding='SAME', activation=relu)(x)
print_activation(x)
if version=='E':
x = tf.layers.Conv2D(256, [3,3], padding='SAME', activation=relu)(x)
print_activation(x)
x = tf.layers.MaxPooling2D([2,2], [2,2], padding='SAME')(x)
print_activation(x)
with tf.variable_scope('unit_4'):
x = tf.layers.Conv2D(512, [3,3], padding='SAME', activation=relu)(x)
print_activation(x)
x = tf.layers.Conv2D(512, [3,3], padding='SAME', activation=relu)(x)
print_activation(x)
if version=='C':
x = tf.layers.Conv2D(512, [1,1], padding='SAME', activation=relu)(x)
print_activation(x)
if version in ['D','E']:
x = tf.layers.Conv2D(512, [3,3], padding='SAME', activation=relu)(x)
print_activation(x)
if version=='E':
x = tf.layers.Conv2D(512, [3,3], padding='SAME', activation=relu)(x)
print_activation(x)
x = tf.layers.MaxPooling2D([2,2], [2,2], padding='SAME')(x)
print_activation(x)
with tf.variable_scope('unit_5'):
x = tf.layers.Conv2D(512, [3,3], padding='SAME', activation=relu)(x)
print_activation(x)
x = tf.layers.Conv2D(512, [3,3], padding='SAME', activation=relu)(x)
print_activation(x)
if version=='C':
x = tf.layers.Conv2D(512, [1,1], padding='SAME', activation=relu)(x)
print_activation(x)
if version in ['D','E']:
x = tf.layers.Conv2D(512, [3,3], padding='SAME', activation=relu)(x)
print_activation(x)
if version=='E':
x = tf.layers.Conv2D(512, [3,3], padding='SAME', activation=relu)(x)
print_activation(x)
x = tf.layers.MaxPooling2D([2,2], [2,2], padding='SAME')(x)
print_activation(x)
with tf.variable_scope('fc'):
x = tf.layers.Flatten()(x)
x = tf.layers.Dense(4096)(x)
print_activation(x)
x = tf.layers.Dense(4096)(x)
print_activation(x)
logits = tf.layers.Dense(num_classes)(x)
print_activation(logits)
return logits
#下面是文章3.2节用conv代替FC的代码
# x = tf.layers.Conv2D(4096, [7,7], activation=relu)(x)
# print_activation(x)
# x = tf.layers.Conv2D(4096, [1,1], activation=relu)(x)
# print_activation(x)
# logits = tf.layers.Conv2D(num_classes, [1,1], activation=relu)(x)
# print_activation(logits)
# return logits
if __name__ == '__main__':
with tf.variable_scope('inputs'):
images = tf.placeholder(tf.float32, [None,224,224,3])
labels = tf.placeholder(tf.float32, [None, 1000])
logits = inference(inputs=images, num_classes=1000,
is_training=True, version='A')
print('inference is ok!')
注意:使用本博客的代码,请添加引用
上一篇: Maxout论文笔记