引言
目前,深度学习已经彻底改变了自然语言处理、计算机视觉、机器人等许多子领域。深度学习当然涉及训练精心设计的深度神经网络,并且各种设计决策会影响这些深度网络的训练机制。其中一些设计决策包括
- 网络中要使用的网络层类型,例如卷积层、线性层、循环层等,以及我们的网络应该有多少层?
- 我们应该使用什么样的归一化层?
- 正确的优化损失函数应该是什么?
这些设计决策主要取决于我们试图解决的基本任务,并且需要更深入地了解我们手头的不同选项。在这篇博文中,我将重点讨论第二点“深度学习中的不同归一化层”。概括地说,我将涵盖以下方法。
- 批量归一化 (Batch Normalization)
- 权重归一化 (Weight Normalization)
- 层归一化 (Layer Normalization)
- 组标准化 (Group Normalization)
- 权重标准化 (Weight Standarization)
批量归一化 (BN)
批量归一化专注于标准化任何特定层的输入(即来自先前层的激活)。标准化输入意味着网络中任何层的输入应具有大约为零的均值和单位方差。从数学上来说,BN 层通过减去当前 mini-batch 中的输入均值并除以标准差来变换当前 mini-batch 中的每个输入。
但每一层不需要期望输入具有零均值和单位方差,相反,模型可能在使用其他均值和方差时表现更好。因此BN层还引入了两个可学习的参数 γ γ γ和 β β β。
整个图层操作如下。它接受输入 x i x_i xi 并将其转换为 y i y_i yi,如下表所述。
问题是BN如何帮助NN训练?直观上,在梯度下降中,网络根据任意层的当前输入计算梯度,并在梯度指示的方向上减少权重。但由于各层是一个接一个地堆叠的,由于前一层的权重略有更新,任何特定层的输入数据分布变化太大,因此当前梯度可能会为网络产生次优信号。但 BN 将输入数据的分布限制在网络中的任何特定层(即前一层的激活),这有助于网络为权重更新产生更好的梯度。因此,BN 经常提供非常稳定和加速的培训制度。
然而,以下是批量归一化的一些缺点。
- BN 在每次训练迭代中计算批量统计数据(小批量均值和方差),因此在训练时需要更大的批量大小,以便能够有效地逼近小批量的总体均值和方差。这使得 BN 更难训练网络用于对象检测、语义分割等应用,因为它们通常使用高输入分辨率(通常大至 1024x 2048),并且较大批量的训练在计算上不可行。
- BN 不能很好地与 RNN 配合使用。问题是 RNN 与之前的时间戳有循环连接,并且需要为 BN 层中的每个时间步设置单独的 β 和 γ,这反而会增加额外的复杂性,并使 BN 与 RNN 一起使用变得更加困难。
- 不同的训练和测试计算:在测试(或推理)期间,BN 层不会计算测试数据小批量的均值和方差(上面算法表中的步骤 1 和 2),而是使用根据训练数据计算出的固定均值和方差。这在使用 BN 时需要谨慎,并会带来额外的复杂性。在 pytorch 中,model.eval() 确保在评估模型中设置模型,因此 BN 层利用它来使用根据训练数据预先计算的固定均值和方差。
权重归一化 (WN)
由于Batch Normalization的缺点,T. Saliman和P. Kingma提出了Weight Normalization。他们的想法是将长度与权重向量的方向解耦,从而重新参数化网络以加速训练。
重新参数化对于权重归一化意味着什么?
权重归一化论文的作者建议使用两个参数 g(权重向量的长度)和 v(权重向量的方向)权重向量)代替 w 进行梯度下降,方法如下。
权重归一化与批量归一化类似,可以加快训练速度,并且与 BN 不同,它也适用于 RNN。但与批归一化相比,使用权重归一化训练深度网络的稳定性明显较差,因此在实践中并未广泛使用。
层归一化 (LN)
受批量归一化结果的启发,Geoffrey Hinton 等人。提出了层归一化,它沿着特征方向而不是小批量方向对激活进行归一化。这通过消除对批次的依赖克服了 BN 的缺点,并且也更容易应用于 RNN。
本质上,层归一化将激活的每个特征归一化为零均值和单位方差。
组归一化 (GN)
与层归一化类似,组归一化也是沿特征方向应用,但与 LN 不同的是,它将特征分为一定的组,并分别对每个组进行归一化。在实践中,组标准化比层标准化表现更好,其参数num_groups被调整为超参数。
如果您觉得 BN、LN、GN 令人困惑,下图非常准确地总结了它们。给定形状(N、C、H、W)的激活,BN 标准化 N 方向,LN 和 GN 标准化 C 方向,但 GN 另外将 C 通道分组并单独标准化各组。
接下来让我们了解什么是权重标准化。
权重标准化 (WS)
权重标准化正在将任何层的权重转换为具有零均值和单位方差。该层可以是卷积层、RNN 层或线性层等。对于任何具有形状(N,*)的给定层,其中 * 表示 1 个或多个维度,权重标准化,沿 * 维度变换权重。
下面是在 pytorch 中实现 2D 卷积层权重标准化的示例代码。
class Conv2d(nn.Conv2d):
def __init__(self, in_channels, out_channels, kernel, **kwargs):
super().__init__(in_channels, out_channels, kernel, **kwargs)
def forward(self, x):
weight = self.weight
weight_mean = weight.mean(dim=(1,2,3), keepdim=True)
std = weight.std(dim=(1,2,3) + 1e-5
weight = (weight - weight_mean)/ std
return F.conv2d(x, weight, self.bias, self.stride, self.padding, self.dilation, self.groups)
基本思想是仅在前向传递期间变换权重并相应地计算激活。 Pytorch 将立即处理向后传递。类似地,它也可以应用于线性层。
最近,Siyun Qiao等人在他们的论文“Micro-Batch Training with Batch-Channel Normalization and Weight Standardization”中介绍了权重标准化,并发现当组归一化与权重标准化混合时,可以即使批量大小小至 1,其性能也优于或与 BN 相当。如下图所示,作者在 Imagenet 分类和 MS COCO 目标检测任务上训练了 GN、BN、GN+WS 与 Resnet50 和 Resnet101 的组合,发现:即使批量比 BN 使用的小得多,GN+WS 的性能始终优于 BN 版本。这在语义分割、实例分割等密集预测任务中引起了人们的关注,由于内存限制,这些任务通常无法使用较大的批量大小进行训练。
总之,模型中的归一化层通常有助于加速和稳定学习过程。如果大批量训练不是问题并且网络没有任何循环连接,则可以使用批量归一化。对于较小批量或复杂层(例如 LSTM、GRU)的训练,可以尝试使用权重标准化进行组标准化,而不是批量标准化。
需要注意的一件重要事情是,在实践中,归一化层用于 Linear/Conv/RNN 层和 ReLU 非线性(或双曲正切等)之间,以便当激活达到非线性激活函数时,激活同样以零为中心。这可能会避免由于错误的随机初始化而永远不会被激活的死亡神经元,因此可以改善训练。
以下是本文使用的参考文献列表:
- Ioffe, Sergey, and Christian Szegedy. “Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift.” arXiv preprint arXiv:1502.03167 (2015).
- Salimans, Tim, and Durk P. Kingma. “Weight normalization: A simple reparameterization to accelerate training of deep neural networks.” Advances in neural information processing systems 29 (2016): 901-909.
- Ba, Jimmy Lei, Jamie Ryan Kiros, and Geoffrey E. Hinton. “Layer normalization.” arXiv preprint arXiv:1607.06450 (2016).
- Qiao, Siyuan, et al. “Weight standardization.” arXiv preprint arXiv:1903.10520 (2019)