Caffe中的Convolution+BatchNorm+Scale模块参数设置 & 融合

Convolution+BatchNorm+Scale+Relu的组合模块在卷积后进行归一化,然后在放出非线性Relu层,可以加速训练收敛。但在推理时BatchNorm非常耗时,可以将训练时学习到的BatchNorm+Scale的线性变换参数融合到卷积层,替换原来的Convolution层中weight和bias,实现在不影响准确度的前提下加速预测时间。

一、Convolution+BatchNorm+Scale层在caffe中参数设置示例:
layer {
  name:  "Conv1"
  type: "Convolution"
  bottom: "Conv1"
  top:  "Conv2"
  convolution_param {
    num_output: 64
    kernel_h:1
    kernel_w:3
    pad_h: 0
    pad_w: 1
    stride: 1
    weight_filler {
        type: "msra"
      }
    bias_term: false
  }
}
 
layer {
  name: "Conv2/bn"
  type: "BatchNorm"
  bottom:  "Conv2"
  top:  "Conv2"
  batch_norm_param {
    use_global_stats: false
      eps:1e-03
  }
  param {
    lr_mult: 0
    decay_mult: 0
  }
  param {
    lr_mult: 0
    decay_mult: 0
  }
  param {
    lr_mult: 0
    decay_mult: 0
  }
  include {
    phase: TRAIN
  }
}
 
layer {
  name: "Conv2/bn"
  type: "BatchNorm"
  bottom:  "Conv2"
  top:  "Conv2"
  batch_norm_param {
    use_global_stats: true
      eps:1e-03
  }
  param {
    lr_mult: 0
    decay_mult: 0
  }
  param {
    lr_mult: 0
    decay_mult: 0
  }
  param {
    lr_mult: 0
    decay_mult: 0
  }
  include {
    phase: TEST
  }
}
 
layer {
  name: "Conv2/bn/scale"
  type: "Scale"
  bottom:  "Conv2"
  top:  "Conv2"
  param {
    lr_mult: 1
    decay_mult: 0
  }
  param {
    lr_mult: 1
    decay_mult: 0
  }
  scale_param {
    bias_term: true
  }
}
二、解释说明:
1、Convolution层的设置:
权重: 强烈建议手动选择weight_filler初始化方式!对于Convolution+BatchNorm+Scale的组合模块,建议使用msra模式初始化。 (msra: short for  Microsoft Research Asia or He-initialization, ref:Delving Deep into Rectifiers: Surpassing Human-Level Performance on ImageNet Classification)。其他情况xavier初始化比较常用, xavier初始化可以根据输入和输出神经元的个数,自动地决定初始化值的大小。caffe中默认的weight_filler是constant, value:0, 这种默认的初始化方式得到的结果一般不好,我就遇到过使用了默认的weight_filler后导致图像语义分割错误地得到同色图片的情况。
因为BatchNorm层会减去平均值,所以convolution层的bias_term设置并没有意义。bias_term默认值为true, 默认的bias_filler也是constant, value:0。所以手动设置bias_term: false。
学习率和权重衰减系数,因为只有weight,没有bias,使用如下默认值(无需手动设置) 
param {
    lr_mult: 1
    decay_mult: 1
  }
2、BatchNorm层设置:
BatchNorm是进行归一化,计算

                                                                                                  (1)

use_global_stats在训练时设为false,神经网络只针对每一个batch的数据进行归一化操作,并每一步都利用滑移平均计算更新全局的mean和variance,但是并没有使用这两个全局的统计量;在测试时use_global_stats设为true,直接使用训练时计算好的全局mean和variance进行归一化;
eps是在分母的var项上加一个小值,防止方差为0时出错;
moving_average_fraction默认值为0.999,值越小表示较新迭代计算的mean和var权重更大,之前的迭代影响越小;
BatchNorm的三个参数mean,variance,moving_average_fraction。其中mean,variance是由输入数据计算直接计算得到的,moving_average_fraction是指定的,因此都与学习率和衰减率无关,设定

param {
lr_mult: 0
decay_mult: 0
}
param {
lr_mult: 0
decay_mult: 0
}
param {
lr_mult: 0
decay_mult: 0
}
参考资料:

