Rk1828 开发实战:int8 量化推理部署

前面几篇把 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 排查流程

精度不对的时候,按这个顺序排查:

  1. 检查校准数据集大小(推荐 20 个有代表性的样本)
  2. 按模型类型选数据集:
    • LLM → datasets/CMMLU/dataset.json
    • CNN → datasetsdataset_20.txt
  3. 用 /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 也不小。拷到板子上的时候注意这几个文件都要拷全,少一个都跑不起来。


有遇到其他问题的欢迎评论区交流。