使用C++版本Mxnett进行预测的注意事项
現(xiàn)在越來(lái)越多的人選擇Mxnet作為深度學(xué)習(xí)框架,相應(yīng)的中文社區(qū)非常活躍,而且后面推出的gluon以及gluoncv非常適合上手和實(shí)驗(yàn),特別是gluoncv中提供了非常多、非常新的預(yù)訓(xùn)練model zoo,比如像yolov3這種~~不過(guò)網(wǎng)上(包括Mxnet社區(qū)、gluon論壇等等)大多是關(guān)于Python版本的話題,關(guān)于C++版本的資料卻非常少,最近在用C++版本的mxnet,進(jìn)行人臉檢測(cè)和識(shí)別,踩到不少的坑,在這里總結(jié)一下。
1.C++版本的Mxnet需要進(jìn)行手動(dòng)編譯,里面有不同的數(shù)學(xué)計(jì)算加速方式,比如MKL,MKLDNN或者openblas(前者主要針對(duì)Intel的cpu架構(gòu),后者是一個(gè)比較通用的線性代數(shù)優(yōu)化庫(kù),MKLDNN針對(duì)神經(jīng)網(wǎng)絡(luò)進(jìn)行優(yōu)化)等等,編譯完成之后可以使用里面的c_api,即#include <mxnet/c_predict_api.h>或者使用提供的cpp的api:#include "mxnet-cpp/MxNetCpp.h"。
2.如果手動(dòng)編譯過(guò)Mxnet會(huì)發(fā)現(xiàn)Mxnet實(shí)際上是好幾個(gè)項(xiàng)目的集合,比如NNVM,mshadow,dmlc等等,后端引擎負(fù)責(zé)真正的計(jì)算部分,前端實(shí)現(xiàn)接口調(diào)用,而且作者花了大部分精力圍繞在Python接口的編寫上,所以關(guān)于Python方面的接口非常多,而像C、C++的接口真的很少,不過(guò)Mxnet是一個(gè)經(jīng)常進(jìn)行更新的項(xiàng)目,所以以后是否會(huì)完善這些拭目以待。
3.性能時(shí)間度量。以下:
(1)一定要注意mxnet前端語(yǔ)言可能會(huì)異步調(diào)用后端的計(jì)算結(jié)果,以Python為例,當(dāng)你使用CPU對(duì)比較深的resnet模型進(jìn)行一次預(yù)測(cè),有時(shí)發(fā)現(xiàn)耗僅僅數(shù)毫秒,而在后面的asnumpy時(shí)卻使用了上百毫秒。避免這種情況出現(xiàn)的最好方式就是使用mxnet.ndarray.waitall(),強(qiáng)制等待前面的操作執(zhí)行完成;
(2)很多操作第一次都會(huì)比較耗時(shí),比如load參數(shù)到內(nèi)存,甚至像opencv中的resize有時(shí)第一次也會(huì)比較耗時(shí),所以如果想公平的統(tǒng)計(jì)某一時(shí)段的時(shí)間開(kāi)銷,最好是先手動(dòng)執(zhí)行一次,然后跑多個(gè)loop取平均值進(jìn)行比較。有些同學(xué)拿imread一次預(yù)測(cè)然后統(tǒng)計(jì)時(shí)間,這樣的話相當(dāng)于把load參數(shù)等相關(guān)開(kāi)銷都計(jì)算在內(nèi)了,這是不適合的;
(3)關(guān)于batch操作。不止訓(xùn)練階段有batch操作,預(yù)測(cè)(predict或者inference)也有,比如做人臉識(shí)別,需要把檢測(cè)出來(lái)的多個(gè)人臉的bounding box的圖像分別摳出來(lái)然后組成一個(gè)batch,這時(shí)候識(shí)別網(wǎng)絡(luò)的輸入就是batch_num x channel x high x width。為什么需要進(jìn)行batch操作?假如我們使用GPU,很明顯可以進(jìn)行cuda并行計(jì)算大大加快處理速度;如果使用CPU的話某些數(shù)學(xué)優(yōu)化庫(kù)也會(huì)讓這個(gè)速度有一定提升,不過(guò)相比較而言不是非常明顯;使用batch操作非常需要注意的是一定要考慮內(nèi)存是否足夠,實(shí)際處理的時(shí)候要評(píng)估一下最大的batch數(shù)目,否則很容易o(hù)ut of memory;
4.關(guān)于Mxnet C/C++的預(yù)測(cè),一般用MXPredCreate創(chuàng)建識(shí)別引擎PredictorHandle,然后使用MXPredSetInput設(shè)置輸入,用MXPredForward進(jìn)行預(yù)測(cè),一定要注意的是創(chuàng)建的PredictorHandle在使用完之后一定別忘調(diào)用MXPredFree釋放,否則跑多次內(nèi)存會(huì)泄漏的非常快。另外要注意C/C++提供的api中,預(yù)測(cè)的時(shí)候MXPredSetInput設(shè)置的參數(shù)維度是固定的,比如當(dāng)你的batch數(shù)變化的時(shí)候PredictorHandle也需要改變,為了feed不同的輸入,可以用MXPredReshape重新改變batch_num x channel x high x width的輸入形狀,而不需要每次重新load參數(shù)再調(diào)MXPredCreate,因?yàn)镸XPredCreate的開(kāi)銷非常大,相比較而言MXPredReshape的開(kāi)銷小一些。但MXPredReshape也并不是一點(diǎn)開(kāi)銷沒(méi)有,當(dāng)你需要識(shí)別的人臉數(shù)的batch一直在變,頻繁的reshape形狀毫無(wú)疑問(wèn)開(kāi)銷就會(huì)顯得比較大,這樣就有一個(gè)問(wèn)題:怎么在使用loop進(jìn)行識(shí)別(也就是對(duì)于每個(gè)人臉都丟進(jìn)網(wǎng)絡(luò)里,輸入是1 x channel x high x width識(shí)別完一個(gè)再接著下一個(gè))和batch方式(輸入是batch_num?x channel x high x width)之間進(jìn)行權(quán)衡?我覺(jué)得一方面要考慮使用的網(wǎng)絡(luò)在使用batch時(shí)到底能提升多大,一方面也需要考慮MXPredReshape本身的開(kāi)銷,比如我們可以設(shè)置一個(gè)batch數(shù)的閾值,當(dāng)大于這個(gè)值的時(shí)候進(jìn)行MXPredReshape,否則直接循環(huán)進(jìn)行預(yù)測(cè)。
轉(zhuǎn)載于:https://www.cnblogs.com/supersayajin/p/10288157.html
總結(jié)
以上是生活随笔為你收集整理的使用C++版本Mxnett进行预测的注意事项的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Android自定义圆形进度条
- 下一篇: 易天光通信ETU 25G SFP28光模