149 lines
4.4 KiB
Markdown
149 lines
4.4 KiB
Markdown
# SCRFD RKNN 推理崩溃问题
|
||
|
||
## 问题现象
|
||
|
||
SCRFD 640x640 人脸检测模型在推理时立即崩溃:
|
||
|
||
```
|
||
terminate called after throwing an instance of 'std::out_of_range'
|
||
what(): vector::_M_range_check: __n (which is 18446744073709551615) >= this->size() (which is 1)
|
||
```
|
||
|
||
崩溃发生在 `rknn_inputs_set()` 调用时。
|
||
|
||
## 环境信息
|
||
|
||
- **平台**: Orange Pi 5 Plus (RK3588)
|
||
- **RKNN 运行时**: 最初 1.5.2,后更新到 2.3.2
|
||
- **RKNN-Toolkit2**: 2.3.2
|
||
- **模型**: SCRFD 2.5G 640 (版本 2.3.2)
|
||
|
||
## 根因分析
|
||
|
||
### 1. RKNN 库版本不匹配
|
||
|
||
系统最初安装的 `librknnrt.so` 是 **1.5.2** 版本:
|
||
```bash
|
||
$ strings /usr/local/lib/librknnrt.so | grep "librknnrt version"
|
||
librknnrt version: 1.5.2 (c6b7b351a@2023-08-23T15:28:22)
|
||
```
|
||
|
||
但 SCRFD 模型是用 **2.3.2** 版本的 toolkit 编译的:
|
||
```bash
|
||
$ strings scrfd_2.5g_640.rknn | grep "compiler version"
|
||
2.3.2(compiler version: 2.3.2 (@2025-04-03T08:26:16))
|
||
```
|
||
|
||
### 2. 动态形状模型兼容性问题
|
||
|
||
SCRFD 2.3.2 模型使用**动态形状** (`dynamic_shape`):
|
||
- 输入/输出维度在运行时才确定
|
||
- C API `rknn_inputs_set()` 无法正确处理
|
||
- Python API (rknnlite) 可以正常工作
|
||
|
||
对比不同版本的模型输出维度:
|
||
|
||
| 模型 | 版本 | 输出维度示例 | 是否崩溃 |
|
||
|------|------|-------------|---------|
|
||
| SCRFD 2.5G 640 | 2.3.2 | `[12800, 1]` (2D, 动态) | ✅ 崩溃 |
|
||
| SCRFD 500M 640 | 1.4.1b16 | `[1, 12800, 1, 1]` (4D, 静态) | ✅ 正常 |
|
||
| RetinaFace 320 | 2.3.2 | `[1, 4200, 4]` (静态) | ✅ 正常 |
|
||
| YOLOv8n 640 | 2.3.2 | `[1, 84, 8400]` (静态) | ✅ 正常 |
|
||
|
||
## 解决方案
|
||
|
||
### 步骤 1: 更新 RKNN 运行时库
|
||
|
||
将系统库更新到与模型编译版本一致:
|
||
|
||
```bash
|
||
# 备份旧版本
|
||
sudo cp /usr/local/lib/librknnrt.so /usr/local/lib/librknnrt.so.1.5.2.backup
|
||
|
||
# 删除旧版本
|
||
sudo rm /usr/local/lib/librknnrt.so
|
||
|
||
# 链接新版本 (系统已安装的 2.3.2)
|
||
sudo ln -s /usr/lib/librknnrt.so /usr/local/lib/librknnrt.so
|
||
|
||
# 验证
|
||
strings /usr/local/lib/librknnrt.so | grep "librknnrt version"
|
||
# 应输出: librknnrt version: 2.3.2 (429f97ae6b@2025-04-09T09:09:27)
|
||
```
|
||
|
||
### 步骤 2: 使用兼容的模型版本
|
||
|
||
由于动态形状模型在 C API 中存在兼容性问题,建议使用**静态形状**版本:
|
||
|
||
**推荐模型**: `face_det_scrfd_500m_640_rk3588.rknn` (版本 1.4.1b16)
|
||
- 版本: 1.4.1b16-dad86923
|
||
- 编译时间: 2022-11-26
|
||
- 输入: 640x640x3, NHWC
|
||
- 输出: 9个张量 (scores_8/16/32, bbox_8/16/32, kps_8/16/32)
|
||
|
||
**不兼容模型**: `scrfd_2.5g_640.rknn` (版本 2.3.2)
|
||
- 动态形状导致 C API 崩溃
|
||
- 仅能通过 Python rknnlite 使用
|
||
|
||
### 步骤 3: 正确的 RKNN 输入配置
|
||
|
||
对于量化 INT8 模型,正确的输入配置:
|
||
|
||
```cpp
|
||
InferInput input;
|
||
input.type = RKNN_TENSOR_UINT8; // 传递 UINT8,让 RKNN 自动量化
|
||
input.is_nhwc = true;
|
||
input.data = input_buf;
|
||
input.size = 640 * 640 * 3;
|
||
|
||
// rknn_input 结构体
|
||
rknn_input inputs[1];
|
||
inputs[0].index = 0;
|
||
inputs[0].type = RKNN_TENSOR_UINT8;
|
||
inputs[0].size = input.size;
|
||
inputs[0].fmt = RKNN_TENSOR_NHWC;
|
||
inputs[0].buf = input_buf;
|
||
inputs[0].pass_through = 0; // 关键:0 表示需要 RKNN 进行类型转换
|
||
```
|
||
|
||
**关键点**:
|
||
- `pass_through = 0`: 让 RKNN 自动将 UINT8 转换为模型需要的 INT8
|
||
- `pass_through = 1`: 直接传递数据,需要数据已经是 INT8 格式且维度匹配
|
||
|
||
## 验证方法
|
||
|
||
### 验证库版本
|
||
```bash
|
||
strings /usr/local/lib/librknnrt.so | grep "librknnrt version"
|
||
strings /usr/lib/librknnrt.so | grep "librknnrt version"
|
||
```
|
||
|
||
### 验证模型版本
|
||
```bash
|
||
strings model.rknn | grep "compiler version" | head -1
|
||
```
|
||
|
||
### 最小化 C++ 测试
|
||
```cpp
|
||
#include <rknn_api.h>
|
||
|
||
// 1. rknn_init()
|
||
// 2. rknn_query() 获取输入属性
|
||
// 3. rknn_inputs_set() 设置输入
|
||
// 4. rknn_run() 运行推理
|
||
// 5. rknn_outputs_get() 获取输出
|
||
```
|
||
|
||
## 经验总结
|
||
|
||
1. **版本一致性**: RKNN 运行时库版本必须与模型编译版本一致
|
||
2. **动态形状**: C API 对动态形状模型支持不完善,优先使用静态形状模型
|
||
3. **输入配置**: 量化模型的 `pass_through` 和 `type` 必须正确配置
|
||
4. **调试技巧**: 先用 Python (rknnlite) 验证模型可用,再移植到 C++
|
||
|
||
## 参考链接
|
||
|
||
- [RKNN API 文档](https://github.com/rockchip-linux/rknpu2/blob/master/doc/Rockchip_RKNPU_User_Guide_RKNN_API_V1.4.0_EN.pdf)
|
||
- [SCRFD 原始仓库](https://github.com/deepinsight/insightface/tree/master/detection/scrfd)
|
||
- [RKNN-Toolkit2 版本兼容性](https://github.com/airockchip/rknn-toolkit2)
|