大家好我是栗子鑫,今天主要介绍一下笔者在秋招的面试某厂的时候,面试真题:DL中的归一化有哪些?
遇到了这个问题,笔者主要主要回答了BN,LN,IN,GN以及SN,介绍了其内容及其特点。下文将介绍这几种归一化,文末附源码。
在介绍各个算法之前引入一个问题:为什么深度学习需要归一化?
神经网络学习过程的本质就是为了学习数据分布,如果我们没有做归一化处理,那么每一批次训练数据的分布不一样,则网络结构需要在多个batch中找到平衡点,这样就导致网络很难收敛。同时经过归一化的数据其损失函数的等高线图更接近圆形,梯度下降的方向震荡更小,收敛更快。
01
—
BN (Batch Normalization)
笔者上一篇“面经”对BN有详细介绍,感兴趣的朋友可以点击下面的链接查看。
02
—
LN (Layer Normalization)
LN的思想与BN非常类似,只是BN是在每个神经元对一个mini batch大小的样本进行规范化,而LN则是在每一层对单个样本的所有神经元节点进行规范化。
LN的具体内容举个🌰说明:
对于一个RNN系列的神经网络,对于前向神经网络的第隐藏层,假设为第层的输入向量,H表示隐藏单元的数量,则 LN 的均值和方差统计量为(同一层所有的单元共享均值和方差):
则对输入向量进行层标准化,再进行 缩放和平移(用于恢复非线性)标准化后输入:
为当前层的输入和上一层的隐藏状态加权而来。
LN特点
LN主要是针对单个训练样本训练,不需要像BN中对一个批次的样本来做训练,因此可以避免 BN 中受 mini-batch 数据分布影响的问题,可以用于 BN不擅长的小mini-batch场景、动态网络场景和 RNN,特别是自然语言处理领域。此外,LN 不需要保存 mini-batch 的均值和方差,节省了额外的存储空间。
03
—
IN (Instance Normalization)
IN和BN一样,也是Normalization的一种方法,只是IN是作用于单张图片,但是BN作用于一个Batch。
BN对Batch中的每一张图片的同一个通道一起进行Normalization操作,而IN是指单张图片的单个通道单独进行Normalization操作。IN针对图像像素做normalization,最初用于图像的风格化迁移。在图像风格化中,生成结果主要依赖于某个图像实例,feature map 的各个 channel 的均值和方差会影响到最终生成图像的风格。具体内容如下
IN 对每个样本的 H、W 维度的数据求均值和标准差,保留 N 、C 维度,也就是说,它只在 channel 内部求均值和标准差,其公式如下:
其中 H,W代表图像的高度和宽度,i代表channel,t代表batchsize
IN的特点
IN本身是一个非常简单的算法,尤其适用于批量较小且单独考虑每个像素点的场景中,因为其计算归一化统计量时没有混合批量和通道之间的数据,可以考虑使用IN。
04
—
GN (Group Normalization)
GN是为了解决BN对较小的mini-batch size效果差的问题。GN适用于训练网络需要占用显存比较大的任务,同时受设备限制,例如图像分割。对这类任务,可能 batch size 需要设置很大,而当 batch size 是个位数时,BN 的表现很差,因为没办法通过几个样本的数据量,来近似总体的均值和标准差。GN 也是独立于 batch 的,它是 LN 和 IN 的折中,主要内容如下:
GN的主要思想:在 channel 方向 group,然后每个 group 内做 Norm,计算 的均值和方差,这样就与batch size无关,不受其约束。
具体方法:GN 计算均值和标准差时,把每一个样本 feature map 的 channel 分成 G 组,每组将有 C/G 个 channel,然后将这些 channel 中的元素求均值和标准差。各组 channel 用其对应的归一化参数独立地归一化。
G为分了几组
GN特点
GN的归一化方式避开了batch size对模型的影响,特征的group归一化同样可以解决 的问题,并取得较好的效果。
05
—
SN (Switchable Normalization)
在回答这道面试题的时候并没有了解到这个SN,笔者在面试复盘的时候了解了一下SN,上文绍了BN,LN,IN以及GN的算法细节及适用的任务。虽然这些归一化方法往往能提升模型的性能,但是当你接收一个任务时,具体选择哪个归一化方法仍然需要经验去设计,这往往需要大量的对照实验或者开发者优秀的经验才能选出最合适的归一化方法。SN的提出解决了上述问题,将 BN、LN、IN 结合,赋予权重,让网络自己去学习归一化层应该使用什么方法。下图引入一篇知乎博客的图片来介绍SN:

