CNN发展简史——VGG(三)

简介
VGGNet是2014年ILSVRC竞赛的第二名,第一名是GoogLeNet(谷歌为了纪念LeNet,所以用的大写L)。先讲VGG,因为它这个模型在多个迁移学习任务中的表现要优于GoogLeNet。而且,从图像中提取CNN特征,VGG模型是首选算法。它的缺点在于,参数量有140M之多,需要更大的存储空间。但是这个模型很有研究价值。
原论文地址:https://arxiv.org/pdf/1409.1556.pdf

(-2014-)VGG:
VGG16相比AlexNet的一个改进是采用连续的几个3x3的卷积核代替AlexNet中的较大卷积核(11x11,7x7,5x5)。对于给定的感受野(与输出有关的输入图片的局部大小),采用堆积的小卷积核是优于采用大的卷积核,因为多层非线性层可以增加网络深度来保证学习更复杂的模式,而且代价还比较小(参数更少)。
简单来说,在VGG中,使用了3个3x3卷积核来代替7x7卷积核,使用了2个3x3卷积核来代替5*5卷积核,这样做的主要目的是在保证具有相同感知野的条件下,提升了网络的深度,在一定程度上提升了神经网络的效果。

网络结构
在这里插入图片描述
VGG16包含了16个隐藏层(13个卷积层和3个全连接层),如上图中的D列所示。
VGG19包含了19个隐藏层(16个卷积层和3个全连接层),如上图中的E列所示。

在这里插入图片描述
所有卷积层有相同的配置,即卷积核大小为3x3,步长为1,填充为1;共有5个最大池化层,大小都为2x2,步长为2;共有三个全连接层,前两层都有4096通道,第三层共1000路及代表1000个标签类别;最后一层为softmax层;所有隐藏层后都带有ReLU非线性激活函数;经过实验证明,AlexNet中提出的局部响应归一化(LRN)对性能提升并没有什么帮助,而且还浪费了内存的计算的损耗。

总结:

  1. 使用了更小的3*3卷积核,和更深的网络。这样一方面可以有更少的参数,另一方面拥有更多的非线性变换,增加了CNN对特征的学习能力。
  2. 在VGGNet的卷积结构中,引入1*1的卷积核,在不影响输入输出维度的情况下,引入非线性变换,增加网络的表达能力,降低计算量。
  3. 训练时,先训练级别简单(层数较浅)的VGGNet的A级网络,然后使用A网络的权重来初始化后面的复杂模型,加快训练的收敛速度。
  4. 采用了Multi-Scale的方法来训练和预测。可以增加训练的数据量,防止模型过拟合,提升预测准确率。
  5. 但VGG耗费更多计算资源,并且使用了更多的参数(这里不是3x3卷积的锅)。其中绝大多数的参数都是来自于第一个全连接层,因为VGG是有3个全连接层的。 PS:有的文章称:发现这些全连接层即使被去除,对于性能也没有什么影响,这样就显著降低了参数数量。

tensorflow代码:

#!/usr/bin/env python
# -*- coding: UTF-8 -*-

import tensorflow as tf
import numpy as np

# 加载预训练模型
data_dict = np.load('./vgg16.npy', encoding='latin1').item()


# 打印每层信息
def print_layer(t):
    print
    t.op.name, ' ', t.get_shape().as_list(), '\n'


# 定义卷积层
"""
此处权重初始化定义了3种方式:
    1.预训练模型参数
    2.截尾正态,参考书上采用该方式
    3.xavier,网上blog有采用该方式
通过参数finetrun和xavier控制选择哪种方式,有兴趣的可以都试试
"""


def conv(x, d_out, name, fineturn=False, xavier=False):
    d_in = x.get_shape()[-1].value
    with tf.name_scope(name) as scope:
        # Fine-tuning
        if fineturn:
            kernel = tf.constant(data_dict[name][0], name="weights")
            bias = tf.constant(data_dict[name][1], name="bias")
            print
            "fineturn"
        elif not xavier:
            kernel = tf.Variable(tf.truncated_normal([3, 3, d_in, d_out], stddev=0.1), name='weights')
            bias = tf.Variable(tf.constant(0.0, dtype=tf.float32, shape=[d_out]),
                               trainable=True,
                               name='bias')
            print
            "truncated_normal"
        else:
            kernel = tf.get_variable(scope + 'weights', shape=[3, 3, d_in, d_out],
                                     dtype=tf.float32,
                                     initializer=tf.contrib.layers.xavier_initializer_conv2d())
            bias = tf.Variable(tf.constant(0.0, dtype=tf.float32, shape=[d_out]),
                               trainable=True,
                               name='bias')
            print
            "xavier"
        conv = tf.nn.conv2d(x, kernel, [1, 1, 1, 1], padding='SAME')
        activation = tf.nn.relu(conv + bias, name=scope)
        print_layer(activation)
        return activation


