如今愈來愈多的人選擇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