PNNA 推理 API 用户手册
PNNA 是一套基于 C 语言的神经网络推理接口,用于在 ARM 或 DSP 平台上部署和运行深度学习模型。接口对模型加载、硬件绑定、内存管理及推理流程进行了统一抽象,可运行于 Linux、RT-Thread 及裸机环境。
PNNA 适用于图像分类、目标检测等常见视觉任务。用户可通过注册预处理与后处理回调函数,快速构建完整的 “输入处理 → 模型推理 → 结果解析” 应用链路;同时也保留了更底层的模型接口,便于在性能优化或资源复用场景下进行深度定制。
本文档面向基于 PNNA API 进行模型部署与应用开发的工程人员,系统说明接口职责、资源生命周期及推荐使用方式。
示例工程结构
examples 目录包含多平台、多模型的完整部署示例:
1examples
2├── yolov5s # ARM Linux 平台部署示例
3│ ├── postprocess # yolov5s 后处理实现
4│ ├── resource # 模型与测试资源
5│ └── yolov5s_demo.c # 完整推理流程示例
6├── resnet18 # ARM Linux 平台部署示例
7│ ├── postprocess
8│ ├── resource
9│ └── resnet18_demo.c
10├── yolov5s_metal_c6x # DSP 裸机(Metal)平台示例
11│ ├── postprocess
12│ ├── resource
13│ └── yolov5s_demo.c
14└── README.md # 示例说明文档
快速开始
环境要求
操作系统:Linux / RT-Thread / 裸机
目标硬件:ARM Cortex-A / Cortex-M / DSP C6x
编译工具:对应平台的交叉编译工具链
PNNA 提供两套推理调用方式,分别面向应用集成与高级定制场景。
方式一:应用层接口(推荐)
应用层接口对模型生命周期和推理流程进行了完整封装,适合绝大多数应用场景。
pnna_open();
app_ctx_t *model = create_app_ctx(nbg_buffer, preprocess, postprocess);
buffer_t input = load_image(image_filename);
app(model, (void **)&output, &input);
free_image_buffer(&input);
destroy_app_ctx(model);
pnna_close();
应用层接口流程图
方式二:模型接口
底层接口仅提供模型加载与推理能力,不参与任何输入输出处理,适用于对性能和资源控制要求较高的场景。
pnna_open();
nn_ctx_t *ctx = create_model(nbg_buffer);
buffer_t input = load_image("test.jpg");
buffer_t quant_input = custom_quantize(input, ctx->input_quant);
infer(ctx, &output, &quant_input);
custom_postprocess(&output);
destroy_model(ctx);
pnna_close();
底层接口流程图
接口层次说明
PNNA 采用分层设计:
应用层接口
管理模型生命周期
自动分配输入/输出缓存
统一预处理、推理、后处理流程
底层模型接口
仅负责模型加载与推理执行
不参与数据处理与内存管理
核心 API 说明
设备管理接口
int pnna_open();
int pnna_close();
全局接口,通常在进程生命周期内各调用一次
不支持多次重复初始化或跨模块反复调用
应用层接口
create_app_ctx()
app_ctx_t *create_app_ctx(buffer_t *nbg_buffer,
preprocess_cb model_preprocess,
postprocess_cb model_postprocess);
功能说明:
内部调用
create_model()加载模型并绑定硬件根据模型输入量化信息创建预处理缓存
根据输出张量数量分配输出缓存
将预处理 / 后处理回调绑定到上下文
destroy_app_ctx()
void destroy_app_ctx(app_ctx_t *model);
释放内容包括:
底层模型资源
输入/输出临时 buffer
应用层上下文自身内存
模型接口
create_model() / destroy_model()
nn_ctx_t *create_model(buffer_t *nbg_buffer, int options);
void destroy_model(nn_ctx_t *ctx);
create_model():解析 NBG 模型并完成硬件绑定,生成nn_ctx_tdestroy_model():仅释放模型及硬件相关资源
底层接口不涉及任何预处理、后处理或 buffer 管理逻辑。
推理接口说明
infer()
int infer(nn_ctx_t *ctx, buffer_t *output, buffer_t *input);
特性:
仅执行模型推理
不检查输入合法性
不做预处理或后处理
输出为原始网络结果
app()
int app(app_ctx_t *model, void **output, buffer_t *input);
app() 封装完整推理链路:
参数检查
可选预处理
调用
infer()执行推理可选后处理
组织并返回结果
app() 输出规则说明
配置后处理函数
output指向用户自定义结构体输出内存由调用者分配
detection *output = malloc(sizeof(detection) * 10);
app(model, (void **)&output, &input);
注意事项:
必须传入
output的地址(void **),而不是直接传结构体数组output参数仅用于返回结果指针,app()不会在内部申请结构化输出内存
错误示例(不推荐):
detection output[10]; // 不推荐
app(model, (void **)output, input);
上述写法会导致指针层级不匹配,可能引发未定义行为。
未配置后处理函数
output类型为buffer_t *输出 buffer 由框架内部管理
buffer_t *output = NULL;
app(model, (void **)&output, &input);
注意事项:
初始将
output置为NULL即可app()内部会将网络输出缓冲区指针赋值给output调用者只负责读取该缓冲区,不负责释放(释放规则以模型生命周期为准)
多输入模型支持
int input_count = model->ctx->input_count;
buffer_t *inputs = malloc(sizeof(buffer_t) * input_count);
for (int i = 0; i < input_count; ++i) {
inputs[i] = load_image(image_paths[i]);
}
app(model, output, inputs);
输入 buffer 生命周期由调用者管理
app()不负责释放输入数据
资源管理对照表
资源 |
创建接口 |
释放接口 |
|---|---|---|
硬件设备 |
pnna_open |
pnna_close |
应用上下文 |
create_app_ctx |
destroy_app_ctx |
底层模型 |
create_model |
destroy_model |
图像数据 |
load_image |
free_image_buffer |
推荐标准流程
pnna_open()create_app_ctx()准备输入数据
app()解析结果
destroy_app_ctx()pnna_close()
作者 @xyy xunyingya@hngwg.com