如今愈来愈多的人选择Mxnet做为深度学习框架,相应的中文社区很是活跃,并且后面推出的gluon以及gluoncv很是适合上手和实验,特别是gluoncv中提供了很是多、很是新的预训练model zoo,好比像yolov3这种~~不过网上(包括Mxnet社区、gluon论坛等等)大可能是关于Python版本的话题,关于C++版本的资料却很是少,最近在用C++版本的mxnet,进行人脸检测和识别,踩到很多的坑,在这里总结一下。前端
1.C++版本的Mxnet须要进行手动编译,里面有不一样的数学计算加速方式,好比MKL,MKLDNN或者openblas(前者主要针对Intel的cpu架构,后者是一个比较通用的线性代数优化库,MKLDNN针对神经网络进行优化)等等,编译完成以后可使用里面的c_api,即#include <mxnet/c_predict_api.h>或者使用提供的cpp的api:#include "mxnet-cpp/MxNetCpp.h"。后端
2.若是手动编译过Mxnet会发现Mxnet其实是好几个项目的集合,好比NNVM,mshadow,dmlc等等,后端引擎负责真正的计算部分,前端实现接口调用,并且做者花了大部分精力围绕在Python接口的编写上,因此关于Python方面的接口很是多,而像C、C++的接口真的不多,不过Mxnet是一个常常进行更新的项目,因此之后是否会完善这些拭目以待。api
3.性能时间度量。如下:网络
(1)必定要注意mxnet前端语言可能会异步调用后端的计算结果,以Python为例,当你使用CPU对比较深的resnet模型进行一次预测,有时发现耗仅仅数毫秒,而在后面的asnumpy时却使用了上百毫秒。避免这种状况出现的最好方式就是使用mxnet.ndarray.waitall(),强制等待前面的操做执行完成;架构
(2)不少操做第一次都会比较耗时,好比load参数到内存,甚至像opencv中的resize有时第一次也会比较耗时,因此若是想公平的统计某一时段的时间开销,最好是先手动执行一次,而后跑多个loop取平均值进行比较。有些同窗拿imread一次预测而后统计时间,这样的话至关于把load参数等相关开销都计算在内了,这是不适合的;框架
(3)关于batch操做。不止训练阶段有batch操做,预测(predict或者inference)也有,好比作人脸识别,须要把检测出来的多我的脸的bounding box的图像分别抠出来而后组成一个batch,这时候识别网络的输入就是batch_num x channel x high x width。为何须要进行batch操做?假如咱们使用GPU,很明显能够进行cuda并行计算大大加快处理速度;若是使用CPU的话某些数学优化库也会让这个速度有必定提高,不过相比较而言不是很是明显;使用batch操做很是须要注意的是必定要考虑内存是否足够,实际处理的时候要评估一下最大的batch数目,不然很容易out of memory;异步
4.关于Mxnet C/C++的预测,通常用MXPredCreate建立识别引擎PredictorHandle,而后使用MXPredSetInput设置输入,用MXPredForward进行预测,必定要注意的是建立的PredictorHandle在使用完以后必定别忘调用MXPredFree释放,不然跑屡次内存会泄漏的很是快。另外要注意C/C++提供的api中,预测的时候MXPredSetInput设置的参数维度是固定的,好比当你的batch数变化的时候PredictorHandle也须要改变,为了feed不一样的输入,能够用MXPredReshape从新改变batch_num x channel x high x width的输入形状,而不须要每次从新load参数再调MXPredCreate,由于MXPredCreate的开销很是大,相比较而言MXPredReshape的开销小一些。但MXPredReshape也并非一点开销没有,当你须要识别的人脸数的batch一直在变,频繁的reshape形状毫无疑问开销就会显得比较大,这样就有一个问题:怎么在使用loop进行识别(也就是对于每一个人脸都丢进网络里,输入是1 x channel x high x width识别完一个再接着下一个)和batch方式(输入是batch_num x channel x high x width)之间进行权衡?我以为一方面要考虑使用的网络在使用batch时到底能提高多大,一方面也须要考虑MXPredReshape自己的开销,好比咱们能够设置一个batch数的阈值,当大于这个值的时候进行MXPredReshape,不然直接循环进行预测。oop