深度學習【19】ncnn安卓搭建並使用自己的模型

NO IMAGE

ncnn安卓搭建並使用自己的模型

github上面已經給了一個ncnn的安卓例子,地址:https://github.com/dangbo/ncnn-mobile
clone 這個專案後用Android studio就可以開啟(12.19更新:這個專案已經更改,不能直接執行,需要自己編譯ncnn,然後更改ncnn-mobile/squeezencnn-AS/app/src/main/jni/Android.mk中的ncnn安裝路徑)。

使用自己的模型

我這邊的例子是caffe轉ncnn,然後ncnn轉memery。
以alexnet為例。
1、首先下載caffe模型,

deploy.prototxt: https://github.com/BVLC/caffe/tree/master/models/bvlc_alexnet
caffemodel:http://dl.caffe.berkeleyvision.org/bvlc_alexnet.caffemodel

2、因為這個alexnet的caffe版本比較老,ncnn不支援。需要用caffe自帶的轉換工具,轉成最新的caffe版本。用一下兩個命令(這兩個命令,需要安裝最新的caffe):

upgrade_net_proto_text [老prototxt] [新prototxt]
upgrade_net_proto_binary [老caffemodel] [新caffemodel]

3、在deploy.prototxt中將caffe的輸入層改成input層:

layer {
name: "data"
type: "Input"
top: "data"
input_param { shape: { dim: 1 dim: 3 dim: 227 dim: 227 } }
}

4、用caffe2ncnn將caffe版本alexnet轉成ncnn的

caffe2ncnn deploy.prototxt bvlc_alexnet.caffemodel alexnet.param alexnet.bin

5、用ncnn2mem將ncnn的alexnet的param和bin檔案,轉成嵌入程式碼的形式,並生成安卓demo中的param.bin檔案

ncnn2mem alexnet.param alexnet.bin alexnet.id.h alexnet.mem.h

這時候會額外生成alexnet.param.bin檔案
6、將生成的alexnet.param.bin和alexnet.bin檔案拷貝到ncnn安卓工程的assets資料夾中。並在MainActivity.java中的initSqueezeNcnn函式中讀取param.bin檔案和bin檔案相關程式碼改成讀取alexnet.param.bin和alexnet.bin(可能你還要修改一下輸入影象的大小)

{
InputStream assetsInputStream = getAssets().open("alexnet.param.bin");
int available = assetsInputStream.available();
param = new byte[available];
int byteCode = assetsInputStream.read(param);
assetsInputStream.close();
}
{
InputStream assetsInputStream = getAssets().open("alexnet.bin");
int available = assetsInputStream.available();
bin = new byte[available];
int byteCode = assetsInputStream.read(bin);
assetsInputStream.close();
}

7、在之前生成的alexnet.id.h中檢視輸入層ID和想要抽取的層的ID,或者用alexnet.id.h替換掉squeezenet_v1.1.id.h,使用安卓工程中的例子獲取輸入層ID和抽取層ID(注意:這個ID是BLOB的ID不是LAYER的ID)。
例如我要抽取最後一層的資料,從alexnet.id.h中可知,輸入層為BLOB_data=0,最後一層為BLOB_prob=23。
與安卓工程相似的寫法:

 ex.input(alexnet_param_id::BLOB_data, in);
ex.extract(alexnet_param_id::BLOB_prob, out);

直接寫id:

 ex.input(0, in);
ex.extract(23, out);

最後需要注意的是:

由於ncnn的資料對齊,你可能會發現抽取出來的資料不對,特別要抽取中間層的時候。那麼請使用ncnn中Mat的reshape函式,reshape一下就可以了。

ncnn::Mat out1(out.reshape(w * h * c));//w,h,c:要抽取層的w,h和channel