INT8 量化推理部署
本章讲在 RK182X 上部署 INT8 量化模型并推理优化:RKNN3 C API + Python API + 性能调优 + 精度验证。
整体框图
应用进程
↓
C API / Python API (librknn3_api.so / rknn3lite)
↓
rknn3_transfer_proxy (PCIe 代理)
↓
RK1828 NPU (8 核)RK182X 使用 RKNN3 Toolkit。RKNN-Toolkit2 用于 RK3588 等主控 SoC。代码示例全部以 RKNN3 为准。
如需生成 INT8 模型,请先参考 模型转换。
1. C API 推理
实测可编译运行的 CNN 推理骨架(
aarch64-linux-gnu-gcc编译,板端跑通):
#include "rknn3_api.h" // 头文件需向 Rockchip 索取
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(context, model_path, weight_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为准
rknn3_profile_mem 实测输出(NPU 8 个独立节点,各约 620~640 MB):
=========================== Memory Usage Information ===========================
Device Memory:
System : 19.12 MB total, 6.12 MB free, 13.00 MB used ( 68.0%)
Node 0 : 639.50 MB total, 418.29 MB free, 221.21 MB used ( 34.6%)
Node 1 : 639.50 MB total, 523.37 MB free, 116.13 MB used ( 18.2%)
Node 2 : 619.90 MB total, 503.98 MB free, 115.91 MB used ( 18.7%)
Node 3 : 639.50 MB total, 523.36 MB free, 116.14 MB used ( 18.2%)
Node 4 : 619.90 MB total, 504.06 MB free, 115.84 MB used ( 18.7%)
Node 5 : 619.90 MB total, 504.14 MB free, 115.76 MB used ( 18.7%)
Node 6 : 639.50 MB total, 523.97 MB free, 115.53 MB used ( 18.1%)
Node 7 : 639.50 MB total, 524.95 MB free, 114.55 MB used ( 17.9%)2. 编译(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/userdata/RK1820_RK1828_AI_SDK/rknn/rknn3-runtime/rknn3-api/includeRK3588 上编译成功:
librknn3_api在/usr/lib/librknn3_api.so,头文件路径需明确指定。
验证编译命令:
which aarch64-linux-gnu-gcc
ls /usr/lib/librknn3_api.so
ls /userdata/RK1820_RK1828_AI_SDK/rknn/rknn3-runtime/rknn3-api/include/rknn3_api.h输出:
/usr/bin/aarch64-linux-gnu-gcc
/usr/lib/librknn3_api.so
/userdata/RK1820_RK1828_AI_SDK/rknn/rknn3-runtime/rknn3-api/include/rknn3_api.h3. Python API 推理
python3 -c "from rknn3lite.api import RKNN3Lite; print('RKNN3Lite API available')"输出:
RKNN3Lite API availablefrom 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)——内存分析只有 C API 的rknn3_profile_mem。实测可用方法(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等。
4. 性能调优
| 参数 | 推荐值 |
|---|---|
| 输入格式 | NHWC(RKNN3 默认) |
| 输入类型 | uint8(convert.py 用 dtype='uint8') |
| 批大小 | 1(跟训练时一致) |
| 核心频率 | 最高频(通过 /rockchip-test/npu2/npu_freq_scaling.sh 或 sysfs) |
| 内存分配 | 各 NPU 节点独立 620~640 MB(用 C API rknn3_profile_mem 查看占用) |
5. 性能测试工具
NPU 工具目录:
ls /rockchip-test/npu2/输出:
model
npu_freq_scaling.sh
npu_stress_test.sh
npu_test.shrknn3_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]
- If input_npy_paths is not provided, random input will be generated
- If golden_output_npy_paths is not provided, cosine similarity will be skipped
- If core_mask is not provided, it will be auto-generated based on core_number
- If you want to use both random input and set core_mask or loop_count, you can set both input_npy_paths and golden_output_npy_paths to empty strings.6. INT8 推理精度优化
6.1 排查流程
- 检查校准数据集数量(建议 20 张代表性样本)
- 按模型类型选择数据集:
- LLM →
datasets/CMMLU/dataset.json - CNN →
datasets/imagenet/.../dataset_20.txt
- LLM →
- 精度验证用
/usr/bin/rknn3_model_test(对比 golden output 余弦相似度;rknn3lite 无profile_ops方法)
6.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',
)7. 已部署的 INT8 模型
ls -lh /userdata/models/Qwen3-1.7B/输出:
总计 1.7G
-rw-r--r-- 1 linaro linaro 594M 8月20日 11:33 Qwen3-1.7B.embed.bin
-rw-r--r-- 1 linaro linaro 24M 8月20日 11:34 Qwen3-1.7B.rknn
-rw-r--r-- 1 linaro linaro 5.9M 8月20日 11:33 Qwen3-1.7B.tokenizer.gguf
-rw-r--r-- 1 linaro linaro 1.1G 8月20日 11:33 Qwen3-1.7B.weight8. RK1828 NPU 实际性能
| 模型 | 推理时间 | FPS / TPS |
|---|---|---|
| MobileNet V2 FP16(rknn3lite) | 5.40 ms | 185.1 FPS(10 次平均) |
| MobileNet V2 FP16(rknn3_cnn_demo) | 4.54 ms | 220 FPS(见 CNN 推理) |
| Qwen3-1.7B (TTFT) | 70 ms | — |
| Qwen3-1.7B (TPS) | — | 133 tok/s |
9. 常见问题
| 现象 | 原因 | 处理 |
|---|---|---|
rknn3_api.h: No such file | SDK include 路径未指定 | 加 -I/userdata/RK1820_RK1828_AI_SDK/.../include |
cannot find -lrknn3_api | 库路径不在 /usr/lib | 确认 /usr/lib/librknn3_api.so 存在 |
profile_mem AttributeError | 用 rknn3lite 调 Python 内存分析 | 改用 C API |
core_mask X is not match ... | -c 与模型核数不匹配 | CNN 用 0x01,LLM 用 0xff |
| 精度掉点严重 | 校准集不足 / 类型错 | 用 20+ 样本 + w8a8 dtype |
10. 下一步
11. 参考文档
RK1820_RK1828_AI_Release-Note_CN.md(SDK 内)— RKNN3 V1.0.0 更新日志Rockchip_RK1820_RK1828_AI_SDK_RELEASE_CN.pdf(SDK 内)— Release NoteRockchip_RK1820_RK1828_AI_SDK_Quick_Start_CN.pdf(SDK 内)— 快速开始
