MXnet转caffe

mxnet虽好,但是mxnet框架还是有点小众,MXnet现在越来越受欢迎了,不过现在要把mxnet训练的模型部落地到移动端,有必要在Inference阶段将其转换为其他框架,以便后续统一部署和管理。Caffe作为小巧灵活的老资格框架,使用灵活,部署方便,所以尝试将mxnet训练的mobilefacenet模型转换为Caffe。这里简单记录用mxnet训的mobilefacenet模型转换为Caffe模型过程遇到的坑,以及完美解决(转换后精度几乎无损,并没有网上说的会掉点)

先写到这里 以后再慢慢补充(逃跑.JPG)

继续填坑。。。。。。

首先展示下结果,下面这个图是mxnet训的mobilefacenet模型对对一张人脸图片输出的128维特征值

下面这张是将maxnet模型转为caffemodel后,对同一张人脸图片用caffemodel输出的结果

可以看出,基本上是无损的,小数点后5、6位才会出现误差。

下面说明一下实现流程

环境:ubuntu16.04 64bit

          mxnet版本1.4

 

 主要是站在巨人肩膀上,从github上下载相关mxnet2caffe的demo,然后做各种完善。 从此博主开始了填坑之旅~~

  首先下载相应的demo

git clone https://github.com/cypw/MXNet2Caffe.git

  阅览下代码,大概知道流程,就是通过  json2prototxt.py将json转为prototxt, 再运行mxnet2caffe.py,将params转为caffemodel,    这里我们要做一些修改,如下:

 打开json2prototxt.py ,将模型改为我要转的mobilefacenet模型;

   打开prototxt_basic.py,将输入维度改为要转换的模型对应的维度

 打开json文件,看一下里面格式是怎么样的

里面有 "op" 、"name" 和 "attrs"三个索引,“attrs”中又包含其他索引

但是,prototxt_basic.py中,是下面这种形式

如果直接运行json2prototxt.py,会报下面这个错误

修改如下:将'param'改为'attrs' ,就可以了

并添加PReLU和Eltwise层(我们模型需要这两层,原代码中并没有实现,原代码对层支持的很少,不知道为什么还有那么对   start 无奈.gif)

def LeakyReLU(txt_file, info):
  if info['attrs']['act_type'] == 'elu':
    txt_file.write('layer {\n')
    txt_file.write('  bottom: "%s"\n'     % info['bottom'][0])
    txt_file.write('  top: "%s"\n'        % info['top'])
    txt_file.write('  name: "%s"\n'       % info['top'])
    txt_file.write('  type: "ELU"\n')
    txt_file.write('  elu_param { alpha: 0.25 }\n')
    txt_file.write('}\n')
    txt_file.write('\n')
  elif info['attrs']['act_type'] == 'prelu':
    txt_file.write('layer {\n')
    txt_file.write('  bottom: "%s"\n'     % info['bottom'][0])
    txt_file.write('  top: "%s"\n'        % info['top'])
    txt_file.write('  name: "%s"\n'       % info['top'])
    txt_file.write('  type: "PReLU"\n')
    txt_file.write('}\n')
    txt_file.write('\n')      
  else:
    raise Exception("unsupported Activation")

def Eltwise(txt_file, info, op):
  txt_file.write('layer {\n')
  txt_file.write('  type: "Eltwise"\n')
  txt_file.write('  top: "%s"\n'        % info['top'])
  txt_file.write('  name: "%s"\n'       % info['top'])
  for btom in info['bottom']:
      txt_file.write('  bottom: "%s"\n' % btom)
  txt_file.write('  eltwise_param { operation: %s }\n' % op)
  txt_file.write('}\n')
  txt_file.write('\n')

  在prototxt_basic.py文件的write_node函数中添加下面几行

    elif info['op'] == 'LeakyReLU':
        LeakyReLU(txt_file, info)
    elif info['op'] == 'elemwise_add':
        ElementWiseSum(txt_file, info)

 

 运行json2prototxt.py ,结果出现下面这个警告并退出

 从警告可以看出,代码无法识别_minus_scalar这个op

 打开model_mobile_glint_amsoftmax-symbol.json

可以看出,_minus_scalar和_mul_scalar这两个op对输入数据做了归一化,mxnet数据预处理放在了模型里面

在prototxt_basic中,程序没有对这个op做处理,其实也没必要对它做处理,这个op可以直接skip,

在basic_prototxt.py的Convolution函数中,添加如下代码

  if('scalar' in info['bottom'][0] ):
      info['bottom'][0] = 'data'

如下图所示

至此,我们就可以成功将json转为prototxt了

 

为了解决在转参数时的名字匹配问题

打开mxnet2caffe.py,将第42行的elif '_gamma' in key_i: 改为 elif '_gamma' in key_i  and 'relu' not in key_i :

取消第44行到底46行的注释,如下图所示

至此,就可以成功运行mxnet2caffe.py了

 

 

但是,校验最后一层输出的时候 ,发现数据对不上,差异非常大,后来又对比了第一个卷积层的输出,数据完全对的上。

后来发现是卷积之后第一个全连接层的问题,,名字不匹配,转出来的caffe模型全连接层的name="pre_fc1", 全连接层之后接的batchnorm层名字叫"fc1",但是mxnet获得的全连接层权重信息字段是“fc1_weight”,replace("_weight")后变为“fc1”,程序相当于把mxnet全连接层的权重信息赋值给net.params["fc1"],也就是赋值给caffe全连接之后的batchnorm层,所有出现了错误

手动将mxnet全连接层的参数赋值给caffe对应的全连接层,全连接之后的batchnorm和scale层的值也有重新赋值

有一点要注意,我们mobilefacenet全连接之后的bn用的是fix_gamma形式

但是mxnet模型对应的gamma参数为0.00030139,这个值并没有用到,caffe 相应的gamma参数有等于1才行,eps的值也要改为2e-5。

至此,模型转换成功~~~

 

对mxnet转caffe的一点见解:

 如果出现误差,往往都是eps引起的,mxnet模型1e-3 caffe默认1e-5 这点要注意,fix_gamma的问题也要注意,同时也要保证每一层的参数都要正确赋值。在验证的时候,一定会要保证数据预处理的方式一致。

 

 

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值