在机器学习中,归一化是一个非常重要的工具,它能帮助我们加速训练的速度。在我们前面的SiglipVisionTransformer 中,也有用到归一化层,如下代码所示:
class SiglipVisionTransformer(nn.Module): ##视觉模型的第二层,将模型的调用分为了图像嵌入模型和transformer编码器模型的调用def __init__(self, config:SiglipVisionConfig):super().__init__()self.config = configself.embed_dim = config.hidden_sizeself.embeddings = SiglipVisionEmbeddings(config) ## 负责将图像嵌入成向量self.encoder = SiglipEncoder(config) ## 负责将向量编码成注意力相关的向量self.post_layer_norm = nn.LayerNorm(embed_dim, eps=config.layer_norm_eps) ## 层归一化def forward(self, pixel_values:torch.Tensor) -> torch.Tensor:"""
pixel_values: [Batch_size,Channels,Height,Width]"""## [ Batch_size,Channels,Height,Width] -> [Batch_size,Num_Patches,Embedding_size]
hidden_states = self.embeddings(pixel_values) ## 将图像嵌入成向量# [Batch_size,Num_Patches,Embedding_size] -> [Batch_size,Num_Patches,Embedding_size]
last_hidden_state = self.encoder(hidden_states) ## 将向量编码成注意力相关的向量# [Batch_size,Num_Patches,Embedding_size] -> [Batch_size,Num_Patches,Embedding_size]
last_hidden_state = self.post_layer_norm(last_hidden_state)return last_hidden_state
这里的post_layer_norm 就是归一化层,所以本文将一起介绍归一化层。
归一化解决的问题:
归一化主要解决的是神经网络训练的过程中会出现的 “协变量偏移” 的问题。
协变量偏移(Covariate Shift)是指由于输入样本的分布不均匀导致神经网络第一层的输入会有剧烈变化,而第一层神经网络输入的剧烈变化又会导致神经网络第一层的输出产生剧烈变化,从而将影响传递到神经网络之后的每一层,导致每一轮迭代,神经网络输出层的输出都剧烈变化从而导致梯度非常不稳定,参数找不到一个稳定地优化方向,从而导致训练缓慢。
Batch Normalization
假设有一个 mini-batch 的输入 ,也就是:
- :batch size
- :通道数(对全连接层来说是特征维度)
- :空间维度(在卷积层中)
其实本质上,Batch Normalization 希望让输入的特征变化得不再那么剧烈,它希望样本所有的特征都基于当前的批次做一次归一化,这样的话当前批次下的特征就不会剧烈变化了。
值得注意的是:对图像输入的Batch Normalization和对普通特征的Batch Normalization的计算略有差别,假定图像的输入是 [ N, C, H, W ],那么计算公式如上所示,torch会对通道的维度进行归一化,让每一个通道的像素值通过该通道所有图片的像素值得到的平均值和方差做归一化,这是因为由于在图像处理的卷积神经网络里面,同一个通道共享同一个卷积核,故整个通道的所有像素值都看成一个特征。
而如果是普通的特征,则输入形如【 N, D 】,N为Batch_Size, D是特征维度,则对每一个特征通过计算所有N个对应特征的平均值和方差来做归一化。
总的来说,如下图所示:
问题所在
其主要问题就在于依赖 mini-batch:批量太小时效果差
- BatchNorm 的均值和方差是 在 batch 维度上估算 的。
- 如果 batch size 很小(比如在线学习、NLP中的RNN),统计结果不稳定,归一化效果会变差。
- 对于 batch size=1 时,根本无法统计 batch 内部分布。
因为BN 尝试用一个批次代表整体样本的分布,但是这只有在批次样本量很大的时候才能拟合,如果批次样本量很小,那么又会出现协变量偏移的问题。
于是又引申出了layer_normalization....
Layer Normalization
Layer Normalization(层归一化)是为了克服 Batch Normalization 的局限性 而提出的,尤其在 batch size 很小 或 处理序列模型(如 RNN、Transformer) 时非常有用。
LN 的核心思想是:
在一个样本内部的所有特征维度上做归一化,而不是像 BatchNorm 那样在 batch 维度上归一化。
LN的做法比较简单:
在图像卷积场景下,如果输入是(N,C,H,W),即分别代表Batch size,通道数,图像高度和宽度,此时我们有N张不同的图像,图像有C个特征,因为每个通道的一整张图像像素都是其一个特征,故一张图像总共有C个特征,每个特征要看成 H * W维的向量。于是我们对所有的特征计算均值和方差进行归一化。
总结
不管是BN还是LN,归一化的操作都使得每一个计算的value处于标准(0,1)的正态分布中,故缓解了训练过程中协变量偏移的问题。