ncnn学习笔记(一)——配置ncnn

由于本人使用的系统是win10,所以记录也是在win10下使用ncnn。

前期准备

网上很多介绍ncnn的配置教程都是从头开始构建编译,其实官方已经编译好一些版本的ncnn,直接下载就行了,没有必要从头开始编译。
官方github: https://github.com/Tencent/ncnn

从官方仓库的页面,点击releases
在这里插入图片描述
我用的是vs2019,shared是动态链接版本,我下的就是shared版本
在这里插入图片描述
解压后随便存放在哪个盘都行,然后记得在环境变量的path把bin路径添加进去,像我就放在D盘下,并且由于我opencv版本的关系,我用的是x64,所以我添加的路径就为:D:\C++_lib\ncnn-20210720-windows-vs2019-shared\x64\bin

pytorch转onnx

官方教程中是使用caffe作为例子,但是我没有使用过caffe,所以我用的是pytorch模型转onnx的方式来验证ncnn是否能正常工作。
还有关于pytorch转onnx,这个我就不多说了,很复杂,坑巨多,自求多福,如果在pytorch里面直接定义了很多骚操作,那么多半转onnx要凉,唯一的办法就是绕开某些操作。这个话题不是本篇重点,跳过。说一点就是:输入和输出一定要命名啊:几个输出就命名几个,这样在用ncnn的load的时候才能直接提取出来。一般导出onnx的代码举例如下:

import torch
import torchvision.models as models
model = models.resnet50()
model.fc = torch.nn.Linear(2048, 2)

batch_size = 1  # 批处理大小
input_shape = (3, 244, 224)     # 输入数据,改成自己的输入shape

# #set the model to inference mode
model.eval()

x = torch.randn(batch_size, *input_shape)   # 生成张量
export_onnx_file = "test.onnx"			# 目的ONNX文件名
torch.onnx.export(model,
                  x,
                  export_onnx_file,
                  verbose=True,
                  opset_version=10,
                  do_constant_folding=True, # 是否执行常量折叠优化
                  input_names=["input"],    # 输入名
                  output_names=["output"],  # 输出名
                  dynamic_axes={
    
    "input": {
    
    0: "batch_size"},  # 批处理变量
                                "output": {
    
    0: "batch_size"}})

我使用了pytorch官方自带的resnet50,并将输出修改为两分类。(没有加载预训练权重,主要是懒。。。。)
运行之后,我们就可以得到onnx模型了,之后的操作也就告别了pytorch框架了,可以随心所欲了,现在需要将onnx格式的模型转成ncnn能够加载的.bin和.param。
在onnx模型所在的目录下,使用命令:

onnx2ncnn test.onnx model.param model.bin

如果什么都没输出,那恭喜成功了!

配置ncnn

由于利用opencv来读取图片,然后再利用ncnn的from_pixels_resize函数将opencv格式的图片转为ncnn格式的图片。所以会需要用到opencv,至于怎么下载opencv,网上一搜都有,就不说了。
还有ncnn内部用到了vulkan,所以在包含目录也要添加vulkande的include目录,下载链接:https://vulkan.lunarg.com/sdk/home#windows
在这里插入图片描述
下载后点击安装,过程很简单。

将onnx转成ncnn能使用的格式后,接下来就是在vs2019配置ncnn了。
在包含目录添加(根据自己实际安装目录)
D:\C++_lib\opencv\build\include
D:\C++_lib\ncnn-20210720-windows-vs2019-shared\x64\include\ncnn
D:\C++_lib\VulkanSDK\1.2.189.2\Include
在这里插入图片描述

在库目录添加(根据自己实际安装目录)
D:\C++_lib\opencv\build\x64\vc15\lib
D:\C++_lib\ncnn-20210720-windows-vs2019-shared\x64\lib
在这里插入图片描述

点击连接器-输入-附加依赖项,添加
opencv_world450.lib
opencv_world450d.lib
ncnn.lib
在这里插入图片描述
测试代码:

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include "net.h"


//这个函数是官方提供的用于打印输出的tensor
void pretty_print(const ncnn::Mat& m)
{
    
    
    for (int q = 0; q < m.c; q++)
    {
    
    
        const float* ptr = m.channel(q);
        for (int y = 0; y < m.h; y++)
        {
    
    
            for (int x = 0; x < m.w; x++)
            {
    
    
                printf("%f ", ptr[x]);
            }
            ptr += m.w;
            printf("\n");
        }
        printf("------------------------\n");
    }
}

int main()
{
    
    
    //使用opencv以灰度图读取图片
    cv::Mat img = cv::imread("E://code//test//image.jpg");
    //获取图片的宽
    int w = img.cols;
    //获取图片的高
    int h = img.rows;

    //cv::imshow("aa", img);
    //cv::waitKey();

    //将OpenCV的图片转为ncnn格式的图片,并且将图片缩放到224×224之间
    ncnn::Mat in = ncnn::Mat::from_pixels_resize(img.data, ncnn::Mat::PIXEL_GRAY, w, h, 224, 224);
    float mean[1] = {
    
     128.f };
    float norm[1] = {
    
     1 / 128.f };
    //对图片进行归一化,将像素归一化到-1~1之间
    in.substract_mean_normalize(mean, norm);

    //定义模型的网络
    ncnn::Net net;
    //加载模型
    net.load_param("E://code//test//model.param");
    net.load_model("E://code//test//model.bin");


    ncnn::Extractor ex = net.create_extractor();
    ex.set_light_mode(true);
    //设置线程个数
    ex.set_num_threads(4);

    //将图片放入到网络中,进行前向推理
    ex.input("input", in);

    ncnn::Mat feat;
    //获取网络的输出结果
    ex.extract("output", feat);

    pretty_print(feat);

    return 0;
}

上面只是一段测试代码,也不用纠结为什么放缩到-1到1之间,你喜欢也可以放缩到0到1之间。
需要注意的是,我是x64模式下导入头文件的,所以最好在vs里面也设为x64模式,不然会出现冲突。
在这里插入图片描述
如果正常输出一个二分类结果,那就没有什么问题了,可以接下来愉快的学习ncnn了。

おすすめ

転載: blog.csdn.net/weixin_41693877/article/details/120720939