目录
目录README.md

pnna 神经网络推理框架简介

概述

pnna 目录是 PNNA 推理框架的主体代码目录,提供面向嵌入式平台的神经网络推理能力。该目录包含核心推理接口、跨平台驱动适配、通用工具函数,以及示例程序与测试代码,用于支撑模型在 ARM、DSP 以及 RT-Thread 等环境上的部署和运行。

pnna 的设计目标是将底层硬件驱动、模型管理、数据预处理和推理执行进行分层封装,使上层应用能够以统一接口完成模型推理,而不直接依赖具体硬件实现细节。各功能模块分别放置在独立目录中,详细用法和实现说明由对应目录下的 README 文档进行说明。


目录结构和说明

pnna
├── examples
│   ├── README.md             # 推理示例总体说明
│   └── ...                   # 不同模型和平台的示例工程
├── include
│   ├── nn_api.h              # 应用层推理接口定义
│   ├── nn_utils.h            # 通用工具函数接口
│   ├── pnna_lite.h           # PNNA Lite 核心接口声明
│   ├── pnna_lite_common.h    # 公共类型与宏定义
│   ├── preprocess.h          # 前处理接口声明
│   └── quantize.h            # 量化相关接口声明
├── src
│   ├── driver_metal_c6x      # DSP 裸机环境驱动实现
│   ├── driver_rtt            # RT-Thread 环境驱动实现
│   ├── nn_api.c              # 推理接口实现
│   ├── nn_utils.c            # 工具函数实现
│   ├── preprocess.c          # 前处理流程实现
│   └── quantize.c            # 量化与数据转换实现
├── lib
│   └── *.so                  # Linux 平台下的 PNNA 动态库文件
├── test
│   └── README.md             # 测试程序说明
└── README.md                 # pnna 目录总览说明

目录职责说明

  1. examples examples 目录提供基于 pnna 的完整推理示例工程,覆盖不同模型和运行平台。 示例主要用于展示 pnna 接口的实际使用方式,包括模型加载、输入准备、推理调用和结果处理。 示例的详细流程和注意事项不在本 README 中展开,具体说明请参考 examples/README.md 以及各示例子目录中的文档。

  2. include include 目录包含 pnna 对外暴露的头文件,定义了推理相关的核心数据结构、接口函数以及通用类型。 这些头文件是应用层或示例工程使用 pnna 功能的主要入口,同时也作为 src 目录中实现代码的接口约束。

  3. src src 目录实现 pnna 的核心功能逻辑,包括模型推理流程、前后处理、工具函数以及不同运行环境下的驱动适配。 driver_metal_c6x 和 driver_rtt 子目录分别用于适配 DSP 裸机和 RT-Thread 操作系统,其余源文件实现平台无关的通用推理逻辑。

  4. lib lib 目录用于存放 Linux 平台下的 PNNA 动态库文件(.so)。 在 ARM Linux 环境中,PNNA 驱动的编译与 Linux 内核版本、内核配置和工具链强相关,直接提供源码在多数情况下难以复用。 因此,该目录以预编译库文件的形式提供 PNNA 驱动与底层实现,供应用程序或示例工程在 Linux 平台下直接链接使用。

  5. test test 目录用于存放 PNNA Driver 的测试代码,包含单元测试和集成测试相关内容,用于验证设备管理、buffer 管理、推理流程以及前后处理等功能的正确性。 测试框架、构建方式和运行方法请参考 test/README.md。

使用说明

pnna 目录本身不直接作为独立工程使用,而是作为推理框架库被示例工程或上层应用引用。一般使用流程为:

  1. 在应用或示例工程中包含 pnna/include 中的接口头文件
  2. 根据目标平台选择并编译 pnna/src 中对应的驱动与实现代码
  3. 通过 pnna 提供的接口完成设备初始化、模型创建与推理执行
  4. 参考 examples 和 test 目录中的示例与测试代码进行功能验证

PNNA API 参考手册

本节说明适用于基于 PNNA API 开发的所有推理应用(如 ResNet, YOLOv5, YOLOv8 等)。

设备管理

在进行任何推理任务前,必须先初始化硬件设备;任务结束后需释放资源。

// 初始化 PNNA 硬件及驱动资源
int pnna_open();

// 释放硬件资源并关闭驱动
int pnna_close();

应用上下文 (App Context) 管理

