神经网络中的两种正则化---Batch Normalization和Weight Normalization

Batch Normalization

原理

BN是对小批量数据进行正则化,其算法原理如下:
神经网络中的两种正则化---Batch Normalization和Weight Normalization_第1张图片
我们可以理解为BN的本质就是一个以 γ \gamma γ β \beta β为参数,从 x i x_i xi y i y_i yi的映射。即:
B N γ β : x i . . . m → y i . . . m BN_{\gamma\beta}:x_{i...m} \rightarrow y_{i...m} BNγβ:xi...myi...m
其反向传播如下:
神经网络中的两种正则化---Batch Normalization和Weight Normalization_第2张图片

BN在测试时的使用

在测试时,均是使用单个样本进行检测。运行到BN层时使用的均值和方差均是来自于训练样本,随机抽取多个批次,每个批次的大小都是m,进行计算。即:
E ( x ) ← E ( μ B ) E(x) \leftarrow E(\mu_{\Beta}) E(x)E(μB)
V a r ( x ) ← m − 1 m E ( σ B 2 ) Var(x) \leftarrow \frac{m-1}{m}E(\sigma^{2}_{\Beta}) Var(x)mm1E(σB2)
当然,这样比较麻烦,需要大量的计算。所以在训练时就将均值和方差保存下来,并通过滑动平均(moving average)进行更新。其中的均值和方差分别成为滑动均值 E m o v i n g E_{moving} Emoving和滑动方差 V a r m o v i n g Var_{moving} Varmoving
E m o v i n g ( x ) = m ∗ E m o v i n g ( x ) + ( 1 − m ) ∗ E s a m p l e E_{moving}(x)=m*E_{moving}(x)+(1-m)*E_{sample} Emoving(x)=mEmoving(x)+(1m)Esample
V a r m o v i n g ( x ) = m ∗ V a r m o v i n g ( x ) + ( 1 − m ) ∗ V a r s a m p l e Var_{moving}(x)=m*Var_{moving}(x)+(1-m)*Var_{sample} Varmoving(x)=mVarmoving(x)+(1m)Varsample
E s a m p l e E_{sample} Esample为采样均值, V a r s a m p l e Var_{sample} Varsample为采样方差,此处的m为遗忘因子momentum,默认为0.99.
根据参数 γ \gamma γ β \beta β和上述方式得到:
y = γ x − u V a r ( x ) + ϵ + β y = \gamma\frac{x-u}{\sqrt{Var(x)+\epsilon}}+\beta y=γVar(x)+ϵ xu+β

CNN中的BN

对于卷积,BN是以feature map为单位,对于 s h a p e = m ∗ p ∗ q ∗ d shape=m*p*q*d shape=mpqd的输入,每个feature map计算 m ∗ p ∗ q m*p*q mpq个数据,有d组参数 γ \gamma γ β \beta β

示例

[1]. Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift

Weight Normalization

理论:

WN是将权重进行归一化,这个明显区别于BN对数据进行归一化的方式。BN将miniBatch的局部归一化作为全局归一化,进而引入噪声,而WN则没有这个问题,因此WN除了可以应用于CNN,还可以应用于RNN、生成网络和深度强化学习等对噪声敏感的学习中。
一个神经网络节点:
y = ϕ ( w x + b ) y =\phi(wx+b) y=ϕ(wx+b)
在SGD过程中,将参数 w w w解藕为欧式范数 g g g和方向向量 v v v,则
w = g ∣ ∣ v ∣ ∣ v w = \frac{g}{||v||}v w=vgv
在反向传播中, g g g v v v都是损失函数 L L L的参数。则其计算方式:
神经网络中的两种正则化---Batch Normalization和Weight Normalization_第3张图片
或者另外一种表达方式:
神经网络中的两种正则化---Batch Normalization和Weight Normalization_第4张图片
它能够达成两个目标:

  1. 通过 g / ∣ ∣ v ∣ ∣ g/||v|| g/v缩放权重梯度
  2. 远离当前的权重梯度 ▽ w L \triangledown_wL wL
    这些都可以加速收敛,这个类似于优化器中的Momentum或者Adam[2],虽然没有严格意义上对不同参数学习不同的学习率,但是效果上是相似的。

