0919批量归一化

  • 现在主流的卷积神经网络几乎都使用了批量归一化
  • 批量归一化是一种流行且有效的技术,它可以持续加速深层网络的收敛速度

训练神经网络时出现的挑战

1、数据预处理的方式通常会对最终结果产生巨大影响

  • 使用真实数据时,第一步是标准化输入特征(使其均值为0,方差为1),这种标准化可以很好地与优化器配合使用(可以将参数的量级进行统一)

2、对于典型的多层感知机或卷积神经网络,在训练时中间层中的变量可能具有更广的变化范围

  • 不论是沿着从输入到输出的层跨同一层中的单元、或是随着时间的推移,模型参数的随着训练更新变化莫测
  • 归一化假设变量分布中的不规则的偏移可能会阻碍网络的收敛

3、更深层的网络很复杂,容易过拟合

  • 这就意味着正则化变得更加重要

问题:

0919批量归一化_第1张图片

当神经网络比较深的时候会发现:数据在下面,损失函数在上面,这样会出现什么问题?

  • 正向传递的时候,数据是从下往上一步一步往上传递
  • 反向传递的时候,数据是从上面往下传递,这时候就会出现问题:梯度在上面的时候比较大,越到下面就越容易变小(因为是n个很小的数进行相乘,越到后面结果就越小,也就是说越靠近数据的,层的梯度就越小)
  • 上面的梯度比较大,那么每次更新的时候上面的层就会不断地更新;但是下面层因为梯度比较小,所以对权重地更新就比较少,这样的话就会导致上面的收敛比较快,而下面的收敛比较慢,这样就会导致底层靠近数据的内容(网络所尝试抽取的网络底层的特征:简单的局部边缘、纹理等信息)变化比较慢,上层靠近损失的内容(高层语义信息)收敛比较快,所以每一次底层发生变化,所有的层都得跟着变(底层的信息发生变化就导致上层的权重全部白学了),这样就会导致模型的收敛比较慢

所以提出了假设:能不能在改变底部信息的时候,避免顶部不断的重新训练?(这也是批量归一化所考虑的问题)

核心思想

  • 为什么会变?因为方差和均值整个分布会在不同层之间变化

所以假设将分布固定,假设每一层的输出、梯度都符合某一分布,相对来说就是比较稳定的(具体分布可以做细微的调整,但是整体保持基本一致,这样的话,在学习细微的变动时也比较容易)

批量归一化:将不同层的不同位置的小批量(mini-batch)输出的均值方差固定,均值和方差的计算方法如下图所示

  • B:小批量
  • ε:方差的估计值中有一个小的常量 ε > 0,作用是为了确保在做归一化时除数永远不等于零(估计值μB和σB通过使用平均值和方差的噪声估计来抵消缩放问题)
  • 在深度学习中,优化中的各种噪声源通常会导致更快的训练和较少的过拟合:这种变化似乎是正则化的一种形式

在这个基础上做额外的调整如下图所示

0919批量归一化_第2张图片

  • 给定一个来自小批量的输入xi,批量归一化对里面的每一个样本减去均值除以标准差,再乘以γ,最后再加上β
  • 上式中的 μB(样本均值)σB(样本标准差)是从数据中计算得到的
  • 拉伸参数(scale)γ 偏移参数(shift)β 是可以学习的参数(需要与其他模型参数一起学习),是批量归一化之后学出来的,作用是假设分布在某一均值和方差下不合适,就可以通过学习一个新的均值和方法,使得神经网络输出的分布更好(在训练的过程中,中间层的变化幅度不能过于剧烈,应用批量归一化可以将每一层主动居中,并对β和γ进行限制从而将它们重新调整为给定的平均值和大小,避免变化过于剧烈)

原理

  • 批量归一化可应用于单个可选层,也可应用于所有层
  • 在每次训练迭代中,首先规一化输入(通过减去均值并除以其标准差,其中均值和标准差都是基于当前小批量处理得来的)
  • 然后应用比例系数比例偏移
  • 正是由于是基于批量统计的标准化,所以才有了批量归一化的名称

注意

1、如果对批量大小为1的小批量进行批量归一化,将无法学到任何东西(因为在减去均值之后,每个隐藏层单元将为0)

2、只有使用足够大的小批量,批量规一化才是有效且稳定的

3、在使用批量规一化时,批量大小的选择可能比没有批量归一化时更重要

4、批量归一化层在“训练模式”和“预测模式”中的功能不同(和暂退法一样,批量归一化层在训练模式和预测模式下的行为通常不同):

  • 训练模式:通过小批量统计数据归一化。在训练过程中,由于无法得知使用整个数据集来估计平均值和方差,所以只能根据每个小批次的平均值和方差不断训练模型
  • 预测模式:通过数据集统计归一化。在预测模式下,可以根据整个数据集(不再需要样本均值中的噪声以及在微批次上估计每个小批次产生的样本方差)精确计算批量归一化所需的平均值和方差;可能需要使用模型对逐个样本进行预测(一种常用的方法是通过移动平均估算整个训练数据集的样本均值和方差,并在预测时使用它们得到确定的输出)

批量归一化层

批量归一化层和其它层的关键区别是:由于批量归一化在完整的小批量上运行,所以不能像在引入其他层时忽略批量大小

批量归一化层可以学习的参数是 γ β ,可以认为是全连接的每一个特征(或者每一列)都有对应的 γ 和 β

批量归一化层可以作用在全连接或者卷积层的输出上,激活函数前,也可以作用在全连接层和卷积层的输入上,他们的实现略有不同

全连接层

批量归一化层通常置于全连接层中的仿射变换和激活函数之间

  • x:全连接层的输入
  • W:权重参数
  • b:偏置参数
  • ϕ:激活函数
  • BN:批量归一化运算符

