第二篇mxnet 模型直接转换caffe层解析,不用onnx, mobilenet,res50retinaface,upsample,pool

#coding=utf-8
import sys
import argparse
import json
from prototxt_basic import *

parser = argparse.ArgumentParser(description='Convert MXNet jason to Caffe prototxt')
parser.add_argument('--mx-json',     type=str, default='model_mxnet/R50-symbol.json')
parser.add_argument('--cf-prototxt', type=str, default='model_caffe/r50.prototxt')
args = parser.parse_args()

with open(args.mx_json) as json_file:    
  jdata = json.load(json_file)

with open(args.cf_prototxt, "w") as prototxt_file:
  for i_node in range(0,len(jdata['nodes'])): 
    # 添加字典元素,该层的信息这里已经添加了,例如 prototxt_badic.py info['attrs'] ,就是当前层的信息
    node_i    = jdata['nodes'][i_node]  #格式打开symbol.json看一眼格式,{ "nodes":[{},{},{}]},jdata['nodes']是列表,索引访问列表元素
    if str(node_i['op']) == 'null' and str(node_i['name']) != 'data':
      continue
    
    print('{}, \top:{}, name:{} -> {}'.format(i_node,node_i['op'].ljust(20),
                                        node_i['name'].ljust(30),
                                        node_i['name']).ljust(20))  #写到caffe prototxt左边空格的个数
    info = node_i  # 不要搞混了,node_i已经是一个字典变量啦,并且存储的是当前层的键值对信息
    
    info['top'] = info['name']  #在当前层信息的字典变量添加新的键值对
    info['bottom'] = []  #下面循环遍历
    info['params'] = []  #
    for input_idx_i in node_i['inputs']:
      input_i = jdata['nodes'][input_idx_i[0]]
      '''
      遍历的第一个位置的第一个位置肯定是bottom,得到name,"inputs": [[0, 0, 0], [1, 0, 0], [2, 0, 0], [3, 0, 0], [4, 0, 0]]
      然后跳出循环得到遍历后面的第一个元素是该层的多个参数信息,bn层4个参数
      特点是 op 不是null,是这一层的输入bottom 的name,但是数据输入层的信息,name=data,op=null,所以or
      json文件顺序是,该层参数信息字典都是,该层前面位置已经放好了
      '''
      if str(input_i['op']) != 'null' or (str(input_i['name']) == 'data'): #这种情况是得到bottom,name
        info['bottom'].append(str(input_i['name']))
      ##  这里应该,and input_i['name']!="data" ,不然data 后第一个卷积,会多添加data这个名字,不过实际不影响
      if str(input_i['op']) == 'null'  :  #第一个输入层索引不走这,第二及之后的索引列表走这,获得参数信息
        info['params'].append(str(input_i['name']))
        '''
        参数的名字开头和层的名字基本上都是一样的,这里这对卷积层,根据这个kv ,添加一个param,
        一般都是参数名字conv0_weight,层的名字是conv0,不走下面的语句
        但是有时候mxent层的名字不对应例如,参数名字"mobilenet0_conv1_weight",层名字"mobilenet0_conv1_fwd",多了fwd,走这边
        多添加caffe该层的一个信息,
            param {
            name: "mobilenet0_conv1_weight"
            }
        '''
        if not str(input_i['name']).startswith(str(node_i['name'])):  #判断参数层的名字,输入层的名字在上一个if,不走这里
          print('           use shared weight -> %s'% str(input_i['name']))
          info['share'] = True  #添加变量info  字典元素,key value,,

    write_node(prototxt_file, info)  #调用函数
    print("succed")