# 最大池化层
def maxpool(x, name):
    activation = tf.nn.max_pool(x, [1, 2, 2, 1], [1, 2, 2, 1], padding='VALID', name=name)
    print_layer(activation)
    return activation


# 定义全连接层
"""
此处权重初始化定义了3种方式:
    1.预训练模型参数
    2.截尾正态,参考书上采用该方式
    3.xavier,网上blog有采用该方式
通过参数finetrun和xavier控制选择哪种方式,有兴趣的可以都试试
"""


def fc(x, n_out, name, fineturn=False, xavier=False):
    n_in = x.get_shape()[-1].value
    with tf.name_scope(name) as scope:
        if fineturn:
            weight = tf.constant(data_dict[name][0], name="weights")
            bias = tf.constant(data_dict[name][1], name="bias")
            print
            "fineturn"
        elif not xavier:
            weight = tf.Variable(tf.truncated_normal([n_in, n_out], stddev=0.01), name='weights')
            bias = tf.Variable(tf.constant(0.1, dtype=tf.float32, shape=[n_out]),
                               trainable=True,
                               name='bias')
            print
            "truncated_normal"
        else:
            weight = tf.get_variable(scope + 'weights', shape=[n_in, n_out],
                                     dtype=tf.float32,
                                     initializer=tf.contrib.layers.xavier_initializer_conv2d())
            bias = tf.Variable(tf.constant(0.1, dtype=tf.float32, shape=[n_out]),
                               trainable=True,
                               name='bias')
            print
            "xavier"
        # 全连接层可以使用relu_layer函数比较方便,不用像卷积层使用relu函数
        activation = tf.nn.relu_layer(x, weight, bias, name=name)
        print_layer(activation)
        return activation


def VGG16(images, _dropout, n_cls):
    """
    此处权重初始化方式采用的是:
        卷积层使用预训练模型中的参数
        全连接层使用xavier类型初始化
    """
    conv1_1 = conv(images, 64, 'conv1_1', fineturn=True)
    conv1_2 = conv(conv1_1, 64, 'conv1_2', fineturn=True)
    pool1 = maxpool(conv1_2, 'pool1')

    conv2_1 = conv(pool1, 128, 'conv2_1', fineturn=True)
    conv2_2 = conv(conv2_1, 128, 'conv2_2', fineturn=True)
    pool2 = maxpool(conv2_2, 'pool2')

    conv3_1 = conv(pool2, 256, 'conv3_1', fineturn=True)
    conv3_2 = conv(conv3_1, 256, 'conv3_2', fineturn=True)
    conv3_3 = conv(conv3_2, 256, 'conv3_3', fineturn=True)
    pool3 = maxpool(conv3_3, 'pool3')

    conv4_1 = conv(pool3, 512, 'conv4_1', fineturn=True)
    conv4_2 = conv(conv4_1, 512, 'conv4_2', fineturn=True)
    conv4_3 = conv(conv4_2, 512, 'conv4_3', fineturn=True)
    pool4 = maxpool(conv4_3, 'pool4')

    conv5_1 = conv(pool4, 512, 'conv5_1', fineturn=True)
    conv5_2 = conv(conv5_1, 512, 'conv5_2', fineturn=True)
    conv5_3 = conv(conv5_2, 512, 'conv5_3', fineturn=True)
    pool5 = maxpool(conv5_3, 'pool5')

    '''
    因为训练自己的数据,全连接层最好不要使用预训练参数
    '''
    flatten = tf.reshape(pool5, [-1, 7 * 7 * 512])
    fc6 = fc(flatten, 4096, 'fc6', xavier=True)
    dropout1 = tf.nn.dropout(fc6, _dropout)

    fc7 = fc(dropout1, 4096, 'fc7', xavier=True)
    dropout2 = tf.nn.dropout(fc7, _dropout)

    fc8 = fc(dropout2, n_cls, 'fc8', xavier=True)

    return fc8

系列传送门:
CNN发展简史——LeNet(一)
CNN发展简史——AlexNet(二)
CNN发展简史——GoogLeNet(四)
CNN发展简史——ResNet(五)
CNN发展简史——DenseNet(六)

猜你喜欢

转载自blog.csdn.net/qq_42823043/article/details/89673227