六、TensorFlow实现VGGNet

VGGNet是牛津大学计算机视觉组Google DeepMind一起研发的深度卷积神经网络。

特点:1、反复堆叠3x3的小型卷积核和2x2的最大池化层。

2、拥有16~19层深的卷积神经网络。

3、拓展性强,迁移到其他图片数据上的泛化性好。

4、常被用来提取图像特征。

5、模型参数已开源,可在图像分类任务上进行再训练。

网络介绍:

VGGNet拥有5段卷积,每段内有2~3个卷积层,每段尾部连接一个最大池化层用来缩小图片尺寸。

段内卷积核数目相同,越靠后的段,其内卷积核数量越多。

3个3x3的卷积层串联效果,相当于1个7x7的卷积层,且比其拥有更多的非线性变换。

训练技巧:

1、先训练级别A简单网络,再复用A网络的权重来初始化后面的复杂模型,这样收敛速度快。

2、采用Multi-Scale的方法,将图像scale到一个尺寸Q,并将图片输入卷积网络计算,再在最后一个卷积层使用滑窗的方式进行预测,将不同窗口的分类结果平均,将不同的尺寸Q平均,得最后结果,可提高图片数据的利用率预测准确率

3、使用Multi-Scale的方法做数据增强,将原始图像缩放到不同尺寸S,再随机裁切224x224的图片,可增加数据量,防止过拟合。

from datetime import datetime
import math
import time
import tensorflow as tf
import tensorflow.contrib

# input_op是输入的tensor,name是这一层的名称,kh和kw是卷积核高宽
# n_out是卷积核的数量,即输出通道数,dh和dw是步长的高宽,p是参数列表
def conv_op(input_op, name, kh, kw, n_out, dh, dw, p):
    '''创建卷积层并把本层的参数存入参数列表'''
    n_in = input_op.get_shape()[-1].value  # 获取输入通道数

    with tf.name_scope(name) as scope:
        kernel = tf.get_variable(scope + "w", shape=[kh, kw, n_in, n_out], dtype=tf.float32,
                                 initializer=tf.contrib.layers.xavier_initializer_conv2d())
        # 对input_op进行卷积处理
        conv = tf.nn.conv2d(input_op, kernel, (1, dh, dw, 1), padding='SAME')
        bias_init_val = tf.constant(0.0, shape=[n_out], dtype=tf.float32)
        # 使用tf.constant赋值为0
        biases = tf.Variable(bias_init_val, trainable=True, name='b')
        z = tf.nn.bias_add(conv, biases)
        activation = tf.nn.relu(z, name=scope)
        p += [kernel, biases]
        return activation


def fc_op(input_op, name, n_out, p):
    '''定义全连接层的创建函数fc_op'''
    n_in = input_op.get_shape()[-1].value  # 获取输入的通道数

    with tf.name_scope(name) as scope:
        # 创建全连接层的参数
        kernel = tf.get_variable(scope + "w", shape=[n_in, n_out], dtype=tf.float32,
                                 initializer=tf.contrib.layers.xavier_initializer())
        biases = tf.Variable(tf.constant(0.1, shape=[n_out], dtype=tf.float32), name='b')
        # 对input_op和kernel做矩阵乘法并加上biases,再做非线性变换
        activation = tf.nn.relu_layer(input_op, kernel, biases, name=scope)
        p += [kernel, biases]
        return activation


def mpool_op(input_op, name, kh, kw, dh, dw):
    '''定义最大池化层的创建函数'''
    return tf.nn.max_pool(input_op, ksize=[1, kh, kw, 1], strides=[1, dh, dw, 1], padding='SAME', name=name)


