← 返回博客

如何在君正 T33 上用 Magik NPU 加速声音识别

君正 T33 是一款广泛应用于 IPC 摄像头和电池供电 IoT 设备的 SoC,它将 MIPS CPU 与一颗算力约 0.6 TOPS 的 Magik NPU 结合在一起。对于声音识别场景,利用 NPU 加速是将 CPU 占用从 45 MHz 降到几乎为零的关键。

本文详细介绍完整的工作流程:模型准备、Magik 工具链配置、IMP 音频框架集成、以及性能优化。

T33 架构图
君正 T33 声音识别系统架构

为什么要用 Magik NPU?

T33 的 CPU 是一颗 1GHz 的 MIPS 核心。完全在 CPU 上运行声音识别模型虽然可行,但代价不小:

指标
纯 CPU (MIPS)
Magik NPU
CPU 占用
~45 MHz
~5 MHz
推理延迟 (每 5s 窗口)
~12 ms
~3 ms
功耗 (推理时)
~120 mW
~35 mW
留给其他任务的余量
有限
充裕

对于一台同时要编码 H.264 视频、运行 Wi-Fi、处理 RTSP 流媒体的电池摄像头来说,将声音推理卸载到 NPU 不是可选项——而是做出实用产品的必要条件。

前置准备

开始之前,确保你已具备以下条件:

硬件 — 君正 T33 开发板(或基于 T33 的自研 PCB)

工具链 — 君正 Magik Toolkit v3.2(联系君正 FAE 或从开发者门户下载)

SDK — 君正 SDK T31/T33,包含 IMP(Ingenic Media Platform)音频框架

模型 — 训练好的 PyTorch 模型,已导出为 TFLite 格式(FP32 或 INT8)

主机 — Linux x86_64(推荐 Ubuntu 20.04+),用于运行 Magik 编译器

目录结构应如下:

code
/home/user/magik-toolkit-v3.2/
├── compiler/
│   └── magik_compile          # NPU 模型编译器
├── runtime/
│   ├── include/
│   │   └── magik_runtime.h    # NPU 运行时 API 头文件
│   └── lib/
│       └── libmagik.so        # NPU 运行时库
├── examples/
│   └── t33/
│       └── sample_magik.c     # NPU 推理示例
└── docs/
    └── magik_compile_guide.pdf

步骤 1:导出模型为 TFLite

Magik 工具链以 TFLite 模型为输入。通过 ONNX 将 PyTorch 模型导出:

模型转换流程图
PyTorch → TFLite → Magik 编译全流程

首先,将 PyTorch 导出为 ONNX:

pythonpython
import torch
import torch.onnx

from sound_net import SimplifiedSoundNet

model = SimplifiedSoundNet(num_classes=2)
model.load_state_dict(torch.load("sound_net.h5", map_location="cpu"))
model.eval()

dummy_input = torch.randn(1, 1, 225, 225)
torch.onnx.export(model, dummy_input, "model.onnx",
    input_names=["input"], output_names=["output"],
    opset_version=13)
print("ONNX export done")

然后将 ONNX 转换为 TFLite。最简单的方式使用 onnx2tf 工具:

bashbash
pip install onnx2tf
onnx2tf -i model.onnx -o tflite_output/

这会生成 tflite_output/model_float32.tflite。

步骤 2:使用 Magik 工具链编译

准备好 TFLite 模型后,使用 Magik 编译器为 T33 NPU 生成模型二进制文件:

bashbash
# 设置 Magik 工具链环境
export MAGIK_HOME=/home/user/magik-toolkit-v3.2
export PATH=$MAGIK_HOME/compiler:$PATH

# 编译 T33 目标
magik_compile     --model model_float32.tflite     --output model_magik.nb     --target t33     --quantization uint8     --input_mean 0     --input_std 1

关键参数说明:

参数
说明
`--target t33`
目标 SoC。可选:t31, t33
`--quantization uint8`
将权重从 FP32 量化为 UINT8。模型大小缩减 4 倍,准确率损失极小。
`--input_mean / --input_std`
与训练一致的输入归一化参数
`--output model_magik.nb`
编译后的 NPU 二进制文件(nb = Neural network Binary)

编译器输出 .nb 文件——这是在 NPU 上运行的模型二进制。

步骤 3:集成 IMP 音频框架

T33 通过 IMP(Ingenic Media Platform)框架采集音频。以下是最小集成模式:

cc
#include <imp/imp_audio.h>
#include <imp/imp_system.h>
#include "magik_runtime.h"

