一、前言
随着深度学习的发展,为了探索是否层数越多预测越准确,学者们进行了诸多实验,最后发现当层数到达某个值时期预测精度不升反降。而后,BatchNorm出现在一定程度解决了这个问题。
在使用Sigmoid函数后,其在x∈[-2,2]的区间的导数在[0.1,0.25]区间,这就容易在梯度更新的过程中出现梯度弥散的现象,而在进行BatchNorm后,函数值会分布在0附近,且梯度不至于过小,从而在一定程度上解决了梯度弥散的问题。
如上图,较之未标准化的权值,右图(标准化)收敛更加迅速,且优化路径更加理性。
二、BN层
对每个channel求mean和std,再进行标准化,使其分布在0-1区间。其还有一个缩放因子γ,位移因子β
在训练模式下:
1. 前向传播的mean和std会向真实数据的mean和std靠近
2. 反向传播会对β和γ进行更新
在测试模式下上述参数不变
BN默认:
axix=-1(对channel进行)
center=true >>β参数
scale=true >>γ参数
trainable=true
三、实例理解
引入模块:
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers, optimizers
定义2 张图片 4*4 3通道
使其数值服从正态分布N(1, 0.5):
x = tf.random.normal([2,4,4,3], mean=1.,stddev=0.5)
定义BN层:
net = layers.BatchNormalization(axis=-1, center=True, scale=True,
trainable=True)
out = net(x)
print('forward in test mode:', net.variables)
进行一次BN操作并查看其mean和std:
out = net(x, training=True)
print('forward in train mode(1 step):', net.variables)
进行100次BN操作:(结果可看到mean与std不断接近1和0,5)
for i in range(100):
out = net(x, training=True)
print('forward in train mode(100 steps):', net.variables)
进行反向传播:(可看到β和γ的变化)
optimizer = optimizers.SGD(lr=1e-2)
for i in range(10):
with tf.GradientTape() as tape:
out = net(x, training=True)
loss = tf.reduce_mean(tf.pow(out,2)) - 1
grads = tape.gradient(loss, net.trainable_variables)
optimizer.apply_gradients(zip(grads, net.trainable_variables))
print('backward(10 steps):', net.variables)
完整代码:
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers, optimizers
# 2 images with 4x4 size, 3 channels
# we explicitly enforce the mean and stddev to N(1, 0.5)
x = tf.random.normal([2,4,4,3], mean=1.,stddev=0.5)
net = layers.BatchNormalization(axis=-1, center=True, scale=True,
trainable=True)
out = net(x)
print('forward in test mode:', net.variables)
out = net(x, training=True)
print('forward in train mode(1 step):', net.variables)
for i in range(100):
out = net(x, training=True)
print('forward in train mode(100 steps):', net.variables)
optimizer = optimizers.SGD(lr=1e-2)
for i in range(10):
with tf.GradientTape() as tape:
out = net(x, training=True)
loss = tf.reduce_mean(tf.pow(out,2)) - 1
grads = tape.gradient(loss, net.trainable_variables)
optimizer.apply_gradients(zip(grads, net.trainable_variables))
print('backward(10 steps):', net.variables)
四、BN层优点
- 收敛速度↑
- 更好的表现
- 更稳定
知识来自: