解析caffemodel:记录conv、BN、batchnorm和scale

mac2025-03-03  3

import caffe import numpy as np deploy='deploy.prototxt' model='ECO_full_kinetics.caffemodel' net = caffe.Net(deploy,model,caffe.TEST) #net.params是个字典 all_layer_name=net.params.keys() #所有参数的层的名字 all_blob_name=net.blobs.keys() #所有层的名字 #卷积层 type: "Convolution"。包含2个参数,weight和bias l1=net.params['conv1_7x7_s2'] #一个卷积层 print l1[0].data #weights print l1[0].data.shape print l1[1].data #bias print l1[1].data.shape #BN层 type: "BN"。包含4个参数,后续会讲到 l2=net.params['conv1_7x7_s2_bn'] print l2[0].data print l2[1].data print l2[2].data print l2[3].data

卷积层参数解析: 以如下卷积层为例: 其中,普通卷积没有group参数(默认为1,下面会讲到)

卷积层包含weight和bias两项 故试验可得 len(net.params['conv1_7x7_s2'])=2 故weight存储结构如下: net.params['conv1_7x7_s2'][0].data.shape=(64, 3, 7, 7) weight 含义为:num_output为64,即输出有64个feature map;每个feature map(C,H,W)=(3, 7, 7)的卷积核计算所得 net.params['conv1_7x7_s2'][1].data.shape=(64,) bias 含义为:num_output为64,即输出有64个feature map;每个feature map拥有由一个bias所得

卷积层group解析(等同于mobilenet中的depth wise conv): 根据 https://blog.csdn.net/LIYUAN123ZHOUHUI/article/details/70858472 的理解 以mobilenet v1中如下卷积层为例: group=32,num_output=32, 是将输入的32通道分成group份,输出的32通道也分成group份。 第i份输出仅由第i份输入做卷积得到,此时 第i份输入为(C, H, W)=(1,112,112) 第i份输出为(C, H, W)=(1,112,112) o u t p u t s i z e = ⌊ i n p u t s i z e + 2 p a d − k e r n e l s t i d e ⌋ + 1 outputsize=\left \lfloor \frac{input size+2pad-kernel} {stide} \right \rfloor +1 outputsize=stideinputsize+2padkernel+1 公式内括号为向下取整操作

由于设置了bias_term: false,即无bias项,只有weight 故试验可得 len(net.params['conv2_1/dw'])=1 故weight存储结构如下: net.params['conv2_1/dw'][0].data.shape=(32, 1, 3, 3) 含义为:32个组,每个组的卷积核结构 (C,H,W)=(1, 3, 3)

再举一例,考虑如下卷积层: input_size=(1, 32, 112, 112) kernel=3 pad=1 stide=2 group=2 num_output=64 输入的32通道被分为2份,每份16通道,(16,112,112) 输入的64通道别分为2份,每份32通道,(32,56 ,56) 56 = 112 + 2 ∗ 1 − 3 2 + 1 56=\frac{112+2*1-3}{2}+1 56=2112+213+1 考虑第1份:从(16,112,112)到(32,56 ,56),输入32通道说明有32个卷积核,每个卷积核3*3,卷积核通道数为16,所以第一份实际在caffemodel中存储的weight的shape为(32,16,3,3) 然而总共有2份,总共64个输出,故本卷积层实际存储的weight的shape为(64,16,3,3)


关于caffe中BN和BatchNorm+Scale的区别讲解: 参考链接:https://zhidao.baidu.com/question/621624946902864092.html 理论方面: 首先你要理解BatchNormalization是做什么的。它其实做了两件事。

输入归一化 X n o r m = X − E [ X ] V a r [ X ] X_{norm} = \frac {X-E[X]}{Var[X]} Xnorm=Var[X]XE[X] 其中E和Var是个累计计算的均值和方差。 Y = α × X n o r m + β Y = \alpha \times X_{norm}+\beta Y=α×Xnorm+β 对归一化后的X进行比例缩放和位移。其中 α \alpha α β \beta β是通过迭代学习来的。

那么caffe中的BatchNorm层其实只做了第一件事,Scale层做了第二件事。 而这样理解后,BN层=BatchNorm层+Scale层

caffe中BN和BatchNorm+Scale的实例:

1.BN 以下是一个BN层的例子:

param { lr_mult: 1.0 decay_mult: 1.0 } 参数的真实初始学习率=lr_mult * base_lr(在solver里面) 所以,有2个param { }说明他有2个需要学习的参数,即上面所讲到的 α \alpha α β \beta β,而期望和方差是通过q前向传播计算来的,而不是通过学习来的。 考虑如下例子: 需要知道BN层是不会改变任何形状的

input_size=64962828) 设层为layer='BN' 运行后会得到 len(net.params[layer])=4 net.params[layer][0].data.shape=(1, 96)#alpha_ net.params[layer][1].data.shape=(1, 96)#beta_ net.params[layer][2].data.shape=(1, 96)#mean_ net.params[layer][3].data.shape=(1, 96)#var_ 这4个参数就是上面提的 期望、方差、alpha、beta。是否一一对应尚无验证方法。 说明一个output是由一组(期望、方差、alpha、beta)计算得到。

2.BatchNorm+Scale 上述的BN层可等价为以下的BatchNorm+Scale: BatchNorm层3个lr_mult=0,说明他们都不是通过反向传播学习到的 Scale层2个lr_mult=0,说明有2个需要学习的参数。

以下代码实现从BN层移动参数至batchnorm和scale:

bn=net.params['bn'] #bn[0],bn[1],bn[2],bn[3]原本的形状是(1,512) #由于下面的batchnorm和scale的参数形状都是(512,),故做reshape alpha_=bn[0].data.reshape((-1,)) beta_=bn[1].data.reshape((-1,)) mean_=bn[2].data.reshape((-1,)) var_=bn[3].data.reshape((-1,)) batchnorm=net1.params['batchnorm'] scale=net1.params['scale'] batchnorm[0].data[:]=mean_[:] #(512,) batchnorm[1].data[:]=var_[:] #(512,) batchnorm[2].data[:]=1.0 #(1,)其他博客称这个为缩放系数,暂不懂做什么用 scale[0].data[:]=alpha_[:] #(512,) scale[1].data[:]=beta_[:] #(512,)

查看caffe.proto:

message BatchNormParameter { // 当为true,使用保存的均值和方差;否则使用滑动平均计算新的方差和均值. optional bool use_global_stats = 1; // 每次迭代滑动平均衰减系数 optional float moving_average_fraction = 2 [default = .999]; // 防止除以0用的 optional float eps = 3 [default = 1e-5]; }
最新回复(0)