https://github.com/hujie-frank/SENet/issues/26 

https://gist.github.com/ducha-aiki/c0d1325f0cebe0b05c36

3、Scale层设置:
Scale是将BatchNorm得到的数据做线性变换:

                                                                                         (2)

bias_term在这里打开!学习率系数设定为1即可,无需decay_mult。

param {
     lr_mult: 1
     decay_mult: 0
}
param {
     lr_mult: 1
     decay_mult: 0
}
scale_param {
     bias_term: true
}
三、融合BatchNorm+Scale层到卷积层进行推理加速
在推理时BatchNorm非常耗时,可以将训练时学习到的BatchNorm+Scale的线性变换参数融合到卷积层。具体方法为:

1、识别prototxt文件中的Batch和Scale层,直接删除(这要求BatchNorm和Scale层中top和bottom名保持一致,才能保证删除BatchNorm和Scale层后数据仍然能够正确传输,如上文中示例所用的方式)

2、修改caffemodel的weight,将convolution的bias_term修改为true,并用Convolution+BatchNorm+Scale的等效weight和bias去替换原来的weight和新打开的bias_term。convolution输出值为wx+b,作为BatchNorm层的输入,带入公式(1)(2)中,得到公式如下:

                                        (3)(4)

其中各参数的含义和定义同上文公式(1)(2)

3、另外,有些网络使用了dropout层防止过拟合,在预测时可直接删除dropout层,并不影响预测时数据的传输。

代码可以参考https://download.csdn.net/download/cxiazaiyu/10657938

代码中识别type类型符合BatchNorm, Scale和dropout的层对神经网络配置文件prototxt和权重文件caffemodel做相应修改。

四、BatchNorm层训练和测试的注意事项

1:BatchNormal层:

BN层的设定一般是按照conv->bn->scale->relu的顺序来形成一个block。

关于bn,有一个注意点,caffe实现中的use_global_stats参数在训练时设置为false,测试时设置为true。
因为在训练时bn作用的对象是一个batch_size,而不是整个训练集,如果你没有将其设置为false,则有可能造成bn后数据更加偏离中心点,导致nan或87.3365的问题。所以你可以尝试一下修改这个参数。

use_global_stats:为True时,使用保存的均值,方差;为False时,滑动计算均值方差。在caffe中,该参数缺省的话,TEST阶段自动置为True, 其他阶段为False. 当Finetune需要freeze BN的参数时,要把该参数置为False,否则均值,方差仍在更新;

moving_average_fraction:滑动系数,默认0.999;

eps:加在var上面的,防止标准化时分母为0。

2:如何在RGB数据集上训练灰度图模型


把第一层卷积层改个名字就可以,貌似finetuning初始化模型是根据prototxt里面的layer的name初始化的,只有第一层blob的shape不同,所以第一层就不复制,直接随机初始化就行了
然后再慢慢finetune,速度上基本上没影响。

3:dropout层
训练的时候,我们通常设定一个dropout ratio = p,即每一个输出节点以概率 p 置0(不工作)。假设每一个输出都是相互独立的,每个输出都服从二项伯努利分布B(1-p),则大约认为训练时只使用了 (1-p)比例的输出。

测试的时候,最直接的方法就是保留Dropout层的同时,将一张图片重复测试M次,取M次结果的平均作为最终结果。假如有N个节点,则可能的情况为R=2^N,如果M远小于R,则显然平均效果不好;如果M≈N,那么计算量就太大了。因此作者做了一个近似:可以直接去掉Dropout层,将所有输出都使用 起来,为此需要将尺度对齐,即比例缩小输出 r=r*(1-p)。 
即如下公式: 
 
特别的, 为了使用方便,我们不在测试时再缩小输出,而在训练时直接将输出放大1/(1-p)倍,代码中已经实现。

结论: Dropout得到了广泛的使用,但具体用到哪里、训练一开始就用还是后面才用、dropout_ratio取多大,还要自己多多尝试。有时添加Dropout反而会降低性能。

猜你喜欢

转载自blog.csdn.net/zhuiqiuk/article/details/88089500