SN的计算公式与上述的几种归一化方式的计算公式相似,首先计算均值和方差,然后通过缩放和偏置来获取归一后的结果,只是计算的均值和方差所不同,SN的统计量计算了BN,LN,IN三种的统计量,所以要引入6个权值参数(主要对应三种归一化的均值和方差)计算加权的均值和加权的方差作为SN的均值和方差,加权系数使用了Softmax进行归一化:
SN在测试阶段和BN的测试阶段有所不同:在测试阶段,IN和LN都是正常计算,它们不依赖于其他样本。在BN时,以前的方式是在训练过程中的统计均值和方差的滑动平均值在测试时使用。SN论文中提出了批量平均方式,具体过程是,冻结所有的参数,从训练集中随机抽取一定数量的样本,计算SN的均值和方差,然后使用他们的平均值作为BN的统计值。
SN特点
针对不同任务,SN可以自适应不同的任务,通过学习选择与任务合适的权值,在不同层也可以使用不同的权值,灵活性强,缺点显而易见难训练。
05
—
四种归一化的对比
这里主要对比BN、IN、LN以及GN。
下图引入GN论文图:

可见每一种归一化的方式都有所不同,可能读到这里,有些读者还是分不清楚,这里借用一个🌰来说明:
假设有N本一样的数据,每一本书籍有C页,每一页有H行,每一行有W个字:
BN是将所有书籍的相同的某一页的所有字数加起来 即为
IN是将一本书籍的某一页的所有字数加起来 即为
LN是将一本的每一页的所有字数加起来 即为
GN是将每一本书分G个小组 然后对每一个小组做LN 即为
使用场景对比:
BN:常用在计算机视觉任务中,比如图像分类,目标检测,图像分割等,每个mini-batch比较大,数据分布比较接近。
LN:常用在RNN网络,但如果输入的特征区别很大,那么就不建议使用它做归一化处理
IN:常用在风格化迁移,但如果特征图可以用到通道之间的相关性,那么就不建议使用它做归一化处理
GN:GN若分组设置为1,则GN转化为LN,如果分组设置为C,则GN变为IN,代表GN和IN和LN都有联系,这两种标准化方法在训练循环(RNN / LSTM)或生成(GAN)模型方面特别成功。所以GN也适用于这两个场景。
SN: 笔者未使用过,原论文中结果表示更适用于视觉任务中。
06
—
总结
深度学习中归一化笔者已经大致总结了,这也是面试遇到的真题,如果读者想更深一步去了解,则需要阅读原论文去了解。祝大家早日拿到心仪的offer。
07
—
源码
-
BN 不再详细介绍
-
LN
import torch
def layer_norm_process(feature:torch.tensor,beta=0.,gamma=1.0,eps=1e-5):
'''
:param feature: N * C * H * W
:param beta:
:param gamma:
:param eps:
:return:
'''
var_mean = torch.var_mean(feature,dim=[1,2,3],unbiased=False)
var = var_mean[0]
mean = var_mean[1]
#ln归一化
feature = (feature - mean[:,None,None,None]) / torch.sqrt(var[:,None,None,None]+eps)
feature = gamma * feature + beta
return feature -
IN
import torch
def IN_process(p:torch.tensor,eps=1e-5):
"""
:param p: N * C * H * W
:param eps:
:return:
"""
var_mean = torch.var_mean(p,dim=[2,3],unbiased=False)
var = var_mean[0]
mean = var_mean[1]
p = (p - mean[:,:,None,None]) / torch.sqrt(var[:, :,None,None] + eps)
return p -
GN
import torch
def group_norm(x:torch.tensor,
num_groups:int,
num_channels:int,
eps:float=1e-5,
gamma:float=1.0,
beat:float=0.0):
'''
:param x: [N,C,H,W]
:param num_groups: nums
:param num_channels: C
:param eps:
:param beat:
:return:
'''
assert divmod(num_channels,num_groups)[1] == 0
channels_per_group = num_channels // num_groups
new_tensor = []
for t in x.split(channels_per_group,dim= 1):
var,mean = torch.var_mean(t,dim=[1,2,3],unbiased=False)
# var = var_mean[0]
# mean = var_mean[1]
t = (t-mean[:,None,None,None]) / torch.sqrt(var[:,None,None,None]+eps)
t = t * gamma + beat
new_tensor.append(t)
new_tensor = torch.cat(new_tensor,dim=1)
return new_tensor -
SN
https://github.com/switchablenorms/Switchable-Normalization
作者 栗子鑫
编辑 一口栗子
原文始发于微信公众号(六只栗子):归一化知多少
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之家整理,本文链接:https://www.bmabk.com/index.php/post/88698.html