NIN原理和实现

NIN原理和实现个人博客 http www chenjianqu com 原文链接 http www chenjianqu com show 65 html 论文笔记 1 解决了什么改进 CNN 2 提出的模型提出 mlpconv 引入了 1×1 卷积和 globalaverag 提出 NetworkInNet NIN 整个模型未使用全连接 3

 个人博客:http://www.chenjianqu.com/

原文链接:http://www.chenjianqu.com/show-65.html

 

论文笔记

1.解决了什么

改进CNN。

2.提出的模型

提出mlpconv,引入了1×1卷积和global average pooling,提出Network In Network(NIN),整个模型未使用全连接。

3.实验结果

在CIFAR-10和CIFAR-100上面获得SOTA结果。

4.待解决的问题

模型不够深,迁移能力有待加强。

 

卷积神经网络(CNN)

    卷积神经网络一般由卷积层、池化层和全连接层组成,如下图:

3.jpg

    卷积层的工作原理:卷积核与局部感受野(local receptive field)点积得到特征图(feature map),举例如下:

1.png

2.gif

 

模型提出

    传统卷积层的滤波器/卷积核是局部感受野的广义线性模型(GLM),作者认为GLM的抽象层级很低,使用更有效的非线性函数逼近器(nonlinear function approximator)可以提高卷积层的抽象能力。当隐含概念(latent concepts)的样本是线性可分时,即概念的变体都位于GLM定义的分离平面的一侧时,GLM可以实现很好的特征抽象。所以CNN隐含的假设是latent concepts是线性可分的。

    但是实际上相同概念的数据通常存在于非线性流形(nonlinear manifold)上,需要通过高度非线性函数去捕捉这些概念表示。在NIN中,使用微型网络(micro network)结构替代GLM,micro network是一个广义非线性函数逼近器,这里使用多层感知器(MLP)作为micro network。下图是线性卷积层和多层感知器卷积层(MlpConv Layer):

3.png

    线性卷积层和mlpconv都是将局部感受野(local receptive field)映射到输出特征向量。Mlpconv核使用带非线性激活函数的MLP,跟传统的CNN一样,MLP在各个局部感受野中共享参数的,滑动MLP核可以最终得到输出特征图。NIN通过多个mlpconv的堆叠得到。

    在NIN中,卷积层后不接全连接层(FC),而是将最后一个的mlpconv的输出特征图全局平均池化(global average pooling,GAP),而后softmax。

    使用GAP有个好处是增加模型的可解释性。传统的CNN中,因为FC层是一个黑盒,所以很难知道类别信息(category level information)是如何传到前面的卷积层的。而GAP强制要求特征图对应类别信息,因此GAP的可解释性更强。此外,相比于FC,GAP的泛化性能更好,更不容易过拟合。

 

线性卷积层

    传统的线性卷积层的计算公式如下:

2.png

    其中i,j是输出特征图的索引,x_ij是输入图片的局部感受野的索引,k是输出特征图的通道索引,wk是第k个卷积核,max(A,0)代表使用relu激活函数。

    前面说过,当隐含概念是线性可分时,线性卷积层对于抽象是足够的。线性卷积层需要通过一组over-complete的卷积核来覆盖所有隐含概念的变体,一个滤波器检测同一概念的变体。然而,一个概念有太多的卷积核会给下一层卷积层带来额外的负担,因为它需要考虑来自上一层的概念所有变化组合。在CNN中,后面的卷积层滤波器对应原始输入的较大区域,滤波器通过联合上一层输出的较低层的特征来生成更高层次的特征。由此可见,每一层抽象程度更高是有利的。

 

跨通道池化(CCP)

    这个概念在论文Maout Networks中有解释。假设你有一个线性模块,该模型有50个输出通道,但是你想要的是5个输出通道。就可以使用cross-channel pooling来对channel进行下采样(可以使用最大池化)。具体说CCP输出特征图中的每个点是10个原始特征图中对应点的最大值。

 

MLP卷积层

    需要用一个通用函数逼近器来抽取局部感受野的特征,最常用的有径向基网络多层感知器。选择MLP的理由是:1.MLP与卷积神经网络兼容,都使用BP训练;2. 多层感知器本身是一个深度模型,这与特征重用的思想是一致。使用MLP代替原来卷积层的GLM,新的层叫做mlpconv。mlpconv的计算如下:

