Skip to main content
Version: 1.0.0

三、核心神经网络推理引擎(taRuntime)

3.1 taRuntime 概述

关于网络模型的工作大致可以分为模型导入阶段和运行时(Runtime)阶段,本文档主要讨论运行时阶段,也就是与在板端执行推理有关的问题。

taRuntime 是 EA65xx 芯片 SDK 的一个重要组成模块,它在板端提供了一组 C 语言编程接口(API),用于支持板端应用程序基于 EA65xx NPU 硬件完成网络模型推理任务。

为了帮助您理解和使用 taRuntime 模块的接口,本章就一些重要概念和工作原理进行说明。由于篇幅限制,本章只重点讲解与接口设计和使用相关的内容,对于通识性的概念将不做展开说明。

taRuntime 提供的接口功能覆盖:

  • 网络模型加载
  • 模型信息提取
  • 输入输出配置
  • 执行模型推理

3.2 关于 Buffer Pool

如前所述,对于 NPU 推理而言,不论输入图像是 CPU 虚拟地址还是物理地址都需要映射成 NPU 虚拟地址才能被 NPU 使用,而映射过程总是要有一定开销的。

Pool/VB 机制

SDK 的媒体驱动(tasys)提供了一套 Pool/VB 机制(Video Buffer Pool),通过循环复用 Pool 中提供的 VB(Video Frame Buffer)可以减少内存分配和地址映射的次数,从而降低软件延迟。

工作原理

  • taRuntime 接口内部维护了一个查找表
  • 当外部提供图像的方式为物理地址时,接口内部首先试图从查找表获取对应的 NPU 虚拟地址
  • 只有查表失败时才会发起地址映射操作
  • 当外部提供的物理地址源于 Pool/VB 机制时,查表成功的概率极大,可以显著压缩地址管理开销

3.3 关于前处理

前处理定义

前处理(Pre-processing)指的是在执行模型推理之前,对输入数据(图像)进行以下操作,使其符合网络模型第一层对数据格式的要求:

  • 缩放(Resize)
  • 裁切(Crop)
  • 颜色空间变换(Color Space Conversion)
  • 存储格式和精度格式变换

前处理方案

硬件加速方案

  • SDK 提供的 taCV 和 taOpenCV 模块提供了丰富的接口,支持大多数常见的前处理需求
  • 比如,taCV 模块提供基于芯片硬件单元完成的缩放、裁切、颜色空间变换等操作

软件处理方案

  • 对于某些芯片硬件单元不支持的操作,其算子是基于 CPU 算力实现
  • 以 RGB24 图像转 INT8 张量格式为例,涉及像素位置重排和减 offset 操作,在 taOpenCV 中这类算子基于 CPU 算力实现,耗时较长

优化建议

模型移植优化

建议在模型移植阶段就把这类算子合并到网络模型中,推理时利用 NPU 算力完成处理。

PPU 单元利用

  • EA65xx 芯片的 NPU 配属了 PPU(Pre-processing Unit)单元
  • PPU 提供了一定的算子可编程能力
  • 原厂可以基于 PPU 硬件开发新的算子并通过 taCV 模块暴露给用户使用

⚠️ 注意:

  • NPU 单元与 PPU 单元只能分时工作,使用 PPU 算子会占用 NPU 算力。

3.4 关于后处理

后处理定义

后处理(Post-processing)一般是指对 NPU 输出的推理结果进行过滤从而获得最终结果。

典型后处理任务

以 YOLO 系列模型为例,典型的后处理任务包括:

  1. 从上万个待处理结果中去除冗余的检测框
  2. 删除置信度过低的检测框
  3. 对幸存结果进行排序获得 top-k 个候选框
  4. 根据预设的阈值筛选出最终的检测框
  5. 将类别索引 ID 映射回人类可理解的类别标签

后处理实现方式

CPU 处理原因

  • 涉及大量的复杂逻辑处理,运算性质不利于硬件实现
  • 算法更新迭代速度快,后处理需求经常变化

推荐方案

  • 后处理步骤主要借助 CPU 算力完成
  • taOpenCV 提供了丰富的专用算子
  • 用户可以利用 taOpenCV 接口实现大部分后处理操作

3.5 关于多进程多线程

本模块的接口支持在多个进程、多个线程中调用,具体工作逻辑如下:

进程工作流程

对于一个进程来说,其工作流程可以分成三个阶段:

  1. 初始化阶段
  2. 推理阶段
  3. 反初始化阶段

一般做法是在推理阶段创建多个工作线程,每个线程负责一路视频流的推理。

多进程支持

当存在多个进程时:

  • 为了避免在进程间协调接口调用时序,SDK 允许每个进程都独立地调用初始化和反初始化接口
  • 实际上只有一次调用会实际生效(触发硬件初始化/反初始化流程)
  • 其它无效的调用会被忽略,但不返回错误

多线程任务管理

在一个进程内部:

  • 用户调用接口时需要提供一个 context 结构体
  • context 的作用是帮助接口识别任务来源
  • 来自多个线程的任务最终会被推送到由内核驱动维护的任务队列
  • 硬件按照先到先服务的原则依次处理队列中的任务

3.6 taRuntime 模块开发

NN 推理概念

NN 推理(Neural Network Inference)指的是在开发板上运行一个 AI 推理程序,核心流程包括:

  1. 从 Linux 文件系统加载网络模型到内存中
  2. 提取推理指令流和权重参数
  3. 分配内存和计算资源
  4. 提交推理任务到 taRuntime
  5. 触发 EA65xx 芯片的 NPU 运行模型
  6. CPU 对 NPU 推理结果进行后处理
  7. 输出检测/识别结果

开发流程

  1. 模型准备:请算法工程师提供能在 EA65xx 板端运行的模型文件
  2. 程序开发:应用开发工程师参考 sample 编写程序
  3. 接口调用:调用 taRuntime 库的 API 接口加载和运行模型文件
  4. 前后处理:调用其它 SDK 模块提供的 API 接口获取图像及进行前后处理
  5. 部署调试:将编译好的程序拷贝到板端调试运行

示例代码

// taRuntime API 基本使用流程

// 初始化
ta_runtime_init();

// 创建上下文
ta_runtime_context context;

// 加载模型:从文件系统加载到系统内存,再读入 NN 域
ta_runtime_load_model_from_file(&context, file_path, 0);

// 设置模型输入
taconn_input_t input;
ta_runtime_set_input_cva(&context, input_count, input);

// 设置模型推理的输出 buffer
taconn_buffer_t *output;
ta_runtime_create_buffer(&context, output_size, output);
ta_runtime_set_output(&context, output_count, output);

// 运行网络
ta_runtime_run_network(&context);

// 确保 CPU 读到最新数据
ta_runtime_invalidate_buffer(&context, output);

// 读取 buffer 数据后,释放内存
ta_runtime_destroy_buffer(&context, output);