本专栏主要是深度学习/自动驾驶相关的源码实现,获取全套代码请参考
目录
- 简介
- BN层
- 计算过程
- 参数说明
- 验证
- 问题:bn层前面的cov不需要bia的原因
- LN层
- 计算过程
- 参数说明
- 验证
- 问题:transfomer用LN而不是BN的原因
简介
深度学习中常见的归一化层包括批量归一化(Batch Normalization)、层归一化(Layer Normalization)、实例归一化(Instance Normalization)、组归一化(Group Normalization)。
批量归一化(Batch Normalization):BN专注于标准化任何特定层的输入(即来自先前层的激活)。标准化输入意味着网络中任何层的输入应具有大约为零的均值和单位方差。BN通过减去当前mini-batch中的输入均值并除以标准差来变换当前mini-batch中的每个输入。此外,BN引入了两个可学习的参数γ和β,用于缩放和平移归一化后的值,以保留原有学习来的特征,同时完成归一化操作,加速训练。
层归一化(Layer Normalization):LN在通道方向上对CHW进行归一化,主要对RNN作用明显。
实例归一化(Instance Normalization):IN在图像像素上对HW进行归一化,主要用于风格化迁移。
组归一化(Group Normalization):GN将通道分组,然后再进行归一化。
这些归一化层的作用主要包括提高优化效率、缓解内部协变量偏移问题、作为正则化方法和提高泛化能力等。但它们也有各自的缺点,例如BN需要较大的批量大小才能有效地逼近小批量的总体均值和方差,这使得BN在训练网络用于对象检测、语义分割等应用时较为困难。
BN层
计算过程
假设输入shape为[4,3,240,240]
BN归一化相当于作用在通道维度上,一共3次归一化,分别求通道1、2、3的4张240x240照片的均值和方差,也就是分别计算3次[4,240,240]数据的均值和方差。
参数说明
主要包含4个参数:均值μ和方差σ²,缩放和平移变量 γ 和 β
均值和方差在训练过程统计得到,可以通过设置momentum值,进行增量式统计,即
x
n
=
(
1
−
m
o
m
e
n
t
u
m
)
∗
x
n
−
1
+
m
o
m
e
n
t
u
m
∗
x
x_n = (1-momentum)*x_{n-1} + momentum* x
xn=(1−momentum)∗xn−1+momentum∗x
在测试过程:拿上面训练的结果使用
缩放和平移变量 γ 和 β通过学习得到
验证
def my_bn(input: torch.Tensor, weight=None, bia=None):
channels = input.size(1)
num = input.size(0) * input.size(2) * input.size(3)
output = deepcopy(input)
# c个均值 c个标准差 c维度gamma c维theta 前两个统计得到,后两个学习得到
exs = []
dxs = []
gamma = torch.ones(size=(channels,))
theta = torch.zeros(size=(channels,))
if weight:
gamma = weight
if bia:
theta = bia
# 按照通道遍历计算
for channel in range(channels):
ex = input[:, channel, :, :].sum() / num
exs.append(ex)
dx = torch.pow(torch.pow(input[:, channel, :, :] - ex, 2).sum() / num, 0.5)
dxs.append(dx)
output[:, channel, :, :] = (output[:, channel, :, :] - ex) / (dx + 0.00001) # 0.00001 for zero denominator
output[:, channel, :, :] = gamma[channel] * output[:, channel, :, :] + theta[channel]
return output
if __name__ == '__main__':
bn = nn.BatchNorm2d(3)
input = torch.randn(size=(2, 3, 5, 5))
output = bn(input)
output_mybn = my_bn(input)
输出结果一致,说明计算过程没有问题
问题:bn层前面的cov不需要bia的原因
每一个卷积核的bia会使得cov输出对应通道的x都变成x+bia
bn层计算当前通道时均值变成mean+bia,标准差不变
z
=
γ
∑
(
x
+
b
i
a
−
m
e
a
n
−
b
i
a
)
2
v
a
r
+
θ
z
=
γ
∑
(
x
−
m
e
a
n
)
2
v
a
r
+
θ
z=\gamma \frac{\sum (x+bia-mean-bia)^2}{var}+ \theta \newline z=\gamma \frac{\sum (x-mean)^2}{var}+ \theta \newline
z=γvar∑(x+bia−mean−bia)2+θz=γvar∑(x−mean)2+θ
所以cov的bia没用作用
LN层
计算过程
Layer Normalization目前在transfomer框架中大量运用.
假设输入shape为[4,3,240,240]
LN归一化相当于作用在样本数量上,一共4次归一化,分别求照片1、2、3、4的均值和方差,也就是计算4次[3,240,240]数据的均值和方差。
参数说明
主要包含4个参数:均值μ和方差σ²,缩放和平移变量 γ 和 β
均值和方差在正向传播时统计得到,训练测试一样,无需momentum值
缩放和平移变量 γ 和 β通过学习得到
验证
def my_ln(input: torch.Tensor, weight=None, bia=None):
batchs = input.size(0)
num = input.size(1) * input.size(2) * input.size(3)
output = deepcopy(input)
# c个均值 c个标准差 c维度gamma c维theta 前两个统计得到,后两个学习得到
exs = []
dxs = []
gamma = torch.ones(size=(batchs,))
theta = torch.zeros(size=(batchs,))
if weight:
gamma = weight
if bia:
theta = bia
# 按照batch遍历计算
for batch in range(batchs):
ex = input[batch,:, :, :].sum() / num
exs.append(ex)
dx = torch.pow(torch.pow(input[batch,:, :, :] - ex, 2).sum() / num, 0.5)
dxs.append(dx)
output[batch,:, :, :] = (output[batch,:, :, :] - ex) / (dx + 0.00001) # 0.00001 for zero denominator
output[batch,:, :, :] = gamma[batch] * output[batch,:, :, :] + theta[batch]
return output
if __name__ == '__main__':
ln = nn.LayerNorm((3, 5, 5))
input = torch.randn(size=(2, 3, 5, 5))
output = ln(input)
output_myln = my_ln(input)
输出结果一致,说明计算过程没有问题
问题:transfomer用LN而不是BN的原因
CV使用BN是认为rgb维度的信息不具有关联性,如果对channel维度也归一化会造成信息损失;认为图片之间因为有物理意义的约束,样本之间具有相似性,所以使用BN。
而同理nlp领域认为不同句子直接不具有关联性,batch维度归一化导致句子信息丢失;而句子内部具有关联性,所以使用LN.
那么VIT呢?
如需获取全套代码请参考