前面几篇把 RKNN3 工具链、RKLLM 运行时、NPU 架构都过了一遍,这篇聚焦到最实际的环节——INT8 量化模型在 RK1828 上怎么跑起来。包括 C API 和 Python API 两条路怎么打通、编译踩坑、性能调优、精度验证。
前提: 要生成 INT8 模型,先去看前面的模型转换那篇,这里假设你已经有了 .rknn 和 .weight 文件。
一、整体调用链路
先搞清楚调用关系,心里有个数:
应用进程
↓
C API / Python API (librknn3_api.so / rknn3lite)
↓
rknn3_transfer_proxy (PCIe 代理)
↓
RK1828 NPU (8 核)
划重点: RK182X 系列用的是 RKNN3 Toolkit,RKNN-Toolkit2 是 RK3588 那些主控 SoC 用的。所有代码都是基于 RKNN3。
二、C API 推理(已验证可编译可运行)
这是一段完整的 CNN 推理骨架代码,用 aarch64-linux-gnu-gcc 编译通过,在板子上跑过:
#include "rknn3_api.h" // 头文件需要找瑞芯微要
int main(int argc, char* argv[]) {
rknn3_context ctx = 0;
rknn3_init_extend ext = {0};
int ret = rknn3_init(&ctx, &ext); // 必须传 context 指针 + init_extend
ret = rknn3_load_model_from_path(ctx, argv[1], argv[2]);
// 只传 3 个参数(context, model_path, weight_path),没有 core_mask 参数
rknn3_config cfg = {0};
cfg.run_core_mask = 0x01; // core_mask 在这里传
// CNN(如 MobilenetV2)用 0x01;LLM/VLM 用 0xff
ret = rknn3_model_init(ctx, &cfg);
ret = rknn3_profile_mem(ctx); // profile_mem 只在 C API 里有
rknn3_destroy(ctx); // 销毁 context
return 0;
}
C API 和 LLM API 的区别(对照头文件签名验证过的):
- CNN 推理走
rknn3_run(context, inputs, n_inputs, outputs, n_outputs);rknn3_session_run(session, ...)是 LLM 专用的,别搞混了 rknn3_load_model_from_path只接 3 个参数,core_mask 不在这里传,是通过rknn3_config.run_core_mask在rknn3_model_init()里传的rknn3_destroy(context)销毁 context;rknn3_session_destroy(session)是 LLM session 的销毁接口- 完整签名参考 SDK 里的
rknn/rknn3-runtime/rknn3-api/include/rknn3_api.h
三、编译(直接在 RK3588 上编)
# librknn3_api 库在 /usr/lib/librknn3_api.so
# 但 rknn3_api.h 头文件不在标准 include 路径下,必须手动指定 SDK 路径
aarch64-linux-gnu-gcc int8_inference.c -o int8_inference \
-lrknn3_api \
-I/home/firefly/sdk/rknn/rknn3-runtime/rknn3-api/include
踩坑提醒: librknn3_api.so 在 /usr/lib/ 下,链接器能找到;但头文件不在标准路径,必须用 -I 指定,否则编译直接报 rknn3_api.h: No such file or directory。
验证编译环境:
which aarch64-linux-gnu-gcc
ls /usr/lib/librknn3_api.so
ls /home/firefly/sdk/rknn/rknn3-runtime/rknn3-api/include/rknn3_api.h
三个都能找到就没问题:
/usr/bin/aarch64-linux-gnu-gcc
/usr/lib/librknn3_api.so
/home/firefly/sdk/rknn/rknn3-runtime/rknn3-api/include/rknn3_api.h
四、Python API 推理
先确认 rknn3lite 可用:
python3 -c "from rknn3lite.api import RKNN3Lite; print('RKNN3Lite API available')"
输出 RKNN3Lite API available 就行。
推理代码:
from rknn3lite.api import RKNN3Lite
rknn_lite = RKNN3Lite()
rknn_lite.load_rknn('model.rknn', 'model.weight')
rknn_lite.init_runtime(target='rk1820', core_mask=0x01) # CNN: 1 核;LLM/VLM 用 0xff
# 准备输入(NHWC, uint8)
outputs = rknn_lite.inference(inputs=[input_data])
注意: rknn3lite 没有 profile_mem 和 profile_ops 方法(用 hasattr 验证过,都是 False)。内存 Profiling 只能通过 C API 的 rknn3_profile_mem 来做。
rknn3lite 实际可用的方法(dir() 验证,共 19 个):load_rknn / init_runtime / inference / session_run / llm / get_devices_id / get_inputs_tensor_attr / get_outputs_tensor_attr / get_sdk_version / set_chat_template / release 等。
五、性能调优参数
| 参数 | 推荐值 |
|---|---|
| 输入格式 | NHWC(RKNN3 默认) |
| 输入类型 | uint8(convert.py 里 dtype='uint8') |
| Batch size | 1(和训练时保持一致) |
| 核心频率 | 最大频率(通过 /rockchip-test/npu2/npu_freq_scaling.sh 或 sysfs 调整) |
| 显存分配 | 每个独立 NPU 节点 620~640 MB(用 C API rknn3_profile_mem 查看) |
六、性能测试工具
板子上自带了 NPU 测试工具,在 /rockchip-test/npu2/ 目录下:
ls /rockchip-test/npu2/
model
npu_freq_scaling.sh
npu_stress_test.sh
npu_test.sh
rknn3_model_test 的用法:
/usr/bin/rknn3_model_test --help
Usage: /usr/bin/rknn3_model_test <model_path> <weight_path> <input_npy_paths>
<golden_output_npy_paths> <core_mask> [loop_count]
- input_npy_paths 不提供则使用随机输入
- golden_output_npy_paths 不提供则跳过余弦相似度对比
- core_mask 不提供则根据 core_number 自动生成
- 如果想用随机输入同时设置 core_mask 或 loop_count,
把 input_npy_paths 和 golden_output_npy_paths 都设成空字符串
这个工具很实用,可以快速验证模型推理是否正常,还能做精度对比。
七、INT8 推理精度优化
7.1 排查流程
精度不对的时候,按这个顺序排查:
- 检查校准数据集大小(推荐 20 个有代表性的样本)
- 按模型类型选数据集:
- LLM →
datasets/CMMLU/dataset.json - CNN →
datasetsdataset_20.txt
- LLM →
- 用
/usr/bin/rknn3_model_test验证精度(对比 golden output 的余弦相似度;rknn3lite 没有profile_ops方法)
7.2 关键配置
rknn.config(
target_platform='rk1820',
mean_values=[[255*0.485, 255*0.456, 255*0.406]], # ImageNet 标准化
std_values=[[255*0.229, 255*0.224, 255*0.225]],
input_attrs={'input': {'dtype': 'uint8', 'layout': 'NHWC'}},
quantized_dtype='w8a8',
)
提醒: target_platform 还是写 'rk1820',不是 'rk1828'。这个坑前面几篇也反复提了,这里再强调一次。
八、已部署的 INT8 模型
以 Qwen3-1.7B 为例,转换后生成的文件:
ls -lh /home/firefly/models/Qwen3-1.7B/
-rw-r--r-- 1 firefly firefly 594M 9月14日 14:10 Qwen3-1.7B.embed.bin
-rw-r--r-- 1 firefly firefly 24M 9月14日 14:11 Qwen3-1.7B.rknn
-rw-r--r-- 1 firefly firefly 5.9M 9月14日 14:10 Qwen3-1.7B.tokenizer.gguf
-rw-r--r-- 1 firefly firefly 1.1G 9月14日 14:10 Qwen3-1.7B.weight
总共约 1.7 GB,其中权重文件 1.1G 占大头,embedding 594M 也不小。拷到板子上的时候注意这几个文件都要拷全,少一个都跑不起来。
有遇到其他问题的欢迎评论区交流。