基础 | batchnorm原理及代码详解

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/qq_25737169/article/details/79048516

前言:Batchnorm是深度网络中经常用到的加速神经网络训练,加速收敛速度及稳定性的算法,可以说是目前深度网络必不可少的一部分。
本文旨在用通俗易懂的语言,对深度学习的常用算法–batchnorm的原理及其代码实现做一个详细的解读。本文主要包括以下几个部分。

  • Batchnorm主要解决的问题
  • Batchnorm原理解读
  • Batchnorm的优点
  • Batchnorm的源码解读

第一节:Batchnorm主要解决的问题


首先,此部分也即是讲为什么深度网络会需要 b a t c h n o r m b a t c h n o r m b a t c h n o r m batchnormbatchnorm batchnorm batchnormbatchnormbatchnormγ分别称之为 平移参数和缩放参数 。这样就保证了每一次数据经过归一化后还保留的有学习来的特征,同时又能完成归一化这个操作,加速训练。

先用一个简单的代码举个小栗子:

def Batchnorm_simple_for_train(x, gamma, beta, bn_param):
"""
param:x    : 输入数据,设shape(B,L)
param:gama : 缩放因子  γ
param:beta : 平移因子  β
param:bn_param   : batchnorm所需要的一些参数
	eps      : 接近0的数,防止分母出现0
	momentum : 动量参数,一般为0.9, 0.99, 0.999
	running_mean :滑动平均的方式计算新的均值,训练时计算,为测试数据做准备
	running_var  : 滑动平均的方式计算新的方差,训练时计算,为测试数据做准备
"""
	running_mean = bn_param['running_mean']  #shape = [B]
    running_var = bn_param['running_var']    #shape = [B]
	results = 0. # 建立一个新的变量
x_mean=x.mean(axis=0)  # 计算x的均值
x_var=x.var(axis=0)    # 计算方差
x_normalized=(x-x_mean)/np.sqrt(x_var+eps)       # 归一化
results = gamma * x_normalized + beta            # 缩放平移

running_mean = momentum * running_mean + (1 - momentum) * x_mean
running_var = momentum * running_var + (1 - momentum) * x_var

#记录新的值
bn_param['running_mean'] = running_mean
bn_param['running_var'] = running_var 

return results , bn_param
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

看完这个代码是不是对batchnorm有了一个清晰的理解,首先计算均值和方差,然后归一化,然后缩放和平移,完事!但是这是在训练中完成的任务,每次训练给一个批量,然后计算批量的均值方差,但是在测试的时候可不是这样,测试的时候每次只输入一张图片,这怎么计算批量的均值和方差,于是,就有了代码中下面两行,在训练的时候实现计算好 m e a n m e a n m e a n meanmean mean meanmeanmeanvar测试的时候直接拿来用就可以了,不用计算均值和方差。

running_mean = momentum * running_mean + (1 - momentum) * x_mean
running_var = momentum * running_var + (1 - momentum) * x_var

 
 
  • 1
  • 2

所以,测试的时候是这样的:

def Batchnorm_simple_for_test(x, gamma, beta, bn_param):
"""
param:x    : 输入数据,设shape(B,L)
param:gama : 缩放因子  γ
param:beta : 平移因子  β
param:bn_param   : batchnorm所需要的一些参数
	eps      : 接近0的数,防止分母出现0
	momentum : 动量参数,一般为0.9, 0.99, 0.999
	running_mean :滑动平均的方式计算新的均值,训练时计算,为测试数据做准备
	running_var  : 滑动平均的方式计算新的方差,训练时计算,为测试数据做准备
"""
	running_mean = bn_param['running_mean']  #shape = [B]
    running_var = bn_param['running_var']    #shape = [B]
	results = 0. # 建立一个新的变量
x_normalized=(x-running_mean )/np.sqrt(running_var +eps)       # 归一化
results = gamma * x_normalized + beta            # 缩放平移

return results , bn_param
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

你是否理解了呢?如果还没有理解的话,欢迎再多看几遍。

第三节:Batchnorm源码解读


