RtinaFace Mxnet模型转TNN,附Reshape层踩坑
背景说明
我从下面这个位置获取到的RetinaFace模型是mxnet的:
- yangfly: RetinaFace-MobileNet0.25 (baidu cloud:nzof).
TNN提供的模型转换选项如下:
{onnx2tnn,caffe2tnn,tf2tnn,tflite2tnn}
并不支持mxnet直接转换成tnn,那只能将mxnet模型先转换其他格式再转为tnn.
我尝试过从mxnet转为onnx但是会遇到各种问题:
如SoftmaxActivation、UpSampling等算子不支持、以及onnx和mxnet版本不匹配等等
更糟心的是千辛万苦解决了转换路上的问题得到的onnx模型居然不能正确加载或运行…
在此我记录一个能正确转换到tnn的方式,方便后来的人少走弯路,能抛砖引玉就更妙了
模型转换过程
先将mxnet转为caffe,再用tnn转换工具将caffe转为tnn
其实仔细看tnn给的pyhton转换脚本,它的转换过程是caffe->onnx->tnn
哦~,老套路,onnx做中间模型
所以总的转换路线为:
mxnet->caffe->onnx->tnn
我的环境
16.04.1-Ubuntu
Python 3.7.2 (default, Jan 26 2021, 16:01:45)
mxnet 1.7.0
caffe 1.0.0
mxnet to caffe
- 0.下述操作注意换成自己的路径
- 1.clone开源工具 MXNet2Caffe
git clone https://github.com/cypw/MXNet2Caffe
- 2.打开prototxt_basic.py,将输入维度改为要转换的模型对应的维度
txt_file.write(' shape: { dim: 1 dim: 3 dim: 320 dim: 320 }\n')
- 3.通过json2prototxt.py将json转为prototxt
python3.7 ./json2prototxt.py --mx-json model_mxnet/mnet.25-symbol.json --cf-prototxt model_caffe/mnet.25.prototxt
- 4.运行mxnet2caffe.py,将params转为caffemodel
python3.7 ./mxnet2caffe.py --mx-model model_mxnet/mnet.25 --cf-prototxt model_caffe/mnet.25.prototxt --cf-model model_caffe/mnet.25.caffemodel
- 5.一切顺利的话,我们得到两个文件:mnet.25.caffemodel 、 mnet.25.prototxt
caffe to tnn [Reshape层踩坑]
- 1.获取tnn模型转换工具:
docker pull turandotkay/tnn-convert
- 2.将caffe转为tnn.注意下述命令能转化出tnn模型,但是face_rpn_cls_score_reshape_stride32/16/8 三个输出结果是错误的
docker run --volume=$(pwd):/workspace -it turandotkay/tnn-convert:latest python3 ./converter.py caffe2tnn /workspace/mnet.25.prototxt /workspace/mnet.25.caffemodel
模型结果错误排查
-
0.这个太耗时了,想起了苦涩的排查过程
-
1.算法结果输出有三类, 其中结果正确的是face_rpn_bbox_pred_stride、face_rpn_landmark_pred_strid, 错误的是face_rpn_cls_prob_reshape_stride
-
2.进行输出层比对,发现SoftmaxCaffe层上下有两个Reshape操作的shape参数错误,如下图所示(比对模型的关键是找一个能正确输出结果的模型,比如正确caffe模型)
-
3.caffe 中两个shape参数:
修复方法
- 1.查看mnet.25.prototxt文件,发现Reshape层参数形式如下:
type: "Reshape"
reshape_param {
shape {
dim: 2
dim: -1
dim: 0
}
axis: 1
}
- 2.参考[caffe-Reshape层配置], mnet.25.prototxt文件的Reshape层参数是忽略了NCHW中的"N".那把它添加上,"N"设置为1( 只添加 dim: 1),改成如下形式(注意一共要改6处,搜索type: “Reshape”):
type: "Reshape"
reshape_param {
shape {
dim: 1
dim: 2
dim: -1
dim: 0
}
axis: 1
}
3.修改的文件另存为mnet.25.reshape.prototxt, 重新转换
docker run --volume=$(pwd):/workspace -it turandotkay/tnn-convert:latest python3 ./converter.py caffe2tnn /workspace/mnet.25.reshape.prototxt /workspace/mnet.25.caffemodel
- 经过测试,模型转化正确并能正确出结果
思考
- 1.经过上面对caffe的Reshape层的修改,转换出的tnn模型便可以正确解析,所以说明tnn对Reshape参数解析有问题?
- 我们来看两次转换时产生的中间模型onnx,左边是修改前的,右边是修改后的,可以看到修改后确实多了一个维度(从2x20X10变为1x2x20x10),看来是tnn解析onnx时需要完整的输入nchw四个维度信息,否则解析会出错.当然这个推论需要详细了解caffe、onnx、tnn解析模型的代码才能确定.
结案 2021/03/18
上述思考的推理在git上得到tnn成员的回答,感谢这些开源作者的奉献,回复神速
结论: 截止目前 master 分支的代码确实要求模型的输入以及中间每一层都要保持 nchw 四维
详细问答在: [git issues]