Ubuntu16.04---腾讯NCNN框架入门到应用

前端之家收集整理的这篇文章主要介绍了Ubuntu16.04---腾讯NCNN框架入门到应用前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

Ubuntu16.04—腾讯NCNN框架入门到应用


前言

两天前腾讯发布NCNN深度学习框架后,发现可能有些同学对如何使用这些框架并不是十分的了解,一方面这是一个新的框架,另一方面Tencent出的文档对一些细节没有叙述,可能大牛们觉得很容易的步骤,我们往往会卡在那里,所以写下这篇博客来帮助一些对NCNN框架不是很熟悉的人来快速入门。
NCNN源码的地址为https://github.com/Tencent/ncnn


在Ubuntu上安装NCNN

1. 下载编译源码

ruyiwei@ruyiwei:~/code$ git clone https://github.com/Tencent/ncnn

下载完成后,需要对源码进行编译

cd ncnn
mkdir build && cd build
cmake ..
make -j
make install

执行完毕后我们可以看到

Install the project...
-- Install configuration: "release" -- Installing: /home/ruyiwei/code/ncnn/build/install/lib/libncnn.a -- Installing: /home/ruyiwei/code/ncnn/build/install/@H_502_61@include/blob.h -- Installing: /home/ruyiwei/code/ncnn/build/install/@H_502_61@include/cpu.h -- Installing: /home/ruyiwei/code/ncnn/build/install/@H_502_61@include/layer.h -- Installing: /home/ruyiwei/code/ncnn/build/install/@H_502_61@include/mat.h -- Installing: /home/ruyiwei/code/ncnn/build/install/@H_502_61@include/net.h -- Installing: /home/ruyiwei/code/ncnn/build/install/@H_502_61@include/opencv.h -- Installing: /home/ruyiwei/code/ncnn/build/install/@H_502_61@include/platform.h

我们进入 ncnn/build/tools 目录下,如下所示,我们可以看到已经生成了 caffe2ncnn 可ncnn2mem这两个可执行文件,这两个可执行文件的作用是将caffe模型生成ncnn 模型,并且对模型进行加密,具体的使用方法我门在下一节讲述。

ruyiwei@ruyiwei:~/code/ncnn/build/tools$ ll
total 3024
drwxrwxr-x 3 ruyiwei ruyiwei    4096 727 15:36 ./
drwxrwxr-x 6 ruyiwei ruyiwei    4096 727 15:36 ../
-rwxrwxr-x 1 ruyiwei ruyiwei  833720 727 15:36 caffe2ncnn*
-rw-rw-r-- 1 ruyiwei ruyiwei 1102486 727 15:36 caffe.pb.cc
-rw-rw-r-- 1 ruyiwei ruyiwei  894690 727 15:36 caffe.pb.h
drwxrwxr-x 4 ruyiwei ruyiwei    4096 727 15:36 CMakeFiles/
-rw-rw-r-- 1 ruyiwei ruyiwei    1018 727 15:36 cmake_install.cmake
-rw-rw-r-- 1 ruyiwei ruyiwei    9353 727 15:36 Makefile
-rwxrwxr-x 1 ruyiwei ruyiwei  228032 727 15:36 ncnn2mem*

2. 将caffe下AlexNet网络模型转换为NCNN模型

我们在测试的过程中需要caffemodel以及deploy.prototxt,所以我们再将caffe模型转换为NCNN模型的时候,同样也需要caffemodel以及deploy.prototxt这两个文件,为了方便,我们使用AlexNet为例讲解。

AlexNet 的 deploy.prototxt 可以在这里下载 https://github.com/BVLC/caffe/tree/master/models/bvlc_alexnet
AlexNet 的 caffemodel 可以在这里下载 http://dl.caffe.berkeleyvision.org/bvlc_alexnet.caffemodel

由于NCNN提供的转换工具只支持转换新版的caffe模型,所以我们需要利用caffe自带的工具将旧版的caffe模型转换为新版的caffe模型后,在将新版本的模型转换为NCNN模型.

旧版本caffe模型->新版本caffe模型->NCNN模型

2.1 旧版caffe模型转新版caffe模型

我们执行如下命令.[要记得修改路径]

ruyiwei@ruyiwei:~/code/ncnn/build/tools$ ~/caffe/build/tools/upgrade_net_proto_text deploy.prototxt new_deplpy.prototxt
ruyiwei@ruyiwei:~/code/ncnn/build/tools$ ~/caffe/build/tools/upgrade_net_proto_binary bvlc_AlexNet.caffemodel new_bvlc_AlexNet.caffemodel

上面的命令需要根据自己的caffe位置进行修改

