Go to file
xunyingya 34a27ab77f 更新readme,更加pnna_driver函数重新介绍推理流程 2025-07-31 11:40:39 +08:00
resnet18 调整目录结构,改为一个模型一个文件夹,Makefile文件增加log日志打印等级 2025-07-28 09:02:23 +08:00
yolov4_tiny 调整目录结构,改为一个模型一个文件夹,Makefile文件增加log日志打印等级 2025-07-28 09:02:23 +08:00
yolov5s 调整目录结构,改为一个模型一个文件夹,Makefile文件增加log日志打印等级 2025-07-28 09:02:23 +08:00
yolov5s_relu 调整目录结构,改为一个模型一个文件夹,Makefile文件增加log日志打印等级 2025-07-28 09:02:23 +08:00
yolov8s 调整目录结构,改为一个模型一个文件夹,Makefile文件增加log日志打印等级 2025-07-28 09:02:23 +08:00
.gitignore 调整目录结构,改为一个模型一个文件夹,Makefile文件增加log日志打印等级 2025-07-28 09:02:23 +08:00
Makefile Restore Makefile 2025-07-03 09:27:10 +08:00
README.md 更新readme,更加pnna_driver函数重新介绍推理流程 2025-07-31 11:40:39 +08:00

README.md

示例程序使用说明

概述

本项目提供了一个通用的模型部署框架,支持多种模型(例如 YOLO 系列yolov4_tiny、yolov5s、yolov8s 等)。 通过本示例,用户可以了解如何根据所选模型部署相应的推理代码,只需修改前后处理函数,其他部分的代码和函数接口保持一致。


文件简介

example 目录结构及其主要功能如下所示:

examples
├── yolov5s
│   ├── postprocess         # yolov5s 后处理相关函数接口
│   ├── resource            # 相关模型、图片等资源
│   └── yolov5s_demo.c      # yolov5s 推理流程示例代码
├── resnet18
│   ├── postprocess         # resnet18 后处理相关函数接口
│   ├── resource            # 相关模型、图片等资源
│   └── resnet18_demo.c     # resnet18 推理流程示例代码
...
└── README.md               # 示例说明文档
  • yolov5s_demo.c 使用 V2.1 接口,推荐使用;
  • yolov4_tiny_demo.cyolov8s_demo.c 使用 V1.0 接口(已废弃),保留做兼容性参考。

接口说明

打开与关闭设备

int pnna_open();     // 初始化 Pnna 硬件和驱动资源
int pnna_close();    // 释放硬件资源,关闭驱动

创建模型上下文

app_ctx_t *create_app_ctx(buffer *nbg_buffer,
                        void *norm_param,
                        preprocess_cb preprocess,
                        postprocess_cb postprocess);
  • 加载模型并创建推理上下文;
  • 可指定预处理与后处理函数;
  • 支持从内存读取 NBG 模型数据。

执行推理

int app(app_ctx_t *model, void **output, nn_tensor *input);
  • 输入 tensor 将通过预处理函数处理后送入网络;
  • 输出结果将调用用户提供的后处理函数;
  • 若未设置处理函数,将直接使用原始数据。

销毁模型上下文

void destroy_app_ctx(app_ctx_t *model);
  • 自动释放上下文中由分配的所有资源模型、buffer、quant 参数等)。

示例流程

以 yolov5s 为例

推理主流程

yolov5s_demo.c 中所示:

// 1. 打开设备
pnna_open();

// 2. 加载模型
buffer_t *nbg_buffer = read_nbg("yolov5s.nb");

// 3. 创建模型上下文
app_ctx_t *model = create_app_ctx(&nbg_buffer,
                                 &norm_params,
                                 preprocess_normalize_quantize, // 前处理
                                 yolov5s_postprocess_dq);       // 后处理

// 如果不需要前后处理
// app_ctx_t *model = create_app_ctx(&nbg_buffer, NULL, NULL, NULL);

// 4. 读取输入数据
nn_tensor input_data = load_image("car.jpg");

// 5. 推理
app(model, output, &input_data);

// 6. 清理资源
destroy_tensor(input_data);
free_nbg_buffer(nbg_buffer);
destroy_app_ctx(model);

// 7. 关闭设备
pnna_close();

多输入模型参数说明

如果模型有多个输入,则需要多次获取输入数据,输入的个数在函数 create_app_ctx() 完成后可获取

int input_count = yolov5s_model->ctx->input_count;
nn_tensor *input = (nn_tensor *)malloc(input_count * sizeof(nn_tensor));

for (int i = 0; i < input_count; ++i) {
    input[i] = load_image(image_path);
}

app(model, output, input);

推理结果说明

带后处理

输出结果为最终结果,如 yolov5s_demo.c 中所示,最终结果类型为

detection *output = (detection *)malloc(10 * sizeof(detection));
app(model, (void **)output, input);

请勿使用 detection output[10]; ,这种类型在传入 app() 函数时会有类型不匹配的问题

不带后处理

输出结果为 nn_tensor * 类型,使用方法如下:

create_app_ctx(); // 需要先初始化网络后,才能获取网络中的参数
int output_count = yolov5s_model->ctx->output_count;
nn_tensor *output = (nn_tensor *)malloc(output_count * sizeof(nn_tensor));

app(model, (void **)output, input);

请勿使用 nn_tensor output[10]; ,这种类型在传入 app() 函数时会有类型不匹配的问题

前后处理说明

  • 前处理:由 preprocess_cb 指针注入(如 preprocess_normalize_quantize),实现归一化、量化、图像通道排列等;
  • 后处理:如 yolov5s_postprocess_dq负责输出结果解析如目标框解码、阈值过滤、NMS等
  • 可自由替换以适配不同模型结构。
  • 如果不需要前处理create_app_ctx() 函数中,归一化参数和前处理回调函数均填 NULL
  • 如果不需要后处理create_app_ctx() 函数中,后处理回调函数填 NULL

详细介绍如 nn_api.h 中的函数说明所示。

编译与部署说明

ARM 平台部署

  • 使用交叉编译工具链(如 arm-linux-gnueabihf-gcc)编译示例;
  • 将可执行文件、模型 .nb 文件、输入图片传至开发板;
  • 执行部署程序:
./yolov5s_demo

DSP / RT-Thread 平台部署

  • 在裸机或 RTOS 下,链接 rtt_dsp/ 提供的库文件;
  • 使用 yolov5s_demo.c 中的 #ifdef _TMS320C6X 代码块;
  • 模型和输入数据地址需事先固定于内存中。

V1.0 接口(不推荐使用,仅保留说明)

以下函数为历史接口,已被 V2.1 封装取代。建议新项目统一使用 V2.1 接口。

int nn_init(nn_context **context, const char *nbg_name, unsigned int timeout);       // 初始化模型 @deprecated
int nn_infer(nn_context *context, void **input_buffer, void **output_buffer);        // 推理入口 @deprecated
int nn_destroy(nn_context *context);                                                 // 释放资源 @deprecated

作者 {{xunyingya}}