您现在的位置是:首页 >技术交流 >树莓派下部署NCNN网站首页技术交流

树莓派下部署NCNN

TTao9 2024-07-04 12:01:03
简介树莓派部署神经网络

树莓派下部署NCNN

安装树莓派

树莓派的烧录,网上的教程有很多,这里就不赘述了,比如该博客树莓派(4B)镜像烧录及环境配置保姆级教程

安装依赖

首先需要安装下git和cmake依赖、其他依赖。

sudo apt-get install git cmake
sudo apt-get install -y gfortran
sudo apt-get install -y libprotobuf-dev libleveldb-dev libsnappy-dev libopencv-dev libhdf5-serial-dev protobuf-compiler
sudo apt-get install --no-install-recommends libboost-all-dev
sudo apt-get install -y libgflags-dev libgoogle-glog-dev liblmdb-dev libatlas-base-dev

这里有可能下载不成功,报503的错误,那需要换apt-get的源:

选输入下面命令查看你的树莓派对应的系统版本,比如“buster”

lsb_release -a

在这里插入图片描述

之后执行脚本

sudo vim /etc/apt/sources.list

将里面的两行注释#,加上下面两句换成清华源

deb http://mirrors.tuna.tsinghua.edu.cn/raspbian/raspbian/ buster main contrib non-free rpi
deb-src http://mirrors.tuna.tsinghua.edu.cn/raspbian/raspbian/ buster main contrib non-free rpi

主要是这个网址换掉原来的那个网址,其他保持不变

最后更新一下

sudo apt update

有可能所有些没更新,要你用旧的,但是问题不大.

只要上面的依赖都能成功安装,那就没问题了

编译ncnn

下载ncnn源码

https://github.com/Tencent/ncnn.git
cd ncnn

编译源码,在ncnn目录下

mkdir build
cd build
cmake ../
make -j4
make install 

部署resnet18

这里只要需要用到精简化后的onnx文件,可以参考我的上一篇博客在windows下使用ncnn部署加速神经网络(以resnet18为例)_TTao9的博客-CSDN博客里面会教怎么导出精简化后的onnx文件,之后跟上一篇博客一样,进入编译后的build文件夹下的installin下,其实可以单独吧这个文件夹下的exe都复制到另外一个文件夹,制作成ncnn转换工具

之后打开ncnn的转换工具,具体路径在编译完的ncnn工程目录下的installin下,其实可以单独吧这个文件夹下的exe都复制到另外一个文件夹,制作成ncnn转换工具。将onnx文件复制到该文件夹下,运行

./onnx2ncnn resnet18_imagenet_sim.onnx resnet18_imagenet_sim.param resnet18_imagenet_sim.bin

运行之后文件夹下会多出resnet18_imagenet_sim.param和resnet18_imagenet_sim.bin文件,之后将这两个文件放到ncnn工程下的ncnn/examples文件夹下,并且新建一个resnet18_imagenet_sim.cpp,输入以下的代码:

#include "net.h"
#include "benchmark.h"

#include <algorithm>
#if defined(USE_NCNN_SIMPLEOCV)
#include "simpleocv.h"
#else
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#endif
#include <stdio.h>
#include <vector>

static int detect_resnet18(const cv::Mat& bgr, std::vector<float>& cls_scores)
{
    ncnn::Net resnet18;
    resnet18.opt.use_vulkan_compute = true;
    // the ncnn model https://github.com/nihui/ncnn-assets/tree/master/models
    if (resnet18.load_param("resnet18_imagenet_sim.param"))
        exit(-1);
    if (resnet18.load_model("resnet18_imagenet_sim.bin"))
        exit(-1);
    ncnn::Mat in = ncnn::Mat::from_pixels_resize(bgr.data, ncnn::Mat::PIXEL_BGR, bgr.cols, bgr.rows, 256, 256);
    double dStart = ncnn::get_current_time();
    // const float mean_vals[3] = {104.f, 117.f, 123.f};
    // in.substract_mean_normalize(mean_vals, 0);
    const float mean_vals[3] = { 0.485f * 255.f, 0.456f * 255.f, 0.406f * 255.f };
	const float norm_vals[3] = { 1 / 0.229f / 255.f, 1 / 0.224f / 255.f, 1 / 0.225f / 255.f };
	in.substract_mean_normalize(mean_vals, norm_vals);
    ncnn::Extractor ex = resnet18.create_extractor();
    ex.set_light_mode(true);
    // ex.input("data", in);
    ex.input("input", in);
    ncnn::Mat out;
    // ex.extract("prob", out);
    ex.extract("output", out);
    printf("output_size: %d, %d, %d 
", out.w, out.h, out.c);
    out = out.reshape(out.w * out.h * out.c);
    cls_scores.resize(out.w);
    for (int j = 0; j < out.w; j++)
    {
        cls_scores[j] = out[j];
    }
    int top_class = 0;
	float max_score = 0.f;
	for (size_t i = 0; i < cls_scores.size(); i++)
	{
		float s = cls_scores[i];
		if (s > max_score)
		{
			top_class = i;
			max_score = s;
		}
	}
	double dEnd = ncnn::get_current_time();
	printf("%d  score: %f   spend time: %.2f ms
", top_class, max_score, (dEnd - dStart));
    return 0;
}

static int print_topk(const std::vector<float>& cls_scores, int topk)
{
    // 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;
        fprintf(stderr, "%d = %f
", index, score);
    }
    return 0;
}

int main(int argc, char** argv)
{
    if (argc != 2)
    {
        fprintf(stderr, "Usage: %s [imagepath]
", argv[0]);
        return -1;
    }
    const char* imagepath = argv[1];
    cv::Mat m = cv::imread(imagepath, 1);
    if (m.empty())
    {
        fprintf(stderr, "cv::imread %s failed
", imagepath);
        return -1;
    }
    std::vector<float> cls_scores;
    detect_resnet18(m, cls_scores);
    print_topk(cls_scores, 5);

    return 0;
}

这个cpp是模仿ncnn给的示例写的,所以在example文件夹下的CMakeLists.txt还需要将这个文件链接到cmake中,添加这一行就行

在这里插入图片描述

进入到ncnn下的build文件夹,在终端输入

 cmake -DCMAKE_BUILD_TYPE=Release -DNCNN_VULKAN=OFF -DNCNN_BUILD_EXAMPLES=ON ..
 make -j4

这里的DNCNN_VULKAN是关闭vulkan,因为树莓派的vulkan驱动不稳定,不一定的用上加速,DNCNN_BUILD_EXAMPLES是对例子进行编译,默认是OFF,make -j4是编译的进程,可以按照自己的树莓派配置来修改大小

编译后会在ncnn/build_example/examples下生成resnet18_imagenet_sim可执行文件,

在这里插入图片描述

将这个可执行文件连同上面的resnet18_imagenet_sim.param和resnet18_imagenet_sim.bin文件和待测试的图片,复制到同一个文件夹,

在这里插入图片描述

终端出现

在这里插入图片描述

就是成功了。

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。