执行后,就可以生成新的caffe模型.

因为我们每次检测一张图片,所以要对新生成的deploy.prototxt进行修改:第一个 dim 设为 1

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

2.2 新版caffe模型转ncnn模型

ruyiwei@ruyiwei:~/code/ncnn/build/tools$./caffe2ncnn new_deplpy.prototxt new_bvlc_AlexNet.caffemodel AlexNet.param AlexNet.bin

执行上面命令后就可以生成NCNN模型需要的param 与bin 文件.

ruyiwei@ruyiwei:~/code/ncnn/build/tools$ ll
total 717492
drwxrwxr-x 3 ruyiwei ruyiwei      4096 727 16:13 ./
drwxrwxr-x 6 ruyiwei ruyiwei      4096 727 15:36 ../
-rw-rw-r-- 1 ruyiwei ruyiwei 243860928 727 16:13 AlexNet.bin
-rw-rw-r-- 1 ruyiwei ruyiwei      1583 727 16:13 AlexNet.param
-rw-rw-r-- 1 ruyiwei ruyiwei 243862414 727 09:28 bvlc_AlexNet.caffemodel
-rwxrwxr-x 1 ruyiwei ruyiwei    833720 727 15:36 caffe2ncnn*
-rw-rw-r-- 1 ruyiwei ruyiwei   1102486 727 15:36 caffe.pb.cc
-rw-rw-r-- 1 ruyiwei ruyiwei    894690 727 15:36 caffe.pb.h
drwxrwxr-x 4 ruyiwei ruyiwei      4096 727 15:36 CMakeFiles/
-rw-rw-r-- 1 ruyiwei ruyiwei      1018 727 15:36 cmake_install.cmake
-rw-rw-r-- 1 ruyiwei ruyiwei      3629 66 21:40 deploy.prototxt
-rw-rw-r-- 1 ruyiwei ruyiwei      9353 727 15:36 Makefile
-rwxrwxr-x 1 ruyiwei ruyiwei    228032 727 15:36 ncnn2mem*
-rw-rw-r-- 1 ruyiwei ruyiwei 243862660 727 16:03 new_bvlc_AlexNet.caffemodel
-rw-r--r-- 1 ruyiwei ruyiwei      3662 727 16:03 new_deplpy.prototxt

3. 对模型参数加密

得到的AlexNet.param是明文可见的,往往发布的过程需要对这些文件进行加密,NCNN提供了对应的加密工具,ncnn2mem,

ruyiwei@ruyiwei:~/code/ncnn/build/tools$ ./ncnn2mem AlexNet.param AlexNet.bin AlexNet.id.h AlexNet.mem.h

最后可以生成 AlexNet.param.bin 这样的二进制加密文件.

对于加密文件的读取也和原来不同,在源码中,非加密param读取方式为

ncnn::Net net;
net.load_param("AlexNet.param");
net.load_model("AlexNet.bin");

加密param.bin读取方式为

ncnn::Net net;
net.load_param_bin("AlexNet.param.bin");
net.load_model("AlexNet.bin");

4. 编译NCNN例程

前面介绍了如何将caffe模型转为NCNN模型并且加密,最后我们来编译NCNN的例程,这样可以更直观的运行或者理解NCNN.
首先我们需要进入ncnn/examples目录
新建一个makefile,内容如下,最重要的是,NCNN例程序支持opencv2,不支持opencv3.

NCNN = /home/ruyiwei/code/ncnn

OPENCV = /home/ruyiwei/Downloads/opencv-2.4.13

INCPATH =       -I${NCNN}/build/install/@H_502_61@include \
                -I${OPENCV}/modules/objdetect/@H_502_61@include \
                -I${OPENCV}/modules/highgui/@H_502_61@include \
                -I${OPENCV}/modules/imgproc/@H_502_61@include \
                -I${OPENCV}/modules/core/@H_502_61@include

LIBS = -lopencv_core -lopencv_highgui -lopencv_imgproc  \
                -fopenmp -pthread

LIBPATH = -L${OPENCV}/build/lib

%:%.cpp
        $(CXX) $(INCPATH) $(LIBPATH) $^ ${NCNN}/build/install/lib/libncnn.a $(LIBS) -o $@

在当前目录执行

ruyiwei@ruyiwei:~/code/ncnn/examples$ ./squeezenet test.jpg

可得到如下结果

ruyiwei@ruyiwei:~/code/ncnn/examples$ ./squeezenet test.jpg 
404 = 0.990161
908 = 0.004498
405 = 0.004008

test.jpg 为下图所示:

为了可以更直观的显示,我们修改代码如下:

#include <stdio.h>
#include <algorithm>
#include <vector>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
@H_502_61@using @H_502_61@namespace std;
@H_502_61@using @H_502_61@namespace cv;
#include "net.h"

@H_502_61@static @H_502_61@int detect_squeezenet(@H_502_61@const cv::Mat& bgr,std::vector<@H_502_61@float>& cls_scores)
{
    ncnn::Net squeezenet;
    squeezenet.load_param("squeezenet_v1.1.param");
    squeezenet.load_model("squeezenet_v1.1.bin");

    ncnn::Mat in = ncnn::Mat::from_pixels_resize(bgr.data,ncnn::Mat::PIXEL_BGR,bgr.cols,bgr.rows,227,227);

    @H_502_61@const @H_502_61@float mean_vals[3] = {104.f,117.f,123.f};
    in.substract_mean_normalize(mean_vals,0);

    ncnn::Extractor ex = squeezenet.create_extractor();
    ex.set_light_mode(@H_502_61@true);

    ex.input("data",in);

    ncnn::Mat out;
    ex.extract("prob",out);

    cls_scores.resize(out.c);
    @H_502_61@for (@H_502_61@int j=0; j<out.c; j++)
    {
        @H_502_61@const @H_502_61@float* prob = out.data + out.cstep * j;
        cls_scores[j] = prob[0];
    }

    @H_502_61@return 0;
}

@H_502_61@static @H_502_61@int print_topk(@H_502_61@const std::vector<@H_502_61@float>& cls_scores,@H_502_61@int topk,vector<@H_502_61@int>& index_result,vector<@H_502_61@float>& score_result)
{
    // partial sort topk with index
    @H_502_61@int size = cls_scores.size();
    std::vector< std::pair<@H_502_61@float,@H_502_61@int> > vec;
    vec.resize(size);
    @H_502_61@for (@H_502_61@int i=0; i<size; i++)
    {
        vec[i] = std::make_pair(cls_scores[i],i);
    }

    std::partial_sort(vec.begin(),vec.begin() + topk,vec.end(),std::greater< std::pair<@H_502_61@float,@H_502_61@int> >());

    // print topk and score
    @H_502_61@for (@H_502_61@int i=0; i<topk; i++)
    {
        @H_502_61@float score = vec[i].first;
        @H_502_61@int index = vec[i].second;
        index_result.push_back(index);
        score_result.push_back(score);

        //fprintf(stderr,"%d = %f\n",index,score);
    }

    @H_502_61@return 0;
}

@H_502_61@static @H_502_61@int load_labels(string path,vector<string>& labels)
{
    FILE* fp = fopen(path.c_str(),"r");

    @H_502_61@while (!feof(fp))
    {
        @H_502_61@char str[1024];
        fgets(str,1024,fp);  //¶ÁÈ¡Ò»ÐÐ
        string str_s(str);

        @H_502_61@if (str_s.length() > 0)
        {
            @H_502_61@for (@H_502_61@int i = 0; i < str_s.length(); i++)
            {
                @H_502_61@if (str_s[i] == ' ')
                {
                    string strr = str_s.substr(i,str_s.length() - i - 1);
                    labels.push_back(strr);
                    i = str_s.length();
                }
            }
        }
    }
    @H_502_61@return 0;
}


@H_502_61@int main(@H_502_61@int argc,@H_502_61@char** argv)
{
    @H_502_61@const @H_502_61@char* imagepath = argv[1];
    vector<string> labels;
    load_labels("synset_words.txt",labels);
    cv::Mat m = cv::imread(imagepath,CV_LOAD_IMAGE_COLOR);
    @H_502_61@if (m.empty())
    {
        fprintf(stderr,"cv::imread %s Failed\n",imagepath);
        @H_502_61@return -1;
    }

    std::vector<@H_502_61@float> cls_scores;
    detect_squeezenet(m,cls_scores);

    vector<@H_502_61@int> index;
    vector<@H_502_61@float> score;
    print_topk(cls_scores,3,score);


    @H_502_61@for (@H_502_61@int i = 0; i < index.size(); i++)
    {
       cv::putText(m,labels[index[i]],Point(50,50 + 30 * i),CV_FONT_HERSHEY_SIMPLEX,1.2,Scalar(0,100,200),2,8);
    }

    imshow("m",m);
    imwrite("test_result.jpg",m);
    waitKey(0);

    @H_502_61@return 0;
}

这样就可以直观的显示出具体的类别,而不是数字,结果如下:

感谢

https://github.com/guozhongluo/ncnn-vs2015-examples-demo
https://github.com/Tencent/ncnn/wiki

原文链接:https://www.f2er.com/ubuntu/351964.html

猜你在找的Ubuntu相关文章