本节主要讲解一段tensorflow中 B a t c h n o r m B a t c h n o r m B a t c h n o r m BatchnormBatchnorm Batchnorm BatchnormBatchnormBatchnorm3,如下:
代码来自知乎,这里加入注释帮助阅读。

def batch_norm_layer(x, train_phase, scope_bn):
    with tf.variable_scope(scope_bn):
		# 新建两个变量,平移、缩放因子
        beta = tf.Variable(tf.constant(0.0, shape=[x.shape[-1]]), name='beta', trainable=True)
        gamma = tf.Variable(tf.constant(1.0, shape=[x.shape[-1]]), name='gamma', trainable=True)
    # 计算此次批量的均值和方差
    axises = np.arange(len(x.shape) - 1)
    batch_mean, batch_var = tf.nn.moments(x, axises, name='moments')

	# 滑动平均做衰减
    ema = tf.train.ExponentialMovingAverage(decay=0.5)

    def mean_var_with_update():
        ema_apply_op = ema.apply([batch_mean, batch_var])
        with tf.control_dependencies([ema_apply_op]):
            return tf.identity(batch_mean), tf.identity(batch_var)
    # train_phase 训练还是测试的flag
	# 训练阶段计算runing_mean和runing_var,使用mean_var_with_update()函数
	# 测试的时候直接把之前计算的拿去用 ema.average(batch_mean)
    mean, var = tf.cond(train_phase, mean_var_with_update,
                        lambda: (ema.average(batch_mean), ema.average(batch_var)))
    normed = tf.nn.batch_normalization(x, mean, var, beta, gamma, 1e-3)
return normed
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

至于此行代码tf.nn.batch_normalization()就是简单的计算batchnorm过程啦,代码如下:
这个函数所实现的功能就如此公式: γ ( x − μ ) σ + β γ ( x − μ ) σ + β γ ( x − μ ) σ + β γ(x−μ)σ+βγ(x−μ)σ+β \frac{\gamma(x-\mu)}{\sigma}+\beta γ(xμ)σ+βγ(xμ)σ+βσγ(xμ)+βσγ(xμ)+β

def batch_normalization(x,
                        mean,
                        variance,
                        offset,
                        scale,
                        variance_epsilon,
                        name=None):
with ops.name_scope(name, "batchnorm", [x, mean, variance, scale, offset]):
    inv = math_ops.rsqrt(variance + variance_epsilon)
    if scale is not None:
        inv *= scale
    return x * inv + (offset - mean * inv
                  if offset is not None else -mean * inv)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

第四节:Batchnorm的优点

主要部分说完了,接下来对BatchNorm做一个总结:

  • 没有它之前,需要小心的调整学习率和权重初始化,但是有了BN可以放心的使用大学习率,但是使用了BN,就不用小心的调参了,较大的学习率极大的提高了学习速度,
  • Batchnorm本身上也是一种正则的方式,可以代替其他正则方式如dropout等
  • 另外,个人认为,batchnorm降低了数据之间的绝对差异,有一个去相关的性质,更多的考虑相对差异性,因此在分类任务上具有更好的效果。

注:或许大家都知道了,韩国团队在2017NTIRE图像超分辨率中取得了top1的成绩,主要原因竟是去掉了网络中的batchnorm层,由此可见,BN并不是适用于所有任务的,在image-to-image这样的任务中,尤其是超分辨率上,图像的绝对差异显得尤为重要,所以batchnorm的scale并不适合。

参考文献:
【1】http://blog.csdn.net/zhikangfu/article/details/53391840
【2】http://geek.csdn.net/news/detail/160906
【3】 https://www.zhihu.com/question/53133249



对机器学习和人工智能感兴趣,请扫码关注微信公众号!
![在这里插入图片描述](https://img-blog.csdnimg.cn/20181226215124368.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzI1NzM3MTY5,size_16,color_FFFFFF,t_70)
                                </div>
            <link href="https://csdnimg.cn/release/phoenix/mdeditor/markdown_views-095d4a0b23.css" rel="stylesheet">
                </div>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值