4.png

    这里的n是mlp的层数,mlp使用relu作为激活函数。

    从跨通道池化的观点看,上式等价于在普通卷积层上级联跨通道参数池化层(cascaded cross channel parametric pooling,CCCP),每一个池化层对输入特征图进行加权线性重组,然后通过一个非线性激活函数。直白地说CCCP就是1×1卷积。这种结构允许复杂和可学习的跨通道信息交互。

 

全局平均池化(GAP)

    传统的CNN模型先是使用堆叠的卷积层提取特征,输入全连接层(FC)进行分类。这种结构沿袭自LeNet5,把卷积层作为特征抽取器,全连接层作为分类器。但是FC层参数数量太多,很容易过拟合,会影响模型的泛化性能。因此需要用Dropout增加模型的泛化性。

    这里提出GAP代替传统的FC层。主要思想是零每个分类对应最后一层mlpconv的输出特征图。对每个特征图取平均,后将得到的池化后的向量softmax得到分类概率。GAP的优点:

  1. 加强了特征映射和类别之间的对应,更适合卷积神经网络,特征图可以被解释类别置信度。
  2. GAP层不用优化参数,可以避免过拟合。
  3. GAP对空间信息进行汇总,因此对输入数据的空间变换有更好的鲁棒性。

    可以将GAP看做一个结构正则化器,显性地强制特征图映射为概念置信度。

 

Network In Network(NIN)

    NIN是由mlpconv堆叠而成,顶部是GAP层,在mlpconv层之间加入下采样层。下图是有三层mlpconv层的NIN,每个mlpconv层里有3层的mlp。

5.png

    NIN是基于AlexNet 改进而来,因此卷积层的其它参数设置和alexnet类似。

 

NIN训练

    使用四个基准数据集评估NIN模型:CIFAR-10 CIFAR-100 SVHN MNIST。

    模型架构:三层mlpconv堆叠而成,每个mlpconv层后接最大池化层,size=2,stride=2。最后接GAP。

    Dropout:除了最后的mlpconv层外,其他层均使用dropout。

    正则化:所有权重应用L2正则化。

    数据集预处理和及其它训练过程与AlexNet类似。

 

NIN对比实验

    1. CIFAR-10数据集

    对这个数据集,作者应用了相同全局对比度归一化和ZCA白化进行处理,这和Maxout论文里的类似。训练时先通过验证集调整local receptive field size和weight decay,当确定好这两个超参数后,重新训练网络。

    首先测试有无dropout的影响,结果如下:

6.png

    从上图可以看到,在mlpconv层之间引入dropout可以减少20%以上的测试误差,因此这里所有测试的模型都加入了dropout。NIN无数据增强的情况下最终得到10.41%的测试错误率,加入数据增强后达到8.81%。如下图:

7.png

 

    2. CIFAR-100数据集

8.png

 

 

    3. Street View House Number数据集

9.png

 

    4. MNIST数据集

10.png

 

GAP对比实验

    GAP和FC类似,都是对向量化的特征映射进行线性转换,不同的地方是变换矩阵的不同。GAP的变换矩阵is prefixed and it is non-zero only on block diagonal elements which share the same value.(没理解)。FC有稠密的变换矩阵,变换矩阵的值由BP优化。FC和GAP对比如下:

11.png

    作者还探索了GAP在传统的CNN模型上是否也有更好的效果。比如将LeNet5改造,使其最后一个卷积层输出10通道特征图,然后用GAP替换FC+Dropout。在CIFAR-10上测试。

    结果对比:仅仅FC的测试错误率为17.56%,FC+Dropout的测试错误率为15.99%,GAP的测试错误率为16.46%。由此可知GAP具有正则化的作用。之所以比FC+Dropout差,作者说是因为GAP对线性卷积层的要求高,需要带ReLU的线性滤波器去建模类别置信度映射。

 

NIN可视化

    对CIFAR-10上的模型的特征图进行可视化。如下图:

12.png

    很明显最大激活的的特征图对应ground truth。可视化再次证明了NIN的有效性,它通过mlpconv层进行更强的局部接受域建模,全球平均池加强了类别级特征映射的学习。

 

 

