rknn_outputs_get
是 RKNN-Toolkit2 中用于 获取模型推理结果 的核心接口,支持多输出模型的解析与后处理。以下是其功能、参数、使用场景及注意事项的完整说明:
一、功能与作用
-
核心功能
- 从 NPU 推理后的内存中提取输出数据,支持 多输出模型(如目标检测模型的分类、框坐标、置信度分支)。
- 输出数据格式可通过
rknn_output
结构体灵活配置,支持 浮点型(FLOAT32
)或 量化型(如UINT8
)数据 。
-
适用场景
- 图像分类、目标检测等任务的结果解析。
- 实时视频流中逐帧获取推理结果。
- 多模型串联推理时的中间结果传递。
二、参数与返回值
1. 参数说明
参数名 | 类型 | 说明 |
---|---|---|
ctx | rknn_context | RKNN 上下文句柄,需通过 rknn_init 初始化。 |
n_outputs | uint32_t | 输出张量数量,需与模型定义的输出数量一致(可通过 rknn_query 查询)。 |
outputs | rknn_output* | 输出数据数组,每个元素描述一个输出张量的属性与数据指针。 |
params | void* | 扩展参数,通常设为 NULL 。 |
2. 返回值
- 成功:返回
RKNN_SUCC
(状态码 0)。 - 失败:返回错误码(如
RKNN_ERR_FAIL
),常见原因包括内存不足或上下文未初始化 。
三、数据结构与使用流程
1. rknn_output
结构体
typedef struct {
uint32_t index; // 输出索引(从0开始)
void* buf; // 数据指针(由 SDK 自动分配内存)
uint32_t size; // 数据总字节数
bool want_float; // 是否返回浮点型数据(1: float,0: 量化数据)
} rknn_output;
2. 使用流程
// 初始化输出结构体数组
rknn_output outputs[2]; // 假设模型有2个输出
memset(outputs, 0, sizeof(outputs));
// 配置输出参数(例如分类任务)
for (int i = 0; i < 2; i++) {
outputs[i].want_float = 1; // 返回浮点型数据
}
// 获取输出数据
int ret = rknn_outputs_get(ctx, 2, outputs, NULL);
if (ret != RKNN_SUCC) {
printf("获取输出失败!错误码:%d\n", ret);
exit(-1);
}
// 解析输出(示例:分类结果)
float* class_scores = (float*)outputs[0].buf;
float* bbox_coords = (float*)outputs[1].buf;
四、示例与最佳实践
1. 图像分类结果解析
rknn_output outputs[1];
outputs[0].want_float = 1; // 强制转换为 float 类型
ret = rknn_outputs_get(ctx, 1, outputs, NULL);
// 获取概率最大值
float* prob = (float*)outputs[0].buf;
int max_idx = 0;
float max_val = prob[0];
for (int i = 1; i < 1000; i++) { // 假设输出为 1000 类
if (prob[i] > max_val) {
max_val = prob[i];
max_idx = i;
}
}
printf("预测类别:%d,置信度:%.2f\n", max_idx, max_val);
2. 目标检测结果处理
// 获取多个输出(例如 YOLOv5 的 3 个检测头)
rknn_output outputs[3];
memset(outputs, 0, sizeof(outputs));
for (int i = 0; i < 3; i++) {
outputs[i].want_float = 1;
}
rknn_outputs_get(ctx, 3, outputs, NULL);
// 后处理(非极大值抑制等)
post_process((float*)outputs[0].buf, (float*)outputs[1].buf, (float*)outputs[2].buf);
五、注意事项
-
内存管理
- 输出数据的内存由 SDK 自动分配,需调用
rknn_outputs_release
释放资源 。 - 若未释放输出缓存,可能导致内存泄漏(尤其在高频推理场景中)。
- 输出数据的内存由 SDK 自动分配,需调用
-
数据类型匹配
- 对于量化模型(如
UINT8
输入),需根据want_float
标志决定是否反量化。例如:outputs[i].want_float = 0; // 直接获取量化后的 uint8 数据
- 对于量化模型(如
-
零拷贝优化
- 若启用零拷贝接口(如
pass_through=1
),需确保输出通道数对齐(如 RK3588 需 16 像素对齐)。
- 若启用零拷贝接口(如
-
错误处理
- 检查返回值是否为
RKNN_SUCC
,避免因未初始化或参数错误导致程序崩溃 。
- 检查返回值是否为
总结
- 核心价值:
rknn_outputs_get
是模型部署流程中 结果解析的关键环节,直接影响后处理效率和精度。 - 最佳实践:
- 通过
rknn_query
查询输出属性,确保n_outputs
与模型一致 。 - 优先使用浮点型数据简化后处理(非量化场景)。
- 多线程场景中,为每个线程分配独立的输出缓存以避免竞争 。
- 通过
- 扩展阅读: