batchnormalization(BN)(多种角度),IN,LN,GN 的原理,公式,以及反向传播的推倒及代码
(参考自https://mp.weixin.qq.com/s?__biz=MzA4MjY4NTk0NQ==&mid=2247484478&idx=1&sn=10012618cc60f180c5e4fa1ef52d8d00&chksm=9f80bea8a8f737be7e2e3a2374731bcf89ac25238fcdf35fc6dde3157a12333b8c2864c568a2&scene=21#wechat_redirect)
BN

BN应用在判别模型中
首先BN层的作用是把经过relu等非线性激活函数作用后向极限饱和区靠拢的参数,强行拉回标准的正态分布,然后通过α和γ的作用起到一定的非线性性。
这是一般的理解,但是真的是这样吗???开始我就有疑惑,若是BN的作用是这样的话,那么BN肯定应该放在激活函数后面啊!但是很多文章包括最开始提出BN的文章BN 都是在激活函数之前的。这篇文章通过对比实验证明BN跟ics没有任何关系!!!!(在BN层后面加noisy引入一定的ics,但是效果跟使用了BN一样)
所以BN 层的作用到底是什么呢?

BN重新改变了优化问题,使得优化空间变得非常平滑。
对于没有BN的神经网络,其loss函数是不仅非凸,并且还有很多flat regions、sharp minimal。这就使得那些基于梯度的优化方法变得不稳定,因为很容易出现过大或者过小的梯度值。观察上图,可以发现,在使用了BN后,loss的变化变得更加稳定,不会出现过大的跳动;同样,梯度也变得更加平滑。
这是具体的公式推导,很简单。

所以总结一下:
BN层的作用:
1、使用了BN以后平滑了loss曲线,使得训练变得更快更稳定。
2、改进了ICS的作用(虽然实验证明了,但是很多人不信。。。)
3、消除了梯度消失的影响,可以使用更大的学习率,从而跳出不好的局部极值,增强泛化能力。
代码:
作者:BBuf
链接:https://zhuanlan.zhihu.com/p/108700076
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
def batchnorm_forward(x, gamma, beta, bn_param):
"""
Input:
- x: (N, D)维输入数据
- gamma: (D,)维尺度变化参数
- beta: (D,)维尺度变化参数
- bn_param: Dictionary with the following keys:
- mode: 'train' 或者 'test'
- eps: 一般取1e-8~1e-4
- momentum: 计算均值、方差的更新参数
- running_mean: (D,)动态变化array存储训练集的均值
- running_var:(D,)动态变化array存储训练集的方差
Returns a tuple of:
- out: 输出y_i(N,D)维
- cache: 存储反向传播所需数据
"""
mode = bn_param['mode']
eps = bn_param.get('eps', 1e-5)
momentum = bn_param.get('momentum', 0.9)
N, D = x.shape
# 动态变量,存储训练集的均值方差
running_mean = bn_param.get('running_mean', np.zeros(D, dtype=x.dtype))
running_var = bn_param.get('running_var', np.zeros(D, dtype=x.dtype))
out, cache = None, None
# TRAIN 对每个batch操作
if mode == 'train':
sample_mean = np.mean(x, axis = 0)
sample_var = np.var(x, axis = 0)
x_hat = (x - sample_mean) / np.sqrt(sample_var + eps)
out = gamma * x_hat + beta
cache = (x, gamma, beta, x_hat, sample_mean, sample_var, eps)
#滑动平均(影子变量)这种Trick的引入,目的是为了控制变量更新的速度,防止变量的突然变化对变量的整体影响,这能提高模型的鲁棒性。
running_mean = momentum * running_mean + (1 - momentum) * sample_mean
running_var = momentum * running_var + (1 - momentum) * sample_var
# TEST:要用整个训练集的均值、方差
elif mode == 'test':
x_hat = (x - running_mean) / np.sqrt(running_var + eps)
out = gamma * x_hat + beta
else:
raise ValueError('Invalid forward batchnorm mode "%s"' % mode)
bn_param['running_mean'] = running_mean
bn_param['running_var'] = running_var
return out, cache
下面我们着重来推导一下BN层的反向传播。
在说BN的反向计算之前,还得说一下BN的前向计算:
虽然有人说,有了公式你还不会前项计算吗?确实还是有一些需要注意的点的。
1、RGB三通道在计算BN值的时候,应该三个通道分别计算。
2、在训练的时候使用的均值跟方差是每个batch的,但是在测试的时候使用的是全部(训练数据)的均值跟方差,所以这里就需要使用一定得存储空间记下这些均值跟方差,但是若是训练数据太大的话,这可怎么办?这时候就需要使用滑动平均的方法,记忆一定量的均值方差,然后进行更新。
现在做一些约定:

最后的结果图:

代码
def batchnorm_backward(dout, cache):
"""
Inputs:
- dout: 上一层的梯度,维度(N, D),即 dL/dy
- cache: 所需的中间变量,来自于前向传播
Returns a tuple of:
- dx: (N, D)维的 dL/dx
- dgamma: (D,)维的dL/dgamma
- dbeta: (D,)维的dL/dbeta
"""
x, gamma, beta, x_hat, sample_mean, sample_var, eps = cache
N = x.shape[0]
dgamma = np.sum(dout * x_hat, axis = 0)
dbeta = np.sum(dout, axis = 0)
dx_hat = dout * gamma
dsigma = -0.5 * np.sum(dx_hat * (x - sample_mean), axis=0) * np.power(sample_var + eps, -1.5)
dmu = -np.sum(dx_hat / np.sqrt(sample_var + eps), axis=0) - 2 * dsigma*np.sum(x-sample_mean, axis=0)/ N
dx = dx_hat /np.sqrt(sample_var + eps) + 2.0 * dsigma * (x - sample_mean) / N + dmu / N
return dx, dgamma, dbeta
Instance Norm(IN)

IN应用在生成模型中
图片生成的结果主要依赖于某个图像实例,所以要对整个batch归一化不适合图像风格化中,在风格化迁移中使用IN不仅可以加速模型收敛,并且还能保持每个图像实例之间的独立。
前向传播代码如下,反向传播代码与BN类似。
import numpy as np
def Instancenorm(x,gamma,beta):
#x.shape():[B,C,H,W]
results = 0
eps = 1e-5
x_mean = np.mean(x,axis=(2,3),keepdims = True)
x_var = np.var(x,axis=(2,3),keepdims = True)
x_normalized =(x-x_mean)/np.sqrt(x_var+eps)
results = gamma*x_normalized+beta
return results
Layer Normalization(LN)

LN是对同一图片的同一层的所有通道进行normalization操作。LN主要用在NLP中。
前向传播代码如下,反向传播代码类似:
def Layernorm(x,gamma,beta):
#x.shape():[B,C,H,W]
results = 0
eps = 1e-5
x_mean = np.mean(x,axis=(1,2,3),keepdims = True)
x_var = np.var(x,axis=(1,2,3),keepdims = True)
x_normalized =(x-x_mean)/np.sqrt(x_var+eps)
results = gamma*x_normalized+beta
return results
Group Normalization(GN)

GN是指对同一张图片的同一层的某几个通道一起进行normalization操作。这几个通道称之为一个Group。
前向传播代码如下,反向传播代码类似:
def Layernorm(x,gamma,beta):
#x.shape():[B,C,H,W]
results = 0
eps = 1e-5
x = np.reshape(x,(x.shape[0],x.shape[1]/16,x.shape[2],x.shape[3])
x_mean = np.mean(x,axis=(2,3,4),keepdims = True)
x_var = np.var(x,axis=(2,3,4),keepdims = True)
x_normalized =(x-x_mean)/np.sqrt(x_var+eps)
results = gamma*x_normalized+beta
return results

本文深入探讨Batch Normalization(BN)、Instance Normalization(IN)、Layer Normalization(LN)与Group Normalization(GN)的原理、公式、反向传播推导及其在不同场景下的应用,如BN在判别模型中的优化问题改善、IN在生成模型中的图像风格迁移加速、LN在NLP中的多通道归一化以及GN在图像处理中的组内通道归一化。
743

被折叠的 条评论
为什么被折叠?