// 音频采集配置
#define SAMPLE_RATE 16000
#define FRAME_MS 20          // 每帧 20ms
#define WINDOW_MS 5000       // 5 秒检测窗口

static magik_ctx_t *g_magik = NULL;
static float g_mel_buffer[1 * 1 * 225 * 225];

// 初始化 IMP 音频采集
int audio_init() {
    // ... IMP 音频初始化代码 ...
    return 0;
}

// 初始化 Magik NPU 运行时
int npu_init(const char *model_path) {
    magik_config_t cfg = {
        .model_path = model_path,
        .npu_id = 0,          // T33 有一个 NPU 核心
        .thread_count = 1,
    };
    g_magik = magik_init(&cfg);
    if (!g_magik) return -1;
    return 0;
}

// 处理一个 5 秒音频窗口
int process_window(const int16_t *audio_5s) {
    // 1. 计算 Mel 频谱图 (225×225)
    mel_from_audio(audio_5s, SAMPLE_RATE, g_mel_buffer);

    // 2. 运行 NPU 推理
    magik_tensor_t input = {
        .data = g_mel_buffer,
        .shape = {1, 1, 225, 225},
        .dtype = MAGIK_FLOAT32,
    };
    magik_tensor_t output;
    magik_run(g_magik, &input, 1, &output, 1);

    // 3. 读取结果(output 为 [non_cry, cry] 概率)
    float *probs = (float *)output.data;
    float cry_confidence = probs[1];

    if (cry_confidence > 0.5f) {
        printf("检测到哭声!置信度=%.3f\n", cry_confidence);
    }

    magik_free_tensor(&output);  // 释放 NPU 输出缓冲区
    return 0;
}

步骤 4:编译和运行

使用交叉编译器编译:

bashbash
# 使用 MIPS 交叉编译器
mips-linux-uclibc-gcc -o sound_detect_t33 \
    main.c \
    -I${MAGIK_HOME}/runtime/include \
    -L${MAGIK_HOME}/runtime/lib \
    -lmagik -limp -lpthread \
    -O2 -march=mips32r2

部署到 T33 开发板:

bashbash
# 通过 HTTP 服务器上传(T33 典型工作流)
# 在 PC 端:
python c/t33/http_server.py

# 在 T33 开发板上:
wget http://192.168.0.xxx:8000/sound_detect_t33
wget http://192.168.0.xxx:8000/model_magik.nb
chmod +x sound_detect_t33
./sound_detect_t33

性能测试结果

在我们 T33 评估板上使用标准模型的测试结果:

指标
值
模型大小 (INT8 量化)
320 KB
NPU 推理时间
每 5 秒窗口 3.2 ms
CPU 占用 (NPU 卸载后)
~5 MHz
内存占用 (峰值)
4.8 MB
精度 vs FP32 基线
-0.3%(保留了 99.7%)

NPU 卸载将 CPU 占用降低了约 9 倍(相比在 MIPS CPU 上运行相同模型),将核心解放出来用于视频编码和网络任务。

常见问题与解决方案

问题:Magik 编译器报错,提示不支持的算子。

解决方案:Magik NPU 支持有限的算子集合(Conv2D、DepthwiseConv2D、ReLU、Add、AveragePool 等)。确保模型只使用支持的算子。导出前替换不支持的算子(例如 LeakyReLU → ReLU、Sigmoid → ReLU)。我们的模型使用标准架构,与 Magik 的算子集兼容。

问题:运行时错误 "NPU firmware not loaded"。

解决方案:确保在调用 magik_init() 之前,内核驱动已加载 NPU 固件。在开发板的初始化脚本中添加:echo /lib/firmware/magik_fw.bin > /sys/class/misc/magik/load_fw

问题:音频采集延迟过高。

解决方案:IMP 默认音频缓冲区可能过大。在 IMP 配置中将 imp_audio_frame_info.frame_num = 4,可将缓冲延迟降到 ~80ms。

结论

君正 T33 的 Magik NPU 使声音识别在电池供电的摄像头和 IoT 设备上变得实用。将模型编译到 NPU 后,你可以在接近零 CPU 开销下获得低于 5ms 的推理延迟——将整个 MIPS 核心留给主应用。

我们的 soundSDK 包含 T33 平台的预编译库和模型文件。SDK 处理了 Magik 运行时初始化、Mel 频谱图计算和结果回调——将集成周期从数周缩短到数天。

作者:softlgh | soundSDK —— 面向边缘设备的离线声音识别 SDK | 官网:https://51tage.com

想亲自体验识别效果?