代码实现

    使用tensorflow.slim,基于CIFAR-10数据集训练NIN网络。

  1. CIFAR-10数据集预处理
    import numpy as np from keras.datasets import cifar10 import keras num_classes=10 (x_train, y_train), (x_test, y_test) = cifar10.load_data() y_train = keras.utils.to_categorical(y_train, num_classes) # one-hot 编码 y_test = keras.utils.to_categorical(y_test, num_classes) # one-hot 编码 def color_preprocessing(x_train,x_test): x_train = x_train.astype('float32') x_test = x_test.astype('float32') mean = [125.307, 122.95, 113.865] std = [62.9932, 62.0887, 66.7048] for i in range(3): x_train[:,:,:,i] = (x_train[:,:,:,i] - mean[i]) / std[i] x_test[:,:,:,i] = (x_test[:,:,:,i] - mean[i]) / std[i] return x_train, x_test # 数据集减去均值,除以标准差 x_train, x_test = color_preprocessing(x_train, x_test)

    2.模型定义

    import tensorflow as tf from tensorflow.contrib.layers import xavier_initializer from tensorflow import name_scope as namespace slim = tf.contrib.slim REGULARIZER=0.0005 def NIN(inputs): with slim.arg_scope([slim.conv2d], stride=1, activation_fn=tf.nn.relu, padding='SAME', weights_initializer=xavier_initializer(), weights_regularizer=slim.l2_regularizer(REGULARIZER), biases_regularizer=slim.l2_regularizer(REGULARIZER), biases_initializer=tf.zeros_initializer()): net=inputs with namespace('mlpconv_1'): net = slim.conv2d(net, kernel_size=5,num_outputs=192,scope='mlpconv_1_conv') net = slim.conv2d(net, kernel_size=1,num_outputs=160,scope='mlpconv_1_conv1x1_1') net = slim.conv2d(net, kernel_size=1,num_outputs=96,scope='mlpconv_1_conv1x1_2') net=slim.max_pool2d(net,[3,3],2,padding='SAME',scope='maxpooling1') net = slim.dropout(net, 0.5, scope='dropout1') with namespace('mlpconv_2'): net = slim.conv2d(net, kernel_size=5,num_outputs=192,scope='mlpconv_2_conv') net = slim.conv2d(net, kernel_size=1,num_outputs=192,scope='mlpconv_2_conv1x1_1') net = slim.conv2d(net, kernel_size=1,num_outputs=192,scope='mlpconv_2_conv1x1_2') net=slim.max_pool2d(net,[3,3],2,padding='SAME',scope='maxpooling2') net = slim.dropout(net, 0.5, scope='dropout2') with namespace('mlpconv_3'): net = slim.conv2d(net, kernel_size=3,num_outputs=192,scope='mlpconv_3_conv') net = slim.conv2d(net, kernel_size=1,num_outputs=192,scope='mlpconv_3_conv1x1_1') net = slim.conv2d(net, kernel_size=1,num_outputs=10,scope='mlpconv_3_conv1x1_2') #GAP net= tf.reduce_mean(net, [1, 2], name='GAP', keep_dims=True) outputs=tf.squeeze(net,axis=[1,2],name='reshape',) return outputs

      3.模型配置

    from tensorflow import name_scope as namespace BATCH_SIZE=128 DATA_LEN=x_train.shape[0] x = tf.placeholder(tf.float32, shape=[None, 32, 32, 3], name='input') y_ = tf.placeholder(tf.float32, [None, 10], name='labels') global_step=tf.Variable(0,trainable=False) y=NIN(x) with namespace('loss'): #softmax并计算交叉熵 #print(y.get_shape().as_list() ) ce_loss = slim.losses.softmax_cross_entropy(y, y_) #交叉熵损失 regularization_loss = tf.add_n(slim.losses.get_regularization_losses())#正则损失 loss=ce_loss+regularization_loss with namespace('train'): #使用指数衰减学习率 learning_rate=tf.train.exponential_decay( 0.01,#初始学习率 global_step, DATA_LEN/BATCH_SIZE,#多少次更新一次学习率 0.99,#学习率衰减率 staircase=True#学习率阶梯下降 ) train_step=tf.train.MomentumOptimizer(learning_rate,0.9,#动量系数 ).minimize(loss,global_step=global_step) with namespace('acc'): correct_prediction=tf.equal(tf.argmax(y,1),tf.argmax(y_,1)) accuracy=tf.reduce_mean(tf.cast(correct_prediction,tf.float32)) tf.summary.scalar('loss',loss) tf.summary.scalar('accuracy',accuracy) merged=tf.summary.merge_all();

       4.模型训练,keras的数据生成器太好用了。

    #定义数据生成器 from keras.preprocessing import image import os import time epochs=30 TEST_STEP=int(x_test.shape[0]/BATCH_SIZE)-1 datagen = image.ImageDataGenerator( horizontal_flip=True, width_shift_range=0.125, height_shift_range=0.125, fill_mode='constant', cval=0.) datagen.fit(x_train) tg=datagen.flow(x_train, y_train, batch_size=BATCH_SIZE) with tf.Session() as sess: init_op=tf.global_variables_initializer() sess.run(init_op) writer=tf.summary.FileWriter('D:/Jupyter/cv/NIN_log',sess.graph) saver=tf.train.Saver() for i in range(epochs): start = time.clock() for j in range(int(DATA_LEN/BATCH_SIZE)): next_data,next_label=next(tg) summary,_,step=sess.run([merged,train_step,global_step],feed_dict={x:next_data,y_:next_label}) writer.add_summary(summary,step) loss_sum=0.0 acc_sum=0.0 for k in range(TEST_STEP): loss_value,acc=sess.run([loss,accuracy], feed_dict={x:x_test[k*BATCH_SIZE:(k+1)*BATCH_SIZE], y_:y_test[k*BATCH_SIZE:(k+1)*BATCH_SIZE]} ) loss_sum+=loss_value acc_sum+=acc elapsed = (time.clock() - start) print('epochs:%d loss:%f acc:%f time:%f'%(i,loss_sum/TEST_STEP,acc_sum/TEST_STEP,elapsed)) model_save_path = os.path.join(r'D:/Jupyter/cv/NIN_log', 'model.ckpt') saver.save(sess, save_path=model_save_path, global_step=i+1) writer.close()

     训练30轮的结果:

    r.png

     

     

     

    参考文献

    [1]Min Lin, Qiang Chen, Shuicheng Yan.Network In Network.

    [2] bryant_meng.【Keras-NIN】CIFAR-10. https://blog.csdn.net/bryant_meng/article/details/. 2018-11-23

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/231409.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • JedisConnectionException: java.net.ConnectException: Connection refused[通俗易懂]

    出现问题我遇到的一个问题,在连接redis的时候出现了错误!错误如下:JedisConnectionException: java.net.ConnectException: Connection refused看错误是 连接被拒绝,网上查了报这个错误的相关解决方案,没有一个可以解决的!问题就是上面的报错的问题,先说明一下我出现这个问题的背景或者环境吧。环境说明re…

    2022年2月27日
    50
  • Linux xsync命令脚本

    Linux xsync命令脚本在/bin/目录下创建xsync脚本如下:#!/bin/bash#1.判断参数个数if[$#-lt1]thenechoNotEnoughArguement!exit;fi#2.遍历集群所有机器forhostinmasternode1node2doecho====================$host====================#3.遍历所有目录,挨个发送forfilein$@do#4…

    2022年5月5日
    161
  • webpack和vue cli_vuecli webpack配置

    webpack和vue cli_vuecli webpack配置如何知道vue-cli创建的项目对应的webpack版本  找到项目下node_modules/webpack/package.json文件里的version字段即可知道

    2022年8月10日
    8
  • Promise的含义和用法「建议收藏」

    Promise的含义和用法「建议收藏」含义Promise是异步编程的一种解决方案。Promise对象有以下2个特点:1.对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:Pending(进行中)、Resolved(已完成)和Rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其…

    2022年5月30日
    33
  • 客户端网页编程导向

    客户端网页编程导向客户端网页编程导向

    2022年4月22日
    54
  • 泰勒展开式_常用泰勒公式大全图片

    泰勒展开式_常用泰勒公式大全图片数学中,泰勒公式是一个用函数在某点的信息描述其附近取值的公式。如果函数足够平滑的话,在已知函数在某一点的各阶导数值的情况之下,泰勒公式可以用这些导数值做系数构建一个多项式来近似函数在这一点的邻域中的值

    2022年8月4日
    7

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号