PNNA 提供高层封装的 App Context,自动管理模型加载、内存分配及前后处理回调。

创建上下文

/**
 * @brief 创建应用推理上下文
 * @param nbg_buffer   模型二进制数据缓存
 * @param preprocess   预处理回调函数(可为 NULL)
 * @param postprocess  后处理回调函数(可为 NULL)
 * @return app_ctx_t* 返回应用上下文指针
 */
app_ctx_t *create_app_ctx(buffer_t *nbg_buffer, \
                          preprocess_cb  preprocess, \
                          postprocess_cb postprocess);

销毁上下文

// 自动释放上下文中分配的所有资源(模型句柄、Tensor Buffer等)
void destroy_app_ctx(app_ctx_t *model);

执行推理 (app)

app() 是执行推理的核心入口,封装了“预处理 -> 模型推理 -> 后处理”的完整链路。

int app(app_ctx_t *model, void **output, buffer_t *input);

app() 函数参数传递说明

app() 函数的第二个参数为 void **output,用于返回推理结果指针。 根据是否配置后处理函数,output 的实际指向对象及内存管理方式有所不同。

配置后处理函数的情况

当模型配置了后处理函数时,app() 返回的结果为最终解析后的结构化数据,其具体类型由后处理函数定义,例如目标检测模型中的 detection

这种模式下:

  • 输出数据的内存由调用者负责申请
  • app() 仅负责将结果写入调用者提供的内存

示例如下:

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

注意事项:

  • 必须传入 output 的地址(void **),而不是直接传结构体数组
  • 不要使用如下方式:
detection output[10];   // 不推荐
app(model, (void **)output, input);

上述写法会导致指针层级不匹配,可能引发未定义行为。

未配置后处理函数的情况

当未配置后处理函数时,app() 不对模型输出做解析,而是直接返回网络原始输出缓冲区

这种模式下:

  • 输出类型固定为 buffer_t *
  • 输出缓冲区由 app() / 模型内部管理
  • 调用者不需要也不应主动申请输出内存

示例如下:

buffer_t *output = NULL;
app(model, (void **)&output, &input_data);

注意事项:

  • 初始将 output 置为 NULL 即可
  • app() 内部会将网络输出缓冲区指针赋值给 output
  • 调用者只负责读取该缓冲区,不负责释放(释放规则以模型生命周期为准)

多输入模型支持

对于具有多个输入节点的模型(如某些特定的检测或分割网络),输入数据的构造方式如下:

// 1. 从上下文获取输入节点数量
int input_count = model->ctx->input_count;

// 2. 分配输入 buffer 数组
buffer_t *inputs = (buffer_t *)malloc(input_count * sizeof(buffer_t));

// 3. 填充每个输入节点的数据
for (int i = 0; i < input_count; ++i) {
    inputs[i] = load_image(image_paths[i]); // 示例:加载图像数据
}

// 4. 执行推理
app(model, output, inputs);

资源管理 API 对照表

为了防止内存泄漏,请严格遵循以下的资源创建与销毁配对规则:

资源类型 创建/获取函数 销毁/释放函数
硬件设备 pnna_open() pnna_close()
文件缓冲 load_binary_to_buffer(...) free_buffer(...)
应用上下文 create_app_ctx(...) destroy_app_ctx(...)
图像数据 load_image(...) / load_image_from_memory(...) free_image_buffer(...)
参数缓冲 create_buffer_from_qparams(...) destroy_buffer_array(...)
底层模型 create_model(...) destroy_model(...)

标准调用流程示例

  1. 初始化:调用 pnna_open()
  2. 加载:读取模型文件,调用 create_app_ctx() 注册前后处理回调。
  3. 输入:加载图像并转换为 buffer_t
  4. 推理:申请结果内存(如果需要),调用 app()
  5. 解析:读取 output 数据进行业务处理。
  6. 清理:依次调用 free_image_buffer, free(output), destroy_app_ctx()
  7. 退出:调用 pnna_close()

作者 {{xunyingya}}

关于

pnna驱动和应用层示例程序

154.7 MB
邀请码
    Gitlink(确实开源)
  • 加入我们
  • 官网邮箱:gitlink@ccf.org.cn
  • QQ群
  • QQ群
  • 公众号
  • 公众号

©Copyright 2023 CCF 开源发展委员会
Powered by Trustie& IntelliDE 京ICP备13000930号