深度学习归一化: BN,LN,IN,GN

深度学习中的常见归一化方法主要有: batch Normalization, layer Normalization, instance Normalization, group Normalization.

神经网络学习过程的本质就是为了学习数据分布, 如果没有做归一化处理, 那么每一批次训练数据的分布不一样, 网络需要在这多个分布中找到平衡点, 对于每层每层网络而言, 同样当输入数据分布在不断变化, 这也会导致每层网络在找平衡点, 因此神经网络就很难收敛了.

四者的对比如下图来自论文GN, 假设输入数据为[N,C,H,W], 为了便于图示, 将HW放在一起, 对图像而言相当于将二维图片拉成一行:

batch Normalization

即批量归一化, 如上图所示, 在 batch 方向进行归一化, 对输入的batchsize的训练样本, 沿batch方向对所有样本的各个通道分别归一化. 从而保证数据分布的一致性, 而对于基于CNN的判别判别模型的结果正是取决于数据整体分布, BN对batchsize的大小比较敏感, 由于每次计算均值和方差是在一个batch上, 所以如果batchsize太小, 则计算的均值、方差不足以代表整个数据分布.

# 模拟BN
def bn(x):
    b, c, h, w = x.shape
    gamma = torch.rand((c,))
    beta = torch.rand((c,))
    for i in range(c):
        # 逐通道归一化
        mean = x[:, i, :, :].mean()
        std = x[:, i, :, :].std()
        x[:, i, :, :] = (x[:, i, :, :] - mean) / (std + 1e-5)
        x[:, i, :, :] = x[:, i, :, :] * gamma[i] + beta[i]
    return x

$\gamma$ 与 $\beta$ 作为可学习参数重构输入. pytorch 中训练时以动量的方式更新均值和方差, 测试时直接使用. $\hat X _{new} =(1- m) * \hat X + m * X _t$, m 为设置的动量参数, $X _t$ 为当前batchsize的均值, $\hat X$ 为估计的统计值, $\hat X _{new}$ 为新的估计均值, 方差情况类似.

layer Normalization

对输入每一层的每一个样本进行归一化

def ln(x):
    b, c, h, w = x.shape
    gamma = torch.rand((b,))
    beta = torch.rand((b,))
    for i in range(b):
        mean = x[i, :, :, :].mean()
        std = x[i, :, :, :].std()
        x[i, :, :, :] = (x[i, :, :, :] - mean) / (std + 1e-5)
        x[i, :, :, :] = x[i, :, :, :] * gamma[i] + beta[i]
    return x

instance Normalization

IN 主要用于GAN网络中, 比如画风迁移、图像生成等, 图片生成的结果主要依赖于某个图像实例自己, 使各个实例保持独立.

def In(x):
    b, c, h, w = x.shape
    gamma = torch.rand((b, c))
    beta = torch.rand((b, c))
    for i in range(b):
        for j in range(c):
            mean = x[i, j, :, :].mean()
            std = x[i, j, :, :].std()
            x[i, j, :, :] = (x[i, j, :, :] - mean) / (std + 1e-5)
            x[i, j, :, :] = x[i, j, :, :] * gamma[i, j] + beta[i, j]
    return x

group Normalization

GN 先将 channel 分组, 然后类似于IN对各个组的数据进行归一化, 相当于与引入了通道间的依赖.