终于知道为什么要freeze BN层,以及如何freeze(这个trick真的可以加快收敛)

一、什么是Batch Normalization(BN)层

BN层是数据归一化的方法,一般都是在深度神经网络中,激活函数之前,我们在训练神经网络之前,都会对数据进行预处理,即减去均值和方差的归一化操作。但是随着网络深度的加深,函数变的越来越复杂,每一层的输出的数据分布变化越来越大。BN的作用就是把数据强行拉回我们想要的比较好的正态分布下。这样可以在一定程度上避免梯度爆炸或者梯度消失的问题,加快收敛的速度。

二、BN是如何操作的

I n p u t : B = x 1... m ; γ , β ( 参 数 需 要 学 习 ) Input: B = {x_{1...m}}; \gamma, \beta(参数需要学习) Input:B=x1...m;γ,β()
O u t p u t : y i = B N γ β ( x i ) Output: {y_i = BN_{\gamma\beta}(x_i)} Output:yi=BNγβ(xi)
u B ← 1 m ∑ i = 1 m x i u_B \leftarrow \frac{1}{m}\sum_{i =1}^mx_i uBm1i=1mxi
σ B 2 ← 1 m ∑ i = 1 m ( x i − u B ) 2 \sigma_B^2 \leftarrow \frac{1}{m}\sum_{i =1}^m(x_i - u_B)^2 σB2m1i=1m(xiuB)2
x ~ ← x i − u B σ B 2 + ϵ \tilde{x} \leftarrow \frac{x_i - u_B}{\sqrt{\sigma_B^2+\epsilon}} x~σB2+ϵ xiuB
y i = γ x ~ i + β y_i = \gamma\tilde{x}_i+\beta yi=γx~i+β

BN工作流程:
1、计算当前batch_size数据的均值和方差;
2、将当前batch内的数据,normalize到均值为0,方差为1的分布上;
3、然后对normalized后的数据进行缩放和平移,缩放和平移的 γ 和 β \gamma和\beta γβ是可学习的。

BN层的状态包含4个参数:

  • weight,即缩放操作的\gamma
  • bias,缩放操作的\beta
  • running_mean,训练阶段在全训练数据上统计的均值,测试阶段会用到
  • running_var,训练阶段在全训练数据上统计的方差,测试阶段会用到

weight和bias这两个参数需要训练,而running_mean、running_val不需要训练,它们只是训练阶段的统计值。
训练时,均值、方差分别是该批次内数据相应维度的均值与方差;
推理时,均值、方差是基于所有批次的期望计算所得,

BN层的使用:
torch.nn.BatchNorm1d(num_features, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True, device=None, dtype=None)
momentum:估计running_mean和 ruuning_var时使用
affine:如果为true,就学习参数 γ 和 β \gamma和\beta γβ,否则不学习。
track_running_stats:如果为true,持续跟踪running_mean,running_var

三、BN最大的作用

加快收敛。

四、为什么要freeze BN层

BN层在CNN网络中大量使用,可以看上面bn层的操作,第一步是计算当前batch的均值和方差,也就是bn依赖于均值和方差,如果batch_size太小,计算一个小batch_size的均值和方差,肯定没有计算大的batch_size的均值和方差稳定和有意义,这个时候,还不如不使用bn层,因此可以将bn层冻结。另外,我们使用的网络,几乎都是在imagenet上pre-trained,完全可以使用在imagenet上学习到的参数。

五、如何freeze BN层

有两种,一种是在训练阶段,将bn层变为eval(),即不更新统计running_mean和runn_val;另一种是需要将bn层的requires grad = False,BN层的参数weight和bias不优化,更新。
frozen: stop gradient update in norm layers
norm_eval: stop moving average statistics update in norm layers

def train(self, model=True):
  freeze_bn = False
  freeze_bn_affine = False
  supper(myNet, self).train(mode)
  if freeze_bn:
      print ("Freezing Mean/Var of BatchNorm2D.")
      for m in self.model.modules():
          if isinstance(m, nn.BatchNorm2d):
              m.eval()
      if freeze_bn_affine:
          print ("Freezeing Weight/Bias of BatchNorm2D.")
          if freeze_bn_affine:
              m.weight.requires_grad = False
              m.bias.requires_grad = False

两种freeze BN的方式,如何使用,我们来看一下《MMDetection: Open MMLab Detection Toolbox and Benchmark》里面的相关实验,在mmdetection中eval = True, requires grad = True是默认设置,不更新BN层的统计信息,也就是running_var和running_mean,但是优化更新其weight和bias的学习参数。
在这里插入图片描述
当GPU内存限制时,batch_size只能设置很小,例如1或者2,因此会对BN层进行freeze。上面的table6 时eval和requires_grad不同组合时的效果,该实验使用的网络是Mask R-CNN。Table 6显示,lr schedulex1时,更新统计信息,即eval = False,会损害网络性能,当eval = True,对权重weight 和 bias是否更新,即requires_grad = False or True,影响不大;但是lr_schedulex2中,eval=True, requires_grad = True 效果最好。

  • 19
    点赞
  • 60
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
加上freeze层之后,会对loss产生一定的影响。freeze层是指在训练模型时固定某些层的参数,不对它们进行更新,只对其他层的参数进行梯度更新。这样做的目的是为了保持已经学习到的特征表示不变,从而提高模型的泛化能力。 首先,加上freeze层会减少可更新的参数数量,从而减少模型的自由度。由于参数不再更新,模型的权重也不会发生变化,因此在训练过程中新加的层不会对已有层的影响进行调整。这样做的好处是减少了过拟合的风险,防止新加层过度学习训练数据的特征,从而提高模型的泛化能力。 其次,由于freeze层不进行参数更新,对应的梯度也不会传播到前面的层,因此在反向传播过程中,梯度无法通过freeze层的权重进行更新。这可能导致损失函数的下降速度较慢,训练过程会变得更加缓慢。不过,由于freeze的是一些已经训练得到较好的层,其特征表示的质量较高,一定程度上可以弥补梯度无法通过的影响。 另外,加上freeze层可能会导致模型的整体性能下降。因为一些层的参数不再更新,可能限制了模型在训练数据上的表现能力。尤其对于一些任务来说,新加的层可能需要学习更加复杂或抽象的特征表示,而这些特征可能无法直接从冻结层中获得。因此,加上freeze层可能会导致模型在一些复杂任务上的性能下降。 综上所述,加上freeze层会对loss产生一些影响。虽然能够减少过拟合的风险,但同时也可能导致训练过程变慢并限制了模型的整体性能。需要根据具体的任务和模型结构来权衡是否加上freeze层及冻结哪些层的参数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值