zoukankan      html  css  js  c++  java
  • vgg学习

    LeNet-5是一个较简单的卷积神经网络。下图显示了其结构:输入的二维图像,先经过两次卷积层到池化层,再经过全连接层,最后使用softmax分类作为输出层。

    AlexNet中包含了几个比较新的技术点,也首次在CNN中成功应用了ReLU、Dropout和LRN等Trick。同时AlexNet也使用了GPU进行运算加速。
    AlexNet将LeNet的思想发扬光大,把CNN的基本原理应用到了很深很宽的网络中。AlexNet主要使用到的新技术点如下:
    (1)成功使用ReLU作为CNN的激活函数,并验证其效果在较深的网络超过了Sigmoid,成功解决了Sigmoid在网络较深时的梯度弥散问题。虽然ReLU激活函数在很久之前就被提出了,但是直到AlexNet的出现才将其发扬光大。
    (2)训练时使用Dropout随机忽略一部分神经元,以避免模型过拟合。Dropout虽有单独的论文论述,但是AlexNet将其实用化,通过实践证实了它的效果。在AlexNet中主要是最后几个全连接层使用了Dropout。
    (3)在CNN中使用重叠的最大池化。此前CNN中普遍使用平均池化,AlexNet全部使用最大池化,避免平均池化的模糊化效果。并且AlexNet中提出让步长比池化核的尺寸小,这样池化层的输出之间会有重叠和覆盖,提升了特征的丰富性。
    (4)提出了LRN层,对局部神经元的活动创建竞争机制,使得其中响应比较大的值变得相对更大,并抑制其他反馈较小的神经元,增强了模型的泛化能力。
    (5)使用CUDA加速深度卷积网络的训练,利用GPU强大的并行计算能力,处理神经网络训练时大量的矩阵运算。AlexNet使用了两块GTX 580 GPU进行训练,单个GTX 580只有3GB显存,这限制了可训练的网络的最大规模。因此作者将AlexNet分布在两个GPU上,在每个GPU的显存中储存一半的神经元的参数。因为GPU之间通信方便,可以互相访问显存,而不需要通过主机内存,所以同时使用多块GPU也是非常高效的。同时,AlexNet的设计让GPU之间的通信只在网络的某些层进行,控制了通信的性能损耗。 

    (6)数据增强,随机地从256*256的原始图像中截取224*224大小的区域(以及水平翻转的镜像),相当于增加了2*(256-224)^2=2048倍的数据量。如果没有数据增强,仅靠原始的数据量,参数众多的CNN会陷入过拟合中,使用了数据增强后可以大大减轻过拟合,提升泛化能力。进行预测时,则是取图片的四个角加中间共5个位置,并进行左右翻转,一共获得10张图片,对他们进行预测并对10次结果求均值。同时,AlexNet论文中提到了会对图像的RGB数据进行PCA处理,并对主成分做一个标准差为0.1的高斯扰动,增加一些噪声,这个Trick可以让错误率再下降1%。

    # -*- coding=UTF-8 -*-  
    import tensorflow as tf  
    # 输入数据  
    import input_data  
    mnist = input_data.read_data_sets("/tmp/data/", one_hot=True)  
    # 定义网络超参数  
    learning_rate = 0.001  
    training_iters = 200000  
    batch_size = 64  
    display_step = 20  
    # 定义网络参数  
    n_input = 784  # 输入的维度  
    n_classes = 10 # 标签的维度  
    dropout = 0.8  # Dropout 的概率  
    # 占位符输入  
    = tf.placeholder(tf.types.float32, [None, n_input])  
    = tf.placeholder(tf.types.float32, [None, n_classes])  
    keep_prob = tf.placeholder(tf.types.float32)  
    # 卷积操作  
    def conv2d(name, l_input, w, b):  
        return tf.nn.relu(tf.nn.bias_add(   
        tf.nn.conv2d(l_input, w, strides=[1111], padding='SAME'),b)   
        , name=name)  
    # 最大下采样操作  
    def max_pool(name, l_input, k):  
        return tf.nn.max_pool(l_input, ksize=[1, k, k, 1],   
        strides=[1, k, k, 1], padding='SAME', name=name)  
    # 归一化操作  
    def norm(name, l_input, lsize=4):  
        return tf.nn.lrn(l_input, lsize, bias=1.0, alpha=0.001 / 9.0, beta=0.75, name=name)  
    # 定义整个网络   
    def alex_net(_X, _weights, _biases, _dropout):  
        _X = tf.reshape(_X, shape=[-128281]) # 向量转为矩阵  
        # 卷积层  
        conv1 = conv2d('conv1', _X, _weights['wc1'], _biases['bc1'])  
        # 下采样层  
        pool1 = max_pool('pool1', conv1, k=2)  
        # 归一化层  
        norm1 = norm('norm1', pool1, lsize=4)  
        # Dropout  
        norm1 = tf.nn.dropout(norm1, _dropout)  
       
        # 卷积  
        conv2 = conv2d('conv2', norm1, _weights['wc2'], _biases['bc2'])  
        # 下采样  
        pool2 = max_pool('pool2', conv2, k=2)  
        # 归一化  
        norm2 = norm('norm2', pool2, lsize=4)  
        # Dropout  
        norm2 = tf.nn.dropout(norm2, _dropout)  
       
        # 卷积  
        conv3 = conv2d('conv3', norm2, _weights['wc3'], _biases['bc3'])  
        # 下采样  
        pool3 = max_pool('pool3', conv3, k=2)  
        # 归一化  
        norm3 = norm('norm3', pool3, lsize=4)  
        # Dropout  
        norm3 = tf.nn.dropout(norm3, _dropout)  
       
        # 全连接层,先把特征图转为向量  
        dense1 = tf.reshape(norm3, [-1, _weights['wd1'].get_shape().as_list()[0]])   
        dense1 = tf.nn.relu(tf.matmul(dense1, _weights['wd1']) + _biases['bd1'], name='fc1')   
        # 全连接层  
        dense2 = tf.nn.relu(tf.matmul(dense1, _weights['wd2']) + _biases['bd2'], name='fc2'
        # Relu activation  
        # 网络输出层  
        out = tf.matmul(dense2, _weights['out']) + _biases['out']  
        return out  
       
    # 存储所有的网络参数  
    weights = {  
        'wc1': tf.Variable(tf.random_normal([33164])),  
        'wc2': tf.Variable(tf.random_normal([3364128])),  
        'wc3': tf.Variable(tf.random_normal([33128256])),  
        'wd1': tf.Variable(tf.random_normal([4*4*2561024])),  
        'wd2': tf.Variable(tf.random_normal([10241024])),  
        'out': tf.Variable(tf.random_normal([102410]))  
    }  
    biases = {  
        'bc1': tf.Variable(tf.random_normal([64])),  
        'bc2': tf.Variable(tf.random_normal([128])),  
        'bc3': tf.Variable(tf.random_normal([256])),  
        'bd1': tf.Variable(tf.random_normal([1024])),  
        'bd2': tf.Variable(tf.random_normal([1024])),  
        'out': tf.Variable(tf.random_normal([n_classes]))  
    }  
    # 构建模型  
    pred = alex_net(x, weights, biases, keep_prob)  
    # 定义损失函数和学习步骤  
    cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(pred, y))  
    optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(cost)  
    # 测试网络  
    correct_pred = tf.equal(tf.argmax(pred,1), tf.argmax(y,1))  
    accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32))  
    # 初始化所有的共享变量  
    init = tf.initialize_all_variables()  
    # 开启一个训练  
    with tf.Session() as sess:  
        sess.run(init)  
        step = 1  
        # Keep training until reach max iterations  
        while step * batch_size < training_iters:  
            batch_xs, batch_ys = mnist.train.next_batch(batch_size)  
            # 获取批数据  
            sess.run(optimizer, feed_dict={x: batch_xs, y: batch_ys, keep_prob: dropout})  
            if step % display_step == 0:  
                # 计算精度  
                acc = sess.run(accuracy, feed_dict={x: batch_xs, y: batch_ys, keep_prob: 1.})  
                # 计算损失值  
                loss = sess.run(cost, feed_dict={x: batch_xs, y: batch_ys, keep_prob: 1.})  
                print "Iter " + str(step*batch_size) + ", Minibatch Loss= " + "{:.6f}".format(loss) + ", Training Accuracy= " + "{:.5f}".format(acc)  
            step += 1  
        print "Optimization Finished!"  
        # 计算测试精度  
        print "Testing Accuracy:", sess.run(accuracy, feed_dict={x: mnist.test.images[:256], y: mnist.test.labels[:256], keep_prob: 1.})  
     
    以上代码忽略了部分卷积层,全连接层使用了特定的权重。
     
    VGG是在从Alex-net发展而来的网络。主要修改一下两个方面:
    1,在第一个卷基层层使用更小的filter尺寸和间隔(3*3); 2,在整个图片和multi-scale上训练和测试图片。
    3*3 filter:
    引入cs231n上面一段话:
    几个小滤波器卷积层的组合比一个大滤波器卷积层好:
    假设你一层一层地重叠了3个3x3的卷积层(层与层之间有非线性激活函数)。在这个排列下,第一个卷积层中的每个神经元都对输入数据体有一个3x3的视野。
    第二个卷积层上的神经元对第一个卷积层有一个3x3的视野,也就是对输入数据体有5x5的视野。同样,在第三个卷积层上的神经元对第二个卷积层有3x3的视野,
    也就是对输入数据体有7x7的视野。假设不采用这3个3x3的卷积层,二是使用一个单独的有7x7的感受野的卷积层,那么所有神经元的感受野也是7x7,但是就有一些缺点。
    首先,多个卷积层与非线性的激活层交替的结构,比单一卷积层的结构更能提取出深层的更好的特征。其次,假设所有的数据有C个通道,那么单独的7x7卷积层将会包含
    7*7*C=49C2个参数,而3个3x3的卷积层的组合仅有个3*(3*3*C)=27C2个参数。直观说来,最好选择带有小滤波器的卷积层组合,而不是用一个带有大的滤波器的卷积层。前者可以表达出输入数据中更多个强力特征,
    使用的参数也更少。唯一的不足是,在进行反向传播时,中间的卷积层可能会导致占用更多的内存。
     
    1*1 filter: 作用是在不影响输入输出维数的情况下,对输入线进行线性形变,然后通过Relu进行非线性处理,增加网络的非线性表达能力。 Pooling:2*2,间隔s=2。
     

    VGG

    VGG-16和VGG-19取名源自作者所处研究组名(Visual Geometry Group),后面的16 19代表了网络的深度。

    VGG-16/VGG-19 138M参数,ILSVRC 2014的亚军网络。

    VGG-16结构的基本框架

    conv1^2 (64) -> pool1 -> conv2^2 (128) -> pool2 -> conv3^3 (256) -> pool3 -> conv4^3 (512) -> pool4 -> conv5^3 (512) -> pool5 -> fc6 (4096) -> fc7 (4096) -> fc8 (1000) -> softmax。 ^3代表重复3次。

    网络输入的224×224的图像。

    VGG网络的特点

    (1). 结构简单,作者将卷积核全部替换为3×3(极少用了1×1);相比于AlexNet 的池化核,VGG全部使用2×2的池化核。

    (2). 参数量大,而且大部分的参数集中在全连接层中。网络名称中有16表示它有16层conv/fc层。

    (3). 合适的网络初始化和使用批量归一(batch normalization)层对训练深层网络很重要。

    (4). VGG-19结构类似于VGG-16,有略好于VGG-16的性能,但VGG-19需要消耗更大的资源,因此实际中VGG-16使用得更多。由于VGG-16网络结构十分简单,并且很适合迁移学习,因此至今VGG-16仍在广泛使用。

    def VGG16(images, _dropout, n_cls):
        """
        此处权重初始化方式采用的是:
            卷积层使用预训练模型中的参数
            全连接层使用xavier类型初始化
        """
        conv1_1 = conv(images, 64, 'conv1_1', fineturn=True) #1
        conv1_2 = conv(conv1_1, 64, 'conv1_2', fineturn=True) #2
        pool1   = maxpool(conv1_2, 'pool1')
     
        conv2_1 = conv(pool1, 128, 'conv2_1', fineturn=True) #3
        conv2_2 = conv(conv2_1, 128, 'conv2_2', fineturn=True) #4
        pool2   = maxpool(conv2_2, 'pool2')
     
        conv3_1 = conv(pool2, 256, 'conv3_1', fineturn=True) #5
        conv3_2 = conv(conv3_1, 256, 'conv3_2', fineturn=True) #6
        conv3_3 = conv(conv3_2, 256, 'conv3_3', fineturn=True) #7
        pool3   = maxpool(conv3_3, 'pool3')
     
        conv4_1 = conv(pool3, 512, 'conv4_1', fineturn=True) #8
        conv4_2 = conv(conv4_1, 512, 'conv4_2', fineturn=True) #9
        conv4_3 = conv(conv4_2, 512, 'conv4_3', fineturn=True) #10
        pool4   = maxpool(conv4_3, 'pool4')
     
        conv5_1 = conv(pool4, 512, 'conv5_1', fineturn=True) #11
        conv5_2 = conv(conv5_1, 512, 'conv5_2', fineturn=True) #12
        conv5_3 = conv(conv5_2, 512, 'conv5_3', fineturn=True) #13
        pool5   = maxpool(conv5_3, 'pool5')
     
        #因为训练自己的数据,全连接层最好不要使用预训练参数
        flatten  = tf.reshape(pool5, [-1, 7*7*512])
        fc6      = fc(flatten, 4096, 'fc6', xavier=True) #14
        dropout1 = tf.nn.dropout(fc6, _dropout)
     
        fc7      = fc(dropout1, 4096, 'fc7', xavier=True) #15
        dropout2 = tf.nn.dropout(fc7, _dropout)
        
        fc8      = fc(dropout2, n_cls, 'fc8', xavier=True) #16
     
        return fc8

  • 相关阅读:
    初学者常用的LINUX命令
    logging模块全总结
    logging模块初识
    xpath知多少
    selenium常用的API
    系统测试基础(适合入门)
    JavaScript正则表达式(一)
    webpack2学习(二)
    webpack2学习(一)
    SQL语句学习
  • 原文地址:https://www.cnblogs.com/hrnn/p/13520663.html
Copyright © 2011-2022 走看看