# keep_prob是控制dropout比率的一个placeholder
def inference_op(input_op, keep_prob):
    '''开始创建VGGNet-16的网络结构'''
    p = []
    # 第一个卷积层的输入尺寸为224x224x3,输出尺寸为224x224x64
    conv1_1 = conv_op(input_op, name="conv1_1", kh=3, kw=3, n_out=64, dh=1, dw=1, p=p)
    conv1_2 = conv_op(conv1_1, name="conv1_2", kh=3, kw=3, n_out=64, dh=1, dw=1, p=p)
    # 第一段网络的输出尺寸变为56x56x128
    pool1 = mpool_op(conv1_2, name="pool1", kh=2, kw=2, dw=2, dh=2)

    # 输出通道变为128
    conv2_1 = conv_op(pool1, name="conv2_1", kh=3, kw=3, n_out=128, dh=1, dw=1, p=p)
    conv2_2 = conv_op(conv2_1, name="conv2_2", kh=3, kw=3, n_out=128, dh=1, dw=1, p=p)
    # 第二段卷积网络的输出尺寸变为56x56x128
    pool2 = mpool_op(conv2_2, name="pool2", kh=2, kw=2, dw=2, dh=2)

    # 输出通道变为256
    conv3_1 = conv_op(pool2, name="conv3_1", kh=3, kw=3, n_out=256, dh=1, dw=1, p=p)
    conv3_2 = conv_op(conv3_1, name="conv3_2", kh=3, kw=3, n_out=256, dh=1, dw=1, p=p)
    conv3_3 = conv_op(conv3_2, name="conv3_3", kh=3, kw=3, n_out=256, dh=1, dw=1, p=p)
    # 第三段卷积网络的输出尺寸变为28x28x256
    pool3 = mpool_op(conv3_3, name="pool3", kh=2, kw=2, dw=2, dh=2)

    # 3个卷积层加1个最大池化层。
    conv4_1 = conv_op(pool3, name="conv4_1", kh=3, kw=3, n_out=512, dh=1, dw=1, p=p)
    conv4_2 = conv_op(conv4_1, name="conv4_2", kh=3, kw=3, n_out=512, dh=1, dw=1, p=p)
    conv4_3 = conv_op(conv4_2, name="conv4_3", kh=3, kw=3, n_out=512, dh=1, dw=1, p=p)
    # 第四段卷积网络的输出尺寸变为14x14x512
    pool4 = mpool_op(conv4_3, name="pool4", kh=2, kw=2, dw=2, dh=2)

    conv5_1 = conv_op(pool4, name="conv5_1", kh=3, kw=3, n_out=512, dh=1, dw=1, p=p)
    conv5_2 = conv_op(conv5_1, name="conv5_2", kh=3, kw=3, n_out=512, dh=1, dw=1, p=p)
    conv5_3 = conv_op(conv5_2, name="conv5_3", kh=3, kw=3, n_out=512, dh=1, dw=1, p=p)
    # 第五段卷积网络的输出尺寸变为7x7x512
    pool5 = mpool_op(conv5_3, name="pool5", kh=2, kw=2, dw=2, dh=2)

    # 将输出结果扁平化
    shp = pool5.get_shape()
    flattened_shape = shp[1].value * shp[2].value * shp[3].value
    # 将每个样本化为长度为7x7x512=25088的一维向量
    resh1 = tf.reshape(pool5, [-1, flattened_shape], name="resh1")

    # 连接一个隐含节点数为4096的全连接层,激活函数为ReLU
    fc6 = fc_op(resh1, name="fc6", n_out=4096, p=p)
    # 连接一个Droppout层,节点保留率为0.5,预测时为1.0
    fc6_drop = tf.nn.dropout(fc6, keep_prob, name="fc6_drop")

    fc7 = fc_op(fc6_drop, name="fc7", n_out=4096, p=p)
    fc7_drop = tf.nn.dropout(fc7, keep_prob, name="fc7_drop")

    # 最后连接一个有1000个输出节点的全连接层
    fc8 = fc_op(fc7_drop, name="fc8", n_out=1000, p=p)
    # 得到分类输出概率
    softmax = tf.nn.softmax(fc8)
    # 求输出概率最大的类别
    predictions = tf.argmax(softmax, 1)
    return predictions, softmax, fc8, p


def time_tensorflow_run(session, target, feed, info_string):
    num_steps_burn_in = 10
    total_duration = 0.0
    total_duration_squared = 0.0
    for i in range(num_batches + num_steps_burn_in):
        start_time = time.time()
        _ = session.run(target, feed_dict=feed)
        duration = time.time() - start_time
        if i >= num_steps_burn_in:
            if not i % 10:
                print('%s: step %d, duration = %.3f' %
                      (datetime.now(), i - num_steps_burn_in, duration))
                total_duration += duration
                total_duration_squared += duration * duration
    mn = total_duration / num_batches
    vr = total_duration_squared / num_batches - mn * mn
    sd = math.sqrt(vr)
    print('%s: %s across %d steps, %.3f +/- %.3f sec /batch' %
          (datetime.now(), info_string, num_batches, mn, sd))


def run_benchmark():
    with tf.Graph().as_default():
        image_size = 224
        images = tf.Variable(tf.random_normal([
            batch_size, image_size, image_size, 3
        ], dtype=tf.float32, stddev=1e-1))
        keep_prob = tf.placeholder(tf.float32)
        predictions, softmax, fc8, p = inference_op(images, keep_prob)

        init = tf.global_variables_initializer()
        sess = tf.Session()
        sess.run(init)

        # 测评forward运算时间
        time_tensorflow_run(sess, predictions, {keep_prob: 1.0}, "Forward")
        # 计算全连接层的输出fc8的l2loss
        objective = tf.nn.l2_loss(fc8)
        # 求相对于这个loss的所有模型参数的梯度
        grad = tf.gradients(objective, p)
        # 测评backward运算时间
        time_tensorflow_run(sess, grad, {keep_prob: 0.5}, "Forward-backward")


batch_size = 32
num_batches = 100
run_benchmark()

猜你喜欢

转载自blog.csdn.net/qq_27437197/article/details/86530690
今日推荐