复习笔记——基础为王,回顾基础,搞扎实是很有必要的,今天我抱着复习的目的和大家分享我理解的BN层,如有错误,欢迎批评指正以及补充.
本篇以复习为基础:模型训练之前,需对数据做归一化处理,使其分布一致。在深度神经网络训练过程中,通常一次训练是一个batch,而非全体数据。每个batch具有不同的分布产生了internal covarivate shift问题——在训练过程中,数据分布会发生变化,对下一层网络的学习带来困难。
当然对于工作麻木的我来说,应试笔试这种东西我大概率是不如应届生的,所以提前声明献丑了:
这里两个参数缩放因子和平移因子分别调整方差和均值。
那么在实际的模型运作中:
1.训练时,均值、方差是1个batch内的计算得到,是变化的。
2.推理时,均值和方差是基于所有batch计算得到的,是固定的,需要补充一个EMA指数加权。
而这两个参数如何更新呢?
就是梯度下降:一般是SGD或者ADAM迭代。
这里以个人相对熟悉的torch中的BN简单举例,因为在实际的代码中,通常会对基本原理的算法进行补充等优化:
在BN的类中,有如下参数:
def __init__(self, num_features, eps=1e-5, momentum=0.1, affine=True,track_running_stats=True):
momentum :设置为 None 时,使用 num_batches_tracked 计算每一轮更新的动量
eps:避免分母为0
num_features:输入通道数
affine:true就更新训练的两个因子,否则不更新
track_running_stats:true为:统计训练时输入的均值和方差
先根据上面公式和给的一些参数,代码如下:
x=torch.rand(8,3,10,10)
def bn_my(x,eps, weight, bias, momentum=0.1, mean=None, var=None, affine=True, track_running_stats=True):
if(track_running_stats):
mean=x.mean([0,2,3])
#print('mean shape:',mean.shape)
var=x.var([0,2,3],unbiased=False)#默认算无偏估计,因此需要手动设置unbiased=False
x = x - mean[None, ..., None, None]
x = x /torch.sqrt(var[None, ..., None, None]+eps)
out= x * weight[..., None, None] + bias[..., None, None]
# print('out:',out.shape)
return out
bn_my()
但实际中,其实我们只需要调包:nn.BatchNorm2d(num_features=3)就可以了哈
这里momentum参数没有用上,是因为它需要多次迭代多个Mini-batch更新动态的mean和var,当然在troch下还有一些比例参数的计算优化,这里不多介绍了,主要是复习下基础和一些概念原理的延伸,补充2个点:
BN越大往往我们的模型精度就会提升,但是显存是个硬伤,那么SYNCBN就是用来解决这个问题的,当你具备多个显卡可以满足使用较大BN去训练,这里说下我的理解:
多卡就是需要求所有卡对应的均值和方差,难点在于如何高效同步多个GPU的结果:
先说前向传播:
之前我在transformer系列的导读篇中介绍过BN和LN的区别,过多不介绍了,有兴趣的朋友自己看把,下面分享下在没有多卡情况下,我们需要用些trcik来进行优化:
提示:这里对文章进行总结:
大概过了下脑子里的BN概念,可能不够全面和精准,但是从机器学习的角度概括来说,BN其实就是网络逐层的调整数据的输出分布,其实验证明了和激活函数成了绝配,这里再总结下BN的作用: