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

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是做什么的。它其实做了两件事。

  1. 输入归一化 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是个累计计算的均值和方差。
  2. 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];
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值