1. 前言

Batch normalization 有多好用我就不多说了,一般来说,做卷积神经网络加上batch normalization,效果会得到一定的提升的。具体的batch normalization的原理可以参照(https://zhuanlan.zhihu.com/p/34879333)

我在他的基础上补充关于卷积神经网络使用Batch normalization的一些代码实现。以下的Batch normalization简称BN

2. contrib.slim中使用BN

使用Tensorflow搭建Inception v3模型的时候,是我第一次接触BN,了解了BN的那么多好处后,开始上手。实战的过程中,最大的感受就是:训练速度加快了很多,而且模型对学习率这种超参数不是很敏感

我们接下来在VGG16模型中引入BN,看看我们如何使用contrib.slim中自带的BN来搭建卷积神经网络。

接下来我们搭建VGG16的卷积基:

def VGG16_base(inputs,scope=None):with tf.variable_scope(scope,'VGG16',[inputs]):with slim.arg_scope([slim.conv2d],padding='SAME',stride=1,kernel_size=[3,3]):with slim.arg_scope([slim.max_pool2d],padding='SAME',stride=2,kernel_size=[2,2]):layer1=slim.conv2d(inputs,64,scope='conv_layer1')layer2=slim.conv2d(layer1,64,scope='conv_layer2')mp_layer1=slim.max_pool2d(layer2,scope='max_pool_layer1')layer3=slim.conv2d(mp_layer1,128,scope='conv_layer3')layerx4 = slim.conv2d(layer3, 128, scope='conv_layerx4')mp_layer2=slim.max_pool2d(layerx4,scope='max_pool_layer2')layer4=slim.conv2d(mp_layer2,256,scope='conv_layer4')layer5=slim.conv2d(layer4,256,scope='conv_layer5')layer6=slim.conv2d(layer5,256,scope='conv_layer6')mp_layer3=slim.max_pool2d(layer6,scope='max_pool_layer3')layer7=slim.conv2d(mp_layer3,512,scope='conv_layer7')layer8=slim.conv2d(layer7,512,scope='conv_layer8')layer9 = slim.conv2d(layer8, 512, scope='conv_layer9')mp_layer4= slim.max_pool2d(layer9, scope='max_pool_layer4')layer10 = slim.conv2d(mp_layer4, 512, scope='conv_layer10')layer11 = slim.conv2d(layer10, 512, scope='conv_layer11')layer12 = slim.conv2d(layer11, 512, scope='conv_layer12')mp_layer5= slim.max_pool2d(layer12, scope='max_pool_layer5')return  mp_layer5

我们这里使用了tensorflow中的contrib.slim包中的slim来搭建卷积层和池化层

嗯?不是说要在slim.conv2d中引入BN的嘛?BN呢?

别急嘛,我们知道tensorlfow中有个好东西,叫做slim.arg_scope。我们的BN是使用到所有的slim.conv2d中,如果我们在每个slim.conv2d中都加BN,就重复操作了,接下来我们使用slim.arg_scope来对上述所有定义的slim.conv2d中加入BN。

def VGG16_arg_scope(weight_decay=0.00004,stddev=0.1,batch_norm_var_collection='moving_vars'):batch_norm_params={'decay':0.9997,'epsilon':0.001,'updates_collections':tf.GraphKeys.UPDATE_OPS,'variables_collections':{'beta':None,'gamma':None,'moving_mean':[batch_norm_var_collection],'moving_variance':[batch_norm_var_collection],}}with slim.arg_scope([slim.conv2d,slim.fully_connected],weights_regularizer=slim.l2_regularizer(weight_decay)):with slim.arg_scope([slim.conv2d],weights_initializer=tf.truncated_normal_initializer(stddev=stddev),activation_fn=tf.nn.relu,normalizer_fn=slim.batch_norm,normalizer_params=batch_norm_params)as sc:return sc

上述代码中的:

with slim.arg_scope([slim.conv2d],weights_initializer=tf.truncated_normal_initializer(stddev=stddev),activation_fn=tf.nn.relu,normalizer_fn=slim.batch_norm,normalizer_params= batch_norm_params)as sc:return sc

这段代码就是对所有的slim.conv2d引入了BN,当然了,其中的batch_norm_params上面定义了,如下:

batch_norm_params={'decay':0.9997,'epsilon':0.001,'updates_collections':tf.GraphKeys.UPDATE_OPS,'variables_collections':{'beta':None,'gamma':None,'moving_mean':[batch_norm_var_collection],'moving_variance':[batch_norm_var_collection],}

既然使用BN,我们就一定要分清:is_training=True 或者is_training=False

训练的时候,一定要加slim.conv2d中的is_training设为True,而且我们刚刚只是设置了卷积基,我们还要后面接上全连接层嘞。

def VGG16(inputs,num_classes=config.NUM_CLASSES,is_training=True,reuse=None,scope='VGG16'):with tf.variable_scope(scope, 'VGG16', [inputs, num_classes], reuse=reuse) as scope:with slim.arg_scope([slim.batch_norm, slim.dropout],is_training=is_training):  # is_training 只会对batch_norm和dropout影响net = VGG16_base(inputs, scope=scope)reshape = tf.layers.flatten(net)# print(type(reshape))dim = reshape.get_shape()[1].valueprint(dim)with slim.arg_scope([slim.fully_connected],activation_fn=tf.nn.relu):fc_layer1=slim.fully_connected(reshape,2048,scope='fc_layer1')fc_layer2=slim.fully_connected(fc_layer1,512,scope='fc_layer2')logit=slim.fully_connected(fc_layer2,num_classes,scope='logit',activation_fn=None)return logit

这里我们设置了slim.batch_norm的is_training。这个slim. batch_norm是在slim.conv2d中设置的。

我们定义完了网络的结构的时候,现在我们在train和test要注意以下几点。

Train的时候,我们需要注意以下三点:

(1) 前向logit需要将上面定义的**VGG16_arg_scope()放在slim.arg_scope()**中,对所有的slim.conv2d采用BN。

with slim.arg_scope(VGG16_arg_scope()):logit=VGG16(image,num_classes=config.NUM_CLASSES,is_training=is_training)

(2)获取集合tf.GraphKeys.UPDATE_OPS ,并将update_op和train_op

同时进行。

update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS)
with tf.control_dependencies(update_ops):train_op=tf.train.AdamOptimizer(config.learning_rate).minimize(losses)

(3)保存变量(主要保存moving_meanmoving_variance

var_list = tf.trainable_variables()
# print('trainable variables',tf.trainable_variables)
g_list = tf.global_variables()
bn_moving_vars = [g for g in g_list if 'moving_mean' in g.name]
bn_moving_vars += [g for g in g_list if 'moving_variance' in g.name]
var_list += bn_moving_vars
saver = tf.train.Saver(var_list=var_list,max_to_keep=5)

测试的时候,is_training=False别忘了

with slim.arg_scope(VGG16_arg_scope()):logit = VGG16(image_batch, num_classes=config.NUM_CLASSES, is_training=False)

我在猫狗数据集上进行分类训练。最终在测试集上,不加BN的精度为89%,加了BN的精度为95%,而且训练速度提升,所有BN有多好,就不用多说了。

后面,我们来说第二种使用BN的方法。

3. tf.nn.batch_normalization的使用

tf.nn.batch_normalization的使用是在我阅读YOLO V2代码时遇到的。作者通过对yolo v1中加入BN,提升了mAP。

他是这样实现的,

首先代码中按照原始的tensorflow 的方法定义了卷积层:

def conv_layer(self, inputs, shape, batch_norm = True, name = '0_conv'):weight = tf.Variable(tf.truncated_normal(shape, stddev=0.1), name='weight')biases = tf.Variable(tf.constant(0.1, shape=[shape[3]]), name='biases')conv = tf.nn.conv2d(inputs, weight, strides=[1, 1, 1, 1], padding='SAME', name=name)if batch_norm:depth = shape[3]scale = tf.Variable(tf.ones([depth, ], dtype='float32'), name='scale')shift = tf.Variable(tf.zeros([depth, ], dtype='float32'), name='shift')mean = tf.Variable(tf.ones([depth, ], dtype='float32'), name='rolling_mean')variance = tf.Variable(tf.ones([depth, ], dtype='float32'), name='rolling_variance')conv_bn = tf.nn.batch_normalization(conv, mean, variance, shift, scale, 1e-05)conv = tf.add(conv_bn, biases)conv = tf.maximum(self.alpha * conv, conv)else:conv = tf.add(conv, biases)return conv

先定义权重,再定义偏置。

使用上一层的输入和定义的权重进行卷积运算,再将结果输入到tf.nn.batch_normalization中,这里我们需要好好品味下,它定义的几个变量,平均值、方差、scale和shift都是和输出维度相同的维度。这个是什么意思呢?很显然,我们在学习BN的时候,说过我们的均值和方差是求batch个神经元的平均值和方差,这里的维度说明了在卷积神经网络中,每一层(不是每层的每个格子)才是一个神经元。这里的均值和方差的计算,应该是对batch个特征图逐层进行求平均和求方差。

好了,定义了卷积函数后,我们引入darknet-19中的每个卷积层就好了。

def build_networks(self, inputs):net = self.conv_layer(inputs, [3, 3, 3, 32], name = '0_conv')net = self.pooling_layer(net, name = '1_pool')net = self.conv_layer(net, [3, 3, 32, 64], name = '2_conv')net = self.pooling_layer(net, name = '3_pool')net = self.conv_layer(net, [3, 3, 64, 128], name = '4_conv')net = self.conv_layer(net, [1, 1, 128, 64], name = '5_conv')net = self.conv_layer(net, [3, 3, 64, 128], name = '6_conv')net = self.pooling_layer(net, name = '7_pool')net = self.conv_layer(net, [3, 3, 128, 256], name = '8_conv')net = self.conv_layer(net, [1, 1, 256, 128], name = '9_conv')net = self.conv_layer(net, [3, 3, 128, 256], name = '10_conv')net = self.pooling_layer(net, name = '11_pool')net = self.conv_layer(net, [3, 3, 256, 512], name = '12_conv')net = self.conv_layer(net, [1, 1, 512, 256], name = '13_conv')net = self.conv_layer(net, [3, 3, 256, 512], name = '14_conv')net = self.conv_layer(net, [1, 1, 512, 256], name = '15_conv')net16 = self.conv_layer(net, [3, 3, 256, 512], name = '16_conv')net = self.pooling_layer(net16, name = '17_pool')net = self.conv_layer(net, [3, 3, 512, 1024], name = '18_conv')net = self.conv_layer(net, [1, 1, 1024, 512], name = '19_conv')net = self.conv_layer(net, [3, 3, 512, 1024], name = '20_conv')net = self.conv_layer(net, [1, 1, 1024, 512], name = '21_conv')net = self.conv_layer(net, [3, 3, 512, 1024], name = '22_conv')net = self.conv_layer(net, [3, 3, 1024, 1024], name = '23_conv')net24 = self.conv_layer(net, [3, 3, 1024, 1024], name = '24_conv') #这里输出为(h/32,w/32,1024)net = self.conv_layer(net16, [1, 1, 512, 64], name = '26_conv')net = self.reorg(net)  #输出shape为(h/32,w/32,64*4)net = tf.concat([net, net24], 3) #拼接,shape为(bz,h/32,w/32,1024+256)net = self.conv_layer(net, [3, 3, int(net.get_shape()[3]), 1024], name = '29_conv')  #转(bz,h/32,w/32,1024)net = self.conv_layer(net, [1, 1, 1024, self.box_per_cell * (self.num_class + 5)], batch_norm=False, name = '30_conv') #转(bz,h/32,w/32,5*(num_classes+5))return net

4. 小结

我们讲完了BN后,读者可以自行尝试他的效果,虽然听说GN,即group normalization也出了,但是我还没有试过,以后尝试了再做个总结吧。

建议阅读:

高考失利之后,属于我的大学本科四年

【资源分享】对于时间序列,你所能做的一切.

【时空序列预测第一篇】什么是时空序列问题?这类问题主要应用了哪些模型?主要应用在哪些领域?

【AI蜗牛车出品】手把手AI项目、时空序列、时间序列、白话机器学习、pytorch修炼

公众号:AI蜗牛车

保持谦逊、保持自律、保持进步

个人微信

备注:昵称+学校/公司+方向

如果没有备注不拉群!

拉你进AI蜗牛车交流群

Batch Normalization 的实战使用相关推荐

  1. Lesson 14.3 Batch Normalization综合调参实战

    Lesson 14.3 Batch Normalization综合调参实战   根据Lesson 14.2最后一部分实验结果不难看出,带BN层的模型并不一定比不带BN层模型效果好,要充分发挥BN层的效 ...

  2. Batch Normalization原理与实战

    作者:天雨粟 链接:https://zhuanlan.zhihu.com/p/34879333 来源:知乎 著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 前言 本期专栏主要来从 ...

  3. batch normalization

    20210702 深度学习中的五种归一化(BN.LN.IN.GN和SN)方法简介 https://blog.csdn.net/u013289254/article/details/99690730 h ...

  4. Batch Normalization的诅咒

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 作者:Sahil Uppal 编译:ronghuaiyang 导读 ...

  5. Batch Normalization应该放在ReLU非线性激活层的前面还是后面?

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 编辑:CVDaily  转载自:计算机视觉Daily https: ...

  6. Batch Normalization 学习笔记

    转载自:http://blog.csdn.net/hjimce/article/details/50866313 可参阅:知乎http://www.zhihu.com/question/3810276 ...

  7. 解读Batch Normalization

    [活动]Python创意编程活动开始啦!!!     CSDN日报20170424 --<技术方向的选择>    程序员4月书讯:Angular来了! 解读Batch Normalizat ...

  8. Batch Normalization批量归一化

    深度学习捷报连连.声名鹊起,随机梯度下降成了训练深度网络的主流方法.尽管随机梯度下降法对于训练深度网络简单高效,但是它有个毛病,就是需要我们人为的去选择参数,比如学习率.参数初始化.权重衰减系数.Dr ...

  9. 【深度学习】Batch Normalization详解

    Batch Normalization 学习笔记 原文地址:http://blog.csdn.net/hjimce/article/details/50866313 作者:hjimce 一.背景意义 ...

最新文章

  1. python 单元测试_聊聊 Python 的单元测试框架(一):unittest
  2. 深入理解jQuery的Event机制
  3. 9.VMware View 4.6安装与部署-connection server(View Replica Server)
  4. pytorch 训练过程acc_深度学习Pytorch实现分类模型
  5. 互联网1分钟 |1220
  6. The parent project must have a packaging type of POM
  7. onload与ready差异
  8. 智能平台管理接口 (IPMI)
  9. MIT 线性代数习题
  10. linux卸载nvdia驱动_Ubuntu 卸载 Nvidia 驱动和安装最新驱动
  11. 手把手教你修改iOS版QQ的运动步数
  12. 认知系列3: 看看资深研发工程师的思维模式
  13. excel 取消合并单元格
  14. 实验中应该遵循的几个原则
  15. [MQ]消息队列与企业服务总线的简单比较,MQESB
  16. 免费在线汉字简体繁体转换工具
  17. 开源B2B2C WSTMart商城系统开发框架及插件介绍
  18. ubuntu中静态ip的修改配置
  19. C++一行输入多个数字(利用cin和空格)
  20. OpenGL显示文字--显示英文

热门文章

  1. 深度评测小米笔记本 Pro 14/15 增强版 2021款 怎么样
  2. 煤矿皮带急停识别检测 opencv
  3. Pycharm的安装与环境配置
  4. 使用DelayQueue模拟订单超时自动取消
  5. 使用 Typora 编辑 Markdown 文件时插入链接的方式
  6. 解决:IIS 假死,运行一段时间服务器上所有网站打不开,必须要重启服务器才行,重启IIS都没用。怎么解决,解决方案
  7. clique共识机制流程及#17620 bug修复理解
  8. 终于用Matlab程序得到了跟TA的Q100结果类似的Modulated heat flow的Amplitude
  9. qdir 类似工具_如何高效率整理电脑上的文件 ?
  10. severlet学习