'''

test model protoxt

1、~/nas/caffe/build/tools/caffe time -model ./model_caffe/r50.prototxt -gpu 1
prototxt 感觉没有问题也都转换成功了
但是res50,模型结构出不来,感觉每一层都没有问题,
运行上述protoxt,test, 层 _plus0,有问题,最后发现,json文件,有两个_plus0,所以caffe 对应名字,重复了,修改最上面的该层名字
然后_plus1又有问题,发现_plus1 上面积层有最下面 也有

2、
caffe 模型运行,一张图片加载都超出内存,所有group 大于1的卷积层加入,engine: CAFFE,使用caffe 的计算,不用cuda 计算,就可以
mobilenet 模型会有这个问题
convolution_param {
num_output: 8
kernel_size: 3
pad: 1
group: 8
stride: 1
bias_term: false
engine: CAFFE
}

3、
mxnet upsample , 后面还有一个crop,caffe 反卷积层参数是直接写的,要根据不同模型修改shape,不知道Deconvosation,shape chw,
~/nas/caffe/build/tools/caffe time -model ./model_caffe/r50.prototxt -gpu 1,运行,报错,查看打印出来层的shape ,手动修改Deconvolution参数就可以了,
这个命令用来调试prototxt文件,找不到bug,根据错误提示,找到问题

4、res50还有一个bug,mxnet pool 下取整, 160.5会变成160
caffe 最大池化是 上取整数变成161
ceil_mode:false,该层添加相关代码重新编译文件后,最大池化,变成下取整
caffe 卷积下取整,最大池化上取整
pytorch 默认都是下取整,ceil_mode=True ,是上取整
mxnet 下取整

5、mx.viz.print_summary(sym, shape={“data”: (1, 3, 640, 640)}),打印每层shape
和caffe,图显示,就能看出来,shape不一致

6、upsampe,添加到代码中之后,caffe 编译成功,mxnet3caffe.py 导caffe 模型出错,不能解析,感觉caffe 重新编译的环境没有包含一样
但是终端直接进入python环境,导入caffe,prototxt 文件就没有问题,没有解决这个bug,
所以现在还是,upsample 到 deconvolution crop ,直接转换,然后手动修改prototxt文件的这个层,
但是注意,caffe,还有个问题,删除修改没有参数的层,对应的权重文件其实有一点点不对应,不知道哪里不对应
所以用修改的caffe,prototxt 文件和原来的prototxt 文件直接拷贝权重得到修改后prototxt 文件的权重

7、
caffe 上采样层源代码
https://blog.csdn.net/m0_37192554/article/details/105832505
caffe 最大池化源代码,池化添加下取整,ceil_mode:false(不进行上取整)
https://blog.csdn.net/weixin_38501242/article/details/82624071

‘’’

‘’’
上述两个循环,针对json 文件,格式,“inputs”: [[7, 0, 0], [8, 0, 0], [9, 0, 0], [10, 0, 0], [11, 0, 0]],这个输入
表示有参数的层 的键值对信息,添加
json文件,对照看,op 很多是Null, 例如bn 层,前面几层是bn层相关的参数,op=null, 不是空的时候,inputs不是空,其列表索引是bn参数信息
例如下

{
“nodes”: [
{
“op”: “null”,
“name”: “data”,
“inputs”: []
},
{
“op”: “null”,
“name”: “bn_data_gamma”,
“inputs”: []
},
{
“op”: “null”,
“name”: “bn_data_beta”,
“inputs”: []
},
{
“op”: “null”,
“name”: “bn_data_moving_mean”,
“attrs”: {
init”: “[“zero”, {}]”,
“eps”: “2e-05”,
“fix_gamma”: “True”,
“momentum”: “0.9”,
“use_global_stats”: “False”
},
“inputs”: []
},
{
“op”: “null”,
“name”: “bn_data_moving_var”,
“attrs”: {
init”: “[“one”, {}]”,
“eps”: “2e-05”,
“fix_gamma”: “True”,
“momentum”: “0.9”,
“use_global_stats”: “False”
},
“inputs”: []
},
{
“op”: “BatchNorm”,
“name”: “bn_data”,
“attrs”: {
“eps”: “2e-05”,
“fix_gamma”: “True”,
“momentum”: “0.9”,
“use_global_stats”: “False”
},
“inputs”: [[0, 0, 0], [1, 0, 0], [2, 0, 0], [3, 0, 0], [4, 0, 0]]
},

[0, 0, 0],第一个元素0,是该层输入层的索引bottom, name是data
[1, 0, 0], [2, 0, 0], [3, 0, 0], [4, 0, 0] 第一个元素1,2,3,4,是该层输入参数索引,

#############一下面为例子,循环过程的操作
{
“nodes”: [
{
“op”: “null”,
“name”: “data”,
“inputs”: []
},
{
“op”: “null”,
“name”: “mobilenet0_conv0_weight”,
“attrs”: {
dtype”: “0”,
lr_mult”: “1.0”,
shape”: “(8L, 3L, 3L, 3L)”,
storage_type”: “0”,
wd_mult”: “1.0”
},
“inputs”: []
},
{
“op”: “Convolution”,
“name”: “mobilenet0_conv0_fwd”,
“attrs”: {
“dilate”: “(1, 1)”,
“kernel”: “(3, 3)”,
“layout”: “NCHW”,
“no_bias”: “True”,
“num_filter”: “8”,
“num_group”: “1”,
“pad”: “(1, 1)”,
“stride”: “(2, 2)”
},
“inputs”: [[0, 0, 0], [1, 0, 0]]
},

这里是0 1 2索引 3键值对
遍历字典元素,op null 都continue
直到 op 不是null,这时候,字典变量node_i 等于当前的卷积层所有参数,top name 和当前层的名字一致
然后再循环"inputs"列表成员的第一个元素,得到bootom name,和而外参数,例如卷积层没有额外参数,
但是bn层除了当前层的参数,还有而外参数层,(这不在网络结构中,只是保存的时候添加的一些层,作为参数保存的多余的层)
虽然是多余的层,但是参数不多于,参数需要提取出来,info[‘params’]添加的是"inputs"列表索引第2个及以后的成员信息的json文件的名字,
例如这里存储的就是 ,mobilenet0_conv0_weight,方便 权重复制到caffe里面寻找,mxnet权重名字,得到权重的信息
info[‘params’] 存储的是层对应的参数的名字,如果层名字不是对应关系,
例如参数名字"mobilenet0_conv1_weight",层名字"mobilenet0_conv1_fwd",多了fwd,
caffe prototxt ,把这个名字,写出来,可以不写,模型本身无用,这是mxnet 这一层的权重名字,
多添加caffe该层的一个信息,
param {
name: “mobilenet0_conv1_weight”
}

‘’’

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值