欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

腾讯开源ncnn:Ubuntu下运行示例

程序员文章站 2022-07-13 17:15:30
...

本博记录为卤煮使用时的记录,如有疏漏,请指正。

卤煮:非文艺小燕儿

本博地址:腾讯开源ncnn:Ubuntu下运行示例

感谢开源共享的各位大牛们,让我们能够站在巨人的肩膀上前行。


ncnn Git:https://github.com/Tencent/ncnn

ncnn 是一个为手机端极致优化的高性能神经网络前向计算框架。ncnn 从设计之初深刻考虑手机端的部署和使用。无第三方依赖,跨平台,手机端 cpu 的速度快于目前所有已知的开源框架。基于 ncnn,开发者能够将深度学习算法轻松移植到手机端高效执行,开发出人工智能 APP,将 AI 带到你的指尖。ncnn 目前已在腾讯多款应用中使用,如 QQ,Qzone,微信,天天P图等。


本文直接使用ncnn开源代码内的CMakeList.txt直接进行编译运行,非常简单快捷。

环境:Ubuntu16.04+opencv2.4.13


示例程序依赖opencv库,有关opencv的安装,可以参照:http://blog.csdn.net/u011557212/article/details/54706966?utm_source=itdadao&utm_medium=referral,亲测好用(最好完全按照步骤操作)。



环境准备妥当,进入编译生成的正题。

(1)git下载ncnn工程,解压。

(2)根目录下,通过终端命令窗口执行以下操作:

mkdir build    #创建build文件夹,用来存放编译生成的文件

cd build #打开build文件

cmake .. #编译根目录下的CMakeLists.txt

此时没有意外的话,会报错如下:

腾讯开源ncnn:Ubuntu下运行示例


这是因为编译了caffe2ncnn相关的tools,也就是将caffemodel转化成ncnn识别的param和bin文件的工具。不编译这个的话,运行示例没有问题,但是如果想用自己的模型的话,需要配置caffe后再编译。由于示例程序已经给好了param和bin文件,所以这里就偷个懒,不编译了。


打开根目录下的CMakeLists.txt文件,定位到最后几行,修改如下:

腾讯开源ncnn:Ubuntu下运行示例

修改内容,一个是放开examples的编译,一个是关掉tools的编译。保存修改后,终端命令定位在build路径下。

再次输入:

cmake ..

make


通过红色的log可以看出生成了一个静态库build/src/libncnn.a和一个可执行文件build/examples/squeezenet。

网上随便下载一张汪汪或者喵喵 whatever you like,放置在可执行文件squeezenet路径下。

然后再把ncnn-master/example文件夹下的模型文件(下图选中的三个)放置在可执行文件squeezenet路径下。

腾讯开源ncnn:Ubuntu下运行示例

然后终端命令窗口定位在可执行文件squeezenet路径下,输入下面指令:

./squeezenet test.jpg

其中test.jpg是你下载的图片的名称,便可以运行示例。


你也可以通过修改示例代码squeezenet,从而更直观的看到运行结果。修改后重新执行上述的Cmake,make指令。修改示例如下:

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

static int detect_squeezenet(const cv::Mat& bgr, std::vector<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);

    const 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(true);

    ex.input("data", in);

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

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

    return 0;
}

static int print_topk(const std::vector<float>& cls_scores, int topk, vector<int>& index_result, vector<float>& score_result)
{
    // partial sort topk with index
    int size = cls_scores.size();
    std::vector< std::pair<float, int> > vec;
    vec.resize(size);
    for (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<float, int> >());

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

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

    return 0;
}

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

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

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


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

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

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


    for (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);

    return 0;
}

运行结果:

腾讯开源ncnn:Ubuntu下运行示例



本来是很简单的事情。由于对Ubuntu和CMake懵懵懂懂,走了一些弯路,这点儿问题折腾了两天。也参考过Ubuntu16.04---腾讯NCNN框架入门到应用,但是卡在生成示例程序那块,用作者的makefile运行总是出错,估计是配置问题,好头疼。折腾了makefile,甚至还折腾了g++编译,最后都是说找不到lncnn。

最终还是在git上向nihui大神请教,分分钟就得到了回复,直至此时才解决了所有问题,成功运行。参考:https://github.com/Tencent/ncnn/issues/69


虽然在这个简单的问题上,耗费了两天之久,但终于扫清所有问题,还是非常开心。

毕竟有问题的时候才会有动力和进步嘛。


共勉,祝顺利。



相关标签: ncnn