参数的数据依赖初始化

BN每次的缩放都是根据数据进行的,因此优化时,具有很强的鲁棒性。WN则没有这个特征。因此初始化就变得非常重要。
对于每个神经元:
神经网络中的两种正则化---Batch Normalization和Weight Normalization_第5张图片
神经网络中的两种正则化---Batch Normalization和Weight Normalization_第6张图片
其中 μ \mu μ σ \sigma σ分别是预激活t的均值和标准差。
v v v使用均值为0,标准差为0.05的正态分布;
g g g b b b分别是第一批样本的统计量进行初始化;

示例

全连接层

def dense(x_, n_filters,init_scaler=1, init=False):
    V = tf.get_variable("v", shape=[x_.shape[-1], n_filters], dtype=tf.float32, initializer=tf.random.normal(0,0.05), trainable=True)
    g = tf.get_variable("g", shape=[n_filters], dtype=tf.float32, initializer=tf.constant_initializer(1.), trainable=True)
    b = tf.get_variable("b", shape=[n_filters], dtype=tf.float32, initializer=tf.constant_initializer(0.), trainable=True)

    # x与方向向量相乘
    x = tf.matmul(x_,V)
    # 缩放系数
    scaler = g/tf.sqrt(tf.reduce_mean(tf.square(V), [0]))
    x = tf.reshape(scaler, [1, n_filters]) * x + tf.reshape(b, [1,n_filters])

    if init:
        # 第一批样本的均值和方差
        init_mean, init_v = tf.nn.moments(x, [0])
        # 初始化的缩放系数
        init_scaler = init_scaler/tf.sqrt(init_v+1e-10)
        # 利用tf.control_dependencies控制计算流图,先执行g*init_scaler赋值给g和-init_mean*init_scaler赋值给b的两个操作,完成g和b的初始化,再执行之后的。
        with tf.control_dependencies([g.assign(g*init_scaler), b.assign_add(-init_mean*init_scaler)]):
            x = tf.matmul(x_,V)
            scaler = g / tf.sqrt(tf.reduce_mean(tf.square(V), [0]))
            x = tf.reshape(scaler, [1, n_filters]) * x + tf.reshape(b, [1, n_filters])

    return x

卷基层

def conv2d(x_, n_filters, filter_size=[3,3], stride=[1,1], pad="SAME",init_scaler=1, init=False):
    V = tf.get_variable("v", shape=filter_size+[x_.shape[-1], n_filters], dtype=tf.float32,
                        initializer=tf.random.normal(0, 0.05), trainable=True)
    g = tf.get_variable("g", shape=[n_filters], dtype=tf.float32, initializer=tf.constant_initializer(1.),
                        trainable=True)
    b = tf.get_variable("b", shape=[n_filters], dtype=tf.float32, initializer=tf.constant_initializer(0.),
                        trainable=True)

    # weight normalization
    w = tf.reshape(g,[1,1,1,n_filters]) * tf.nn.l2_normalize(V, [0,1,2])
    # 计算conv2d
    x = tf.nn.bias_add(tf.nn.conv2d(x_, w, [1]+stride+[1], pad) + b)

    # init
    if init:
        # 第一批样本的均值和方差
        init_mean, init_v = tf.nn.moments(x, [0,1,2])
        # 初始化缩放系数
        init_scaler = init_scaler/tf.sqrt(init_v+1e-10)
        with tf.control_dependencies([g.assign(g*init_scaler), b.assign_add(-init_mean*init_scaler)]):
            # weight normalization
            w = tf.reshape(g, [1, 1, 1, n_filters]) * tf.nn.l2_normalize(V, [0, 1, 2])
            # 计算conv2d
            x = tf.nn.bias_add(tf.nn.conv2d(x_, w, [1] + stride + [1], pad) + b)
    
    return x

参考:
[1]. Weight Normalization: A Simple Reparameterization to Accelerate Training of Deep Neural Networks
[2]. An overview of gradient descent optimization algorithms
[3]. openAI/WeightNormal

你可能感兴趣的:(tensorflow,深度学习,BN,WN)