AI NPU 模块
支持的芯片:[RTL8735C]
概述
该平台集成了专用神经网络处理单元(Neural Processing Unit,NPU),可将深度神经网络(Deep Neural Network,DNN)计算从主 CPU 卸载出来,以较低功耗实现实时 AI 推理,例如目标检测、人脸检测与人脸识别。
在 600 MHz 工作频率下,NPU 在 INT8 精度下可提供约 1 TOPS 的算力。芯片侧提供 256 KB 片上 SRAM (VIP_SRAM)用于中间张量,并在 DDR 中预留 12 MB 专用区域 用于模型权重与 I/O buffer,详情请参考 NN 内存布局。
关于硬件架构、支持的 layer 类型、量化格式以及软件栈,请参考 NPU 硬件参考。
集成概述
所有 NN 示例都采用类似的集成方式。应用程序打开一路 V5 视频通道作为 RGB(或 NV12)输入源,将帧数据送入 VIPNN 模块进行 NPU 推理,并通过结果回调函数接收结构化的后处理结果。
[Video V5: RGB NN_WIDTH x NN_HEIGHT @ fps] --> SISO --> [VIPNN module]
|
nn_display_cb()
运行 NN 的基本步骤:
预编译模型库
SDK 中提供以下预编译 .nb 模型文件:
component/soc/<soc>/video/nn/app/nn_model/binary/
使用模型前,需要确保对应 .nb 文件在应用运行前已经存在于设备文件系统中。关于如何烧录或复制模型文件,请参考 部署模型到设备。
目标检测
YOLO 系列
YOLO(You Only Look Once)是常用的实时目标检测算法。SDK 提供以下模型:
Model object |
Binary filename |
Input size |
Quantised |
|---|---|---|---|
|
|
416 x 416 |
uint8 |
|
|
576 x 320 |
uint8 |
|
|
640 x 480 |
uint8 |
|
|
416 x 416 |
int16 DFP |
在编译期包含对应头文件,并选择模型对象:
#include "model_yolo.h" // yolov4_tiny, yolov7_tiny
#include "model_yolov9.h" // yolov9_tiny
#define NN_MODEL_OBJ yolov7_tiny
#define NN_MODEL_NAME "vfs:/yolov7_tiny_576x320_asymu8.nb"
#define NN_WIDTH 576
#define NN_HEIGHT 320
每个检测目标的输出保存在 objdetect_res_t 中:
typedef struct objdetect_res_s {
union {
float result[6]; // [class_id, score, top_x, top_y, bot_x, bot_y]
detobj_t res;
};
} objdetect_res_t;
坐标均相对于逻辑检测输入尺寸归一化到 [0.0, 1.0]。通常该尺寸等于网络张量尺寸。如果 .nb 模型内部包含预处理或缩放 layer,应用可在 nn_data_param_t 中提供 model_width / model_height,使 YOLO 后处理按逻辑检测尺寸解码框坐标。YOLO 模型基于 COCO 数据集(80 类)训练。
更多信息: https://github.com/AlexeyAB/darknet
人脸检测
SCRFD
SCRFD(Sample and Computation Redistribution for Face Detection)是一种轻量级、高精度人脸检测模型,可输出人脸框和 5 点人脸关键点。
Model object |
Binary filename |
Input size |
Quantised |
|---|---|---|---|
|
|
576 x 320 |
uint8 |
#include "model_scrfd.h"
#define NN_MODEL_OBJ scrfd
#define NN_MODEL_NAME "vfs:/scrfd_500m_bnkps_shape576x320.nb"
#define NN_WIDTH 576
#define NN_HEIGHT 320
检测结果保存在 facedetect_res_t 中:
typedef struct facedetect_res_s {
union {
float result[6]; // [class_id, score, top_x, top_y, bot_x, bot_y]
detobj_t res;
};
landmark_t landmark; // 5 facial landmark points (x, y) normalised to [0.0, 1.0]
} facedetect_res_t;
更多信息: https://github.com/deepinsight/insightface/tree/master/detection/scrfd
人脸识别
MobileFaceNet
MobileFaceNet 是一个轻量级人脸识别模型,使用 ArcFace(Additive Angular Margin Loss)训练。模型输入为裁剪并对齐后的人脸图像,输出 128 维特征向量,用于身份匹配。
MobileFaceNet 通常与 SCRFD 组合成级联的人脸检测加识别流程:SCRFD 先在完整画面中检测并定位人脸,再由 MobileFaceNet 对每个人脸区域提取 embedding,并与已保存的人脸特征数据库进行比对。VIPNN 的相关配置请参考 级联模式。
Model object |
Binary filename |
Input size |
Quantised |
|---|---|---|---|
|
|
112 x 112 |
int8 sym |
#include "model_mobilefacenet.h"
识别结果保存在 face_feature_res_t 中:
#define MAX_FACE_FEATURE_DIM 128
typedef struct face_feature_res_s {
union {
float result[6];
detobj_t res;
};
float feature[MAX_FACE_FEATURE_DIM]; // 128-dim face embedding
} face_feature_res_t;
更多信息: https://github.com/deepinsight/insightface/tree/master/recognition
模型内存与文件大小参考
下表列出 SDK 中各模型的内存占用。DDR memory usage 表示 NPU runtime 所需内存(模型权重 + I/O tensor buffer)。所有模型均可放入 12 MB NN_DDR 区域。
类别 |
模型文件 |
输入尺寸 |
量化格式 |
DDR 内存占用 |
文件大小 |
|---|---|---|---|---|---|
目标检测 |
|
416 x 416 |
uint8 |
6.51 MB |
3.59 MB |
目标检测 |
|
576 x 320 |
uint8 |
7.25 MB |
3.96 MB |
目标检测 |
|
640 x 480 |
uint8 |
10.13 MB |
3.83 MB |
目标检测 |
|
416 x 416 |
int16 DFP |
10.22 MB |
4.73 MB |
人脸检测 |
|
576 x 320 |
uint8 |
2.28 MB |
0.75 MB |
人脸识别 |
|
112 x 112 |
int8 sym |
2.06 MB |
1.40 MB |
备注
同时运行两个模型时(例如 SCRFD + MobileFaceNet 的检测加识别流程),需要确保合计 DDR 占用不超过 12 MB NN_DDR 预算。SCRFD + MobileFaceNet 组合约占用 4.3 MB。
部署模型到设备
VIPNN 模块在运行时通过路径前缀加载模型文件:
vfs:/- 从内部 LittleFS flash 分区(VFS1)读取sd:/- 从 SD 卡读取
快速验证时,可以将 .nb 文件复制到 SD 卡根目录,并将模型路径设置为 sd:/model.nb,无需额外打包步骤。对于量产或无 SD 卡槽的设备,建议使用下文的 vfs: 路径。
烧录模型到 LittleFS(VFS1)
VFS1 是 flash layout 中定义的 LittleFS flash 分区(component/soc/usrcfg/<soc>/ameba_flashcfg.c)。目前 SDK 会将 Wi-Fi、BT 与 NN 数据放在同一个 LittleFS 区域,因为 runtime 仅支持一个 LittleFS flash region:
{VFS1, 0x088A3000, 0x08EA2FFF} /* VFS region 1: wifi/BT/NN data (6 MB) */
{VFS2, 0xFFFFFFFF, 0xFFFFFFFF}
备注
上述地址范围仅供参考。烧录前请始终检查 component/soc/usrcfg/<soc>/ameba_flashcfg.c 中实际的 VFS1 分区地址和大小,因为 flash layout 可能会随固件配置变化。
步骤 1 - 准备模型目录
在 tools/littlefs/linux 下创建本地目录,并复制 SDK NN video 示例使用的模型文件:
cd tools/littlefs/linux
mkdir -p nn_model
cp ../../../component/soc/<soc>/video/nn/app/nn_model/binary/mobilefacenet_pcqsymi8.nb nn_model/
cp ../../../component/soc/<soc>/video/nn/app/nn_model/binary/scrfd_500m_bnkps_shape576x320.nb nn_model/
cp ../../../component/soc/<soc>/video/nn/app/nn_model/binary/yolov4_tiny_asymu8.nb nn_model/
以上命令会把三个常用示例模型打包到同一个 LittleFS 映像中:
mobilefacenet_pcqsymi8.nb:MobileFaceNet 人脸 embedding 模型scrfd_500m_bnkps_shape576x320.nb:SCRFD 人脸检测模型yolov4_tiny_asymu8.nb:YOLO 目标检测模型
步骤 2 - 生成 LittleFS 映像
在 tools/littlefs/linux 目录下执行:
./mklittlefs -b 4096 -p 4096 -s 0x600000 -c nn_model/ nn_model_lfs.bin
映像生成后,可列出 LittleFS 映像中的文件,确认模型文件已被正确打包:
./mklittlefs -b 4096 -p 4096 -s 0x600000 -l nn_model_lfs.bin
示例输出:
1466168 /mobilefacenet_pcqsymi8.nb Mon Nov 17 08:57:48 2025
787568 /scrfd_500m_bnkps_shape576x320.nb Mon Nov 17 08:57:48 2025
3763536 /yolov4_tiny_asymu8.nb Mon Nov 17 08:57:48 2025
参数 |
说明 |
|---|---|
|
block 大小,单位为 byte,需匹配 flash erase block size |
|
page 大小,单位为 byte |
|
映像大小,需与 VFS1 分区大小一致(6 MB) |
|
要打包的输入目录 |
|
输出的 LittleFS 映像文件 |
步骤 3 - 烧录映像
使用 image download tool 将 nn_model_lfs.bin 烧录到 VFS1 起始地址(0x088A3000)。烧录成功后,应用即可通过 vfs: 前缀访问模型文件:
#define FACEDET_MODEL_NAME "vfs:/scrfd_500m_bnkps_shape576x320.nb"
#define FACENET_MODEL_NAME "vfs:/mobilefacenet_pcqsymi8.nb"
#define OBJDET_MODEL_NAME "vfs:/yolov4_tiny_asymu8.nb"
备注
打包后的所有文件总大小不能超过 VFS1 分区大小(6 MB)。上述三个模型约 5.74 MB,可放入默认 6 MB VFS1 映像。各预编译模型文件大小请参考 模型内存与文件大小参考。
VIPNN 模块
NN MMF 模块 vipnn 可接收视频管线中的 RGB 或 NV12 帧,在 NPU 上执行推理,并通过回调函数将结构化的后处理结果传给应用。
每个模型对象(nnmodel_t)中已经绑定对应的预处理与后处理逻辑。因此添加新模型时,通常只需要提供新的 model object,VIPNN 模块本身无需修改。
VIPNN 模块上下文
VIPNN 模块内部上下文如下:
typedef struct vipnn_ctx_s {
void *parent;
vip_network network; // NPU network handle
vip_buffer_create_params_t vip_param_in[MAX_IO_NUM];
vip_buffer_create_params_t vip_param_out[MAX_IO_NUM];
vip_buffer input_buffers[MAX_IO_NUM];
vip_buffer output_buffers[MAX_IO_NUM];
vipnn_params_t params; // module parameters
vipnn_status_t status;
char network_name[64];
int input_count;
int output_count;
vipnn_preproc_t pre_process; // custom pre-process hook
vipnn_postproc_t post_process; // custom post-process hook
disp_postprcess_t disp_postproc; // result display callback
vipnn_cascaded_mode_t cas_mode;
bool module_out_en;
vipnn_measure_t measure; // inference FPS measurement
} vipnn_ctx_t;
模块参数
vipnn_params_t 结构体保存模块运行时参数:
typedef struct vipnn_param_s {
char model_file[64]; // model file path on file system (e.g. "vfs:/model.nb")
uint8_t *model_mem; // pointer to model in memory (alternative to file path)
uint32_t model_size; // model size in bytes (when using model_mem)
int fps; // target inference FPS (0 = unlimited)
int out_res_size; // sizeof one result structure
int out_res_max_cnt; // maximum number of results per frame
int save_out_tensor; // set to 1 to dump raw output tensors for offline debugging
nn_data_param_t *in_param; // input image parameters
nnmodel_t *model; // pointer to the model object
} vipnn_params_t;
nn_data_param_t 中的图像参数用于描述 VIPNN 消费的视频帧:
typedef struct nn_data_param_s {
union {
struct {
int width, height;
int model_width, model_height; // optional logical detector size
landmarki_t landmark;
} img;
/* audio fields omitted */
};
uint32_t codec_type;
void *priv;
int size_in_byte;
} nn_data_param_t;
备注
将 save_out_tensor 设置为 1 后,模块会将 NPU 原始输出 tensor dump 到文件中,便于在 PC 上开发或验证自定义后处理逻辑。量产版本建议关闭该选项。
当 model_mem 非 NULL 时,模块会从该内存指针加载模型,而不是从文件系统加载。这适用于将模型二进制直接嵌入固件的场景。
完整模块初始化
static nn_data_param_t nn_input_params = {
.img = {
.width = NN_WIDTH,
.height = NN_HEIGHT,
},
.codec_type = AV_CODEC_ID_RGB888
};
vipnn_ctx = mm_module_open(&vipnn_module);
if (vipnn_ctx) {
mm_module_ctrl(vipnn_ctx, CMD_VIPNN_SET_MODEL, (int)&NN_MODEL_OBJ);
mm_module_ctrl(vipnn_ctx, CMD_VIPNN_SET_MODEL_FILE_NAME, (int)nn_model_file_name);
mm_module_ctrl(vipnn_ctx, CMD_VIPNN_SET_IN_PARAMS, (int)&nn_input_params);
mm_module_ctrl(vipnn_ctx, CMD_VIPNN_SET_DISPPOST, (int)nn_display_cb);
mm_module_ctrl(vipnn_ctx, CMD_VIPNN_SET_RES_SIZE, sizeof(objdetect_res_t));
mm_module_ctrl(vipnn_ctx, CMD_VIPNN_SET_RES_MAX_CNT, 32);
mm_module_ctrl(vipnn_ctx, CMD_VIPNN_APPLY, 0);
}
设置输入图像参数
使用 CMD_VIPNN_SET_IN_PARAMS 描述传给 VIPNN 的输入帧:
nn_data_param_t nn_input_params = {
.img = {
.width = NN_WIDTH, // incoming RGB/NV12 frame width
.height = NN_HEIGHT, // incoming RGB/NV12 frame height
},
.codec_type = AV_CODEC_ID_RGB888 // or AV_CODEC_ID_NV12
};
mm_module_ctrl(vipnn_ctx, CMD_VIPNN_SET_IN_PARAMS, (int)&nn_input_params);
如果模型内部包含预处理或缩放 layer,V5 RGB 输入帧尺寸可以与逻辑检测输入尺寸不同。此时 width / height 应保持为真实输入帧尺寸,并通过 model_width / model_height 指定后处理使用的检测尺寸:
#define V5_RGB_WIDTH 1280
#define V5_RGB_HEIGHT 720
#define NN_WIDTH 416
#define NN_HEIGHT 416
nn_data_param_t nn_input_params = {
.img = {
.width = V5_RGB_WIDTH,
.height = V5_RGB_HEIGHT,
.model_width = NN_WIDTH,
.model_height = NN_HEIGHT,
},
.codec_type = AV_CODEC_ID_RGB888
};
备注
codec_type 必须与上游 V5 video module 的输出格式一致。需要 RGB 输入的模型应使用 VIDEO_RGB + AV_CODEC_ID_RGB888。width 和 height 表示完整输入帧;ROI 不再通过 nn_data_param_t 配置。如果输入帧尺寸与网络张量尺寸不同且模型本身没有预处理 layer,则模型预处理代码会在推理前对完整帧进行 resize。
设置 NN 模型
每个支持的模型都由一个 nnmodel_t 对象表示,其中绑定了模型二进制、预处理函数和后处理函数。
#include "model_yolo.h"
#define NN_MODEL_OBJ yolov4_tiny
#define NN_MODEL_NAME "vfs:/yolov4_tiny_asymu8.nb"
mm_module_ctrl(vipnn_ctx, CMD_VIPNN_SET_MODEL, (int)&NN_MODEL_OBJ);
mm_module_ctrl(vipnn_ctx, CMD_VIPNN_SET_MODEL_FILE_NAME, (int)NN_MODEL_NAME);
设置结果回调
使用 CMD_VIPNN_SET_DISPPOST 注册回调,以便在每帧推理完成后接收结果。该回调在 VIPNN task 上下文中执行,应尽量保持简短且避免阻塞。
static void nn_display_cb(void *p, void *img_param)
{
vipnn_out_buf_t *out = (vipnn_out_buf_t *)p;
objdetect_res_t *res = (objdetect_res_t *)&out->res[0];
int obj_num = out->res_cnt;
for (int i = 0; i < obj_num; i++) {
RTK_LOGI(TAG, "class=%d score=%.2f [%.2f %.2f %.2f %.2f]\r\n",
(int)res[i].result[0], res[i].result[1],
res[i].result[2], res[i].result[3],
res[i].result[4], res[i].result[5]);
}
}
设置检测阈值
目标检测和人脸检测模型通常通过两个后处理阈值过滤结果:
CMD_VIPNN_SET_CONFIDENCE_THRES:置信度阈值CMD_VIPNN_SET_NMS_THRES:NMS 阈值
过滤 Class ID
如需只保留特定类别,可在后处理或显示回调中根据 class_id 过滤输出结果。目标检测模型的类别 ID 与训练数据集保持一致,例如 YOLO COCO 模型使用 COCO 80 类 ID。
级联模式
级联模式将两个 VIPNN 模块实例串联起来。第一阶段模型(例如 SCRFD 人脸检测)的输出可直接作为第二阶段模型(例如 MobileFaceNet 人脸识别)的输入,从而形成检测后识别的流程,无需在两个阶段之间编写额外 glue code。
SDK 人脸识别示例会使用以下 VIPNN 控制项:
CMD_VIPNN_SET_OUTPUT:使能模块输出MM_CMD_SET_DATAGROUP:设置 data group 的起点或终点CMD_VIPNN_SET_CASCADE_MODE:设置级联模式,例如VIPNN_CMODE_ALL_ROI
facerecog 模块
facerecog_module 用于保存、加载并比对人脸特征。模块会将 MobileFaceNet 输出的 128 维 embedding 与已注册的人脸数据库进行相似度比较,并通过 OSD 回调显示识别结果。
模块命令参考
常用控制命令如下:
命令 |
说明 |
|---|---|
|
设置 |
|
设置 |
|
设置输入图像参数 |
|
设置推理结果显示或处理回调 |
|
设置单个结果结构体大小 |
|
设置每帧最多输出结果数量 |
|
应用配置并初始化 NPU network |
关于 NN 媒体示例的使用方式,请参考 媒体示例 。
NN 内存布局
NPU 在 DDR 中使用专用区域保存模型权重、输入/输出 tensor 以及中间计算 buffer。NN DDR 窗口在 linker script ameba_layout.ld 中定义:
NN_DDR (rwx) : ORIGIN = 0x87400000, LENGTH = 12M
Address range: 0x87400000 - 0x87FFFFFF (12 MB)
完整 DDR 内存映射如下:
Region |
Base |
Size |
Usage |
|---|---|---|---|
|
0x80420000 |
~28 MB |
Application code, heap, stack |
|
0x82000000 |
32 MB |
Encoder (H.264/HEVC) working memory |
|
0x84000000 |
48 MB |
Video processor (ISP) working memory |
|
0x87000000 |
4 MB |
Tile scaler / graphics engine |
|
0x87400000 |
12 MB |
NPU model + tensor buffers |
NPU 硬件参考
计算性能
Data type |
MACs / cycle |
Notes |
|---|---|---|
INT8 |
768 MACs -> ~1 TOPS |
默认格式,吞吐最高 |
INT16 (DFP) |
192 MACs |
适用于更高数值精度需求 |
FP16 / BF16 |
384 MACs |
浮点格式,可用于 PPU 侧执行的 layer |
NPU 架构
NPU 包含三个与软件开发相关的计算子系统:
- Neural Network Engine (NNE)
并行 MAC 阵列,包含多个卷积核心,负责 convolution、depthwise convolution 和 GEMM(fully-connected)等运算,是标准 DNN layer 的主要加速单元。支持 INT8、INT16、FP16 和 BF16。
- Parallel Processing Unit (PPU)
SIMD 可编程执行单元,主要用于:
前处理与后处理 kernel(OpenCL / OpenVX)
NNE 不原生支持的自定义 NN layer
activation、normalisation、reshape 等轻量级算子
IEEE 32-bit floating-point pipeline
- Vision Engine (EVIS)
硬件加速图像处理单元,支持 3x3 filtering、bilinear interpolation(Lerp)、histogram、packed image load/store 以及 dot product 等操作。runtime driver 会使用该单元进行输入格式转换。
NPU 通过 AXI bus 与 SoC 通信,并支持 32-bit 物理地址的虚拟内存机制。
支持的量化格式
格式 |
说明 |
使用场景 |
|---|---|---|
|
非对称 unsigned INT8 |
吞吐最高,大多数模型的默认格式 |
|
对称 INT16(Dynamic Fixed Point) |
需要更高精度时使用 |
|
IEEE 16-bit floating point |
混合精度或 PPU 执行的 layer |
|
Brain floating-point 16-bit tensor format |
由 SDK 工具解析的浮点输出 |
支持的输入图像格式
NPU 可原生处理以下图像格式,无需额外转换成本:
格式 |
说明 |
|---|---|
|
24-bit RGB888,3-channel interleaved(BT.709) |
|
YUV 4:2:0 semi-planar,ISP 原生输出格式 |
|
32-bit RGBX(R, G, B + don't-care byte) |
|
Unsigned 8-bit single-channel |
|
Signed 16-bit single-channel |
在此视频管线中,V5 ISP 通道输出 RGB888 帧,可直接送入 VIPNN 模块,无需额外转换。
支持的 NN layer 类型
NNE 可加速所有标准 DNN layer。不支持或自定义的 layer 会回退到 PPU 执行。
类别 |
操作 |
|---|---|
卷积 (Convolution) |
CONV3D, CONV2D, CONV1D, DECONVOLUTION, DECONVOLUTION1D, GROUPED_CONV2D, FCL2 |
激活 (Activation) |
RELU, LEAKY_RELU, PRELU, SIGMOID, TANH, SOFTMAX, LOG_SOFTMAX, SWISH, MISH, ELU, HARD_SIGMOID, CLIP, EXP, LOG, SQRT, RSQRT, ABS, NEG, LINEAR, SIN, ERF |
逐元素运算 (Elementwise) |
ADD, SUBTRACT, MULTIPLY, DIVIDE, MAXIMUM, MINIMUM, POW, FLOORDIV, MATRIXMUL, RELATIONAL_OPS, LOGICAL_OPS, SELECT, ADDN |
归一化 (Normalisation) |
BATCH_NORM, LAYER_NORM, INSTANCE_NORM, GROUP_NORM, L2_NORMALIZE, MOMENTS |
形状 / 张量操作 (Reshape / Tensor) |
CONCAT, SLICE, SPLIT, RESHAPE, SQUEEZE, PERMUTE, PAD, REVERSE, SPACE2DEPTH, DEPTH2SPACE, BATCH2SPACE, STRIDED_SLICE, REDUCE, ARGMAX, ARGMIN, SHUFFLECHANNEL, RESIZE, EXPAND_BROADCAST |
循环网络 (Recurrent / RNN) |
LSTMUNIT, GRUCELL, GRU, SVDF |
池化 (Pooling) |
MAX_POOL, AVG_POOL, ROI_POOL, POOLWITHARGMAX, UPSAMPLE |
其他 (Miscellaneous) |
PROPOSAL, VARIABLE, DROPOUT, STACK, UNSTACK, REORG, GATHER, SCATTER_ND, ONE_HOT, CAST |
软件栈
NPU runtime 向应用软件提供以下 API:
OpenVX 1.3 + OpenVX 1.2 Neural Network Extension :主要 NN 推理 API
OpenCL 3.0 / 1.2 Full Profile :用于 PPU 上的自定义计算 kernel
Proprietary Extensions for CNN :用于 NN 加速与自定义 layer 的 vendor extension
VIP Lite API (
vip_lite.h):底层 NPU 控制接口,vipnn_module内部会使用该接口
使用常见 AI 框架(Keras、TensorFlow、TFLite、PyTorch、Caffe、ONNX、Darknet)训练的神经网络模型,需要离线通过 Acuity Toolkit 转换为编译后的网络二进制文件(.nb),然后在运行时从 LittleFS flash 分区(vfs:)或 SD 卡(sd:)加载。
自定义模型转换
如果需要将自训练模型转换为 NPU 可运行的 .nb 格式,请联系 Realtek 业务或技术支持窗口获取进一步协助。