当作用在全连接层时,实际上是作用在特征维,对于每一个特征计算标量的均值和方差,对每一个全连接的输入和输出都进行批量归一化,而不是只作用在数据上面,另外也会利用学到的 γ 和 β 对均值和方差进行一次校验

卷积层

对于卷积层,可以在卷积层之后和非线性激活函数之前应用批量归一化

  • 当卷积有多个输出通道时,需要对这些通道的“每个”输出执行批量归一化,每个通道都有自己的拉伸参数偏移参数,并且都是标量
  • 当作用在卷积层上时,实际上是作用在通道维,特别是对于1 * 1的卷积来说,它等价于一个全连接层(对于一个像素来说,它的通道数可以认为是一个N维的向量(N等于通道数),作为它的一种特征;对于输入来说,每一个像素就是一个样本),所以对于一个卷积层来说,假如输入是批量大小 * 高 * 宽 * 通道数的话,那么样本大小就是批量大小 * 高 * 宽,即批量中所有像素都是样本,对应的通道就是特征,所以1 * 1的卷积就是先拉成一个二维矩阵再做全连接。所以这里的意思是说将所有的像素当成样本来计算均值和方差,也就是只作用在通道维(将通道维当成是卷积层的特征维)
  • 假设小批量包含m个样本,并且对于每个通道,卷积的输出具有高度p和宽度q,那么对于卷积层,在每个输出通道的m * p * q个元素上同时执行每个批量归一化。所以在计算均值和方差的时候会收集所有空间位置的值,然后在给定通道内应用相同的均值和方差,以便在每个空间位置对值进行归一化

具体内容

最初在论文中提出它的时候是为了减少内部协变量转移(internal covariate shift,简单来说就是变量值的分布在训练过程中会发生变化),但是这种解释存在两个问题:

  • 这种偏移与严格定义的协变量偏移(internal covariate shift)非常不同,所以名字用词不当
  • 这种解释只提供了一种不明确的直觉,但是留下了一个有待后续挖掘的问题:为什么这项技术如此有效?

后续论文发现它并没有减少内部协变量的转移,并且指出它可能是通过在每个小批量中加入噪音来控制模型的复杂度(虽然 μB 和 σB 是由数据得来的,但是每次选取小批量的时候是随机选取的,所以这里的均值和标准差也是随机的,-:随机偏移,/:随机缩放,这里的噪声是比较大的;β和γ因为是学习来的,学习率是一个固定的数,所以变化不会特别剧烈,变化的程度取决于学习率)

0919批量归一化_第3张图片

  • 如果说将批量归一化看成是一个控制模型复杂度的方法的话,是没有必要和丢弃法(dropout)混合使用的

0919批量归一化_第4张图片

总结

  • 在模型训练过程中,批量归一化利用小批量的均值和标准差,不断调整神经网络的中间输出,使整个神经网络各层的中间输出值更加稳定(对于全连接层,作用在每一个特征维(每一列)上;对于卷积层,拉成一个矩阵之后,作用在输出维)
  • 可以加速收敛速度(使用了批量归一化之后,学习率可以调的比较大,用更大的学习率训练可以提高训练速度,不会出现学习率过大时,上层梯度爆炸,梯度较小时,下层梯度消失的情况。将每一层的输入变成差不多的分布之后,就可以使用大一点的学习率 ),但一般不改变模型精度
  • 批量归一化在全连接层卷积层的使用略有不同
  • 批量归一化层和暂退层一样,在训练模式预测模式下计算不同
  • 批量归一化有许多有益的副作用,主要是正则化。另外一方面,原论文中关于批量归一化“减少内部协变量偏移”的原始动机似乎不是一个有效的解释

代码:

net = nn.Sequential(nn.Conv2d(1,6,kernel_size=5),BatchNorm(6,num_dims=4), # 在第一个卷积后面加了BatchNorm                       
                   nn.Sigmoid(),nn.MaxPool2d(kernel_size=2,stride=2),
                   nn.Conv2d(6,16,kernel_size=5),BatchNorm(16,num_dims=4), # BatchNorm的feature map为卷积层的输出通道数。这里BatchNorm加在激活函数前面。      
                   nn.Sigmoid(),nn.MaxPool2d(kernel_size=2,stride=2),      
                   nn.Flatten(),nn.Linear(16*4*4,120),
                   BatchNorm(120,num_dims=2),nn.Sigmoid(),
                   nn.Linear(120,84),BatchNorm(84,num_dims=2),
                   nn.Sigmoid(),nn.Linear(84,10))   
# 在Fashion-MNIST数据集上训练网络
lr,num_epochs,batch_size = 1.0, 10, 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)
d2l.train_ch6(net, train_iter, test_iter, num_epochs, lr, d2l.try_gpu()) 

# 拉伸参数gamma和偏移参数beta
net[1].gamma.reshape((-1,)), net[1].beta.reshape((-1,))

框架化代码:

# 简洁使用
net = nn.Sequential(nn.Conv2d(1,6,kernel_size=5),nn.BatchNorm2d(6),
                   nn.Sigmoid(),nn.MaxPool2d(kernel_size=2,stride=2),
                   nn.Conv2d(6,16,kernel_size=5),nn.BatchNorm2d(16),
                   nn.Sigmoid(),nn.MaxPool2d(kernel_size=2,stride=2),
                   nn.Flatten(),nn.Linear(256,120),nn.BatchNorm1d(120),
                   nn.Sigmoid(),nn.Linear(120,84),nn.BatchNorm1d(84),
                   nn.Sigmoid(),nn.Linear(84,10))
# 使用相同超参数来训练模型
d2l.train_ch6(net, train_iter, test_iter, num_epochs, lr, d2l.try_gpu())

 

 

你可能感兴趣的