Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,7 @@ option(MNN_COREML "Enable CoreML" OFF)
option(MNN_NNAPI "Enable NNAPI" OFF)
option(MNN_QNN "Enable QNN" OFF)
option(MNN_QNN_ONLINE_FINALIZE "Enable QNN Online Finalize" ON)
option(MNN_RKNN "Enable RKNN runtime backend" OFF)

option(MNN_GPU_TIME_PROFILE "Enable time profiling for the OpenCL backend and Vulkan backend." OFF)
option(MNN_GPU_PROFILE_SILENT "When GPU time profiling is enabled, only accumulate total time without printing per-kernel details." OFF)
Expand Down Expand Up @@ -680,6 +681,13 @@ IF(MNN_QNN)
list(APPEND MNN_OBJECTS_TO_LINK $<TARGET_OBJECTS:MNN_QNN>)
ENDIF()

# RKNN
IF(MNN_RKNN)
add_definitions(-DMNN_RKNN_ENABLED=1)
add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/source/backend/rknn/)
list(APPEND MNN_OBJECTS_TO_LINK $<TARGET_OBJECTS:MNN_RKNN>)
ENDIF()

# NEUROPILOT
IF(MNN_NEUROPILOT)
target_compile_options(MNNCore PRIVATE -DMNN_NEUROPILOT=1)
Expand Down
123 changes: 123 additions & 0 deletions docs/inference/npu.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
- CoreML
- NNAPI
- HIAI
- RKNN

## QNN

Expand Down Expand Up @@ -178,3 +179,125 @@ cp -r ${DDK}/include ${MNN}/source/backend/hiai/3rdParty/include
1. cmake 参数打开npu开关: -DMNN_NPU=ON
2. backend type设置成:MNN_FORWARD_USER_0
3. 执行可执行程序(需动态加载:libMNN_NPU.so, libhiai_ir_build.so, libhiai_ir.so, libhiai.so)

## RKNN
适用于 Rockchip RKNPU 平台。当前接入方式不是在线逐算子构图,而是同一份 ONNX 在 Host 侧同时生成:
- 包装后的 `.mnn`
- sidecar `.rknn`

其中 `.mnn` 内部保留 `Input + Plugin(type="RKNN")` 包装图,运行时由 MNN 的 CPU Plugin 框架调用 RKNN C API 执行 `.rknn`。

### RKNN 后端整体介绍

- Host 侧通过 `MNNConvert --rknn` 完成双产物生成,不走 `compilefornpu` 的 `MNN -> NPU` 逐算子编译链路。
- Device 侧通过 MNN 的 CPU Plugin 框架调用 RKNN C API 加载 `.rknn` 并执行;应用侧 Session backend 仍使用 `MNN_FORWARD_CPU`。
- RKNN backend 读取 runtime 库路径、转换脚本路径、目标平台等信息时,不做硬编码,全部从环境变量读取;缺失时直接报 `MNN_ERROR`。

更完整的 RKNN 说明、包内容、示例代码与板端运行方式,请参考:
- `source/backend/rknn/README.md`
- 包含 Host 转换、aarch64 交叉编译、Plugin 运行机制、独立示例代码、板端包内容与运行方式。

### 编译

#### Host,编译带 RKNN 转换能力的 MNNConvert

需要开启:
- `-DMNN_BUILD_CONVERTER=ON`
- `-DMNN_RKNN_CONVERT_MODE=ON`

示例:

```bash
cmake -S ${MNN_ROOT} -B ${BUILD_DIR} \
-DMNN_BUILD_CONVERTER=ON \
-DMNN_RKNN_CONVERT_MODE=ON

cmake --build ${BUILD_DIR} --target MNNConvert -j8
```

#### Device/Runtime,编译带 RKNN backend 的 MNN

需要开启:
- `-DMNN_RKNN=ON`
- `-DRKNN_API_INCLUDE_DIR=/path/to/rknn_api/include`

示例:

```bash
cmake -S ${MNN_ROOT} -B ${BUILD_DIR} \
-DMNN_RKNN=ON \
-DRKNN_API_INCLUDE_DIR=/path/to/rknn_api/include

cmake --build ${BUILD_DIR} --target MNN -j8
```

### Host,生成 RKNN 包装模型

调用 `MNNConvert --rknn` 前,必须设置以下环境变量:

- `MNN_RKNN_TARGET`
- 例如 `rv1126b`
- `MNN_RKNN_PYTHON`
- RKNN Toolkit 所在 Python 解释器
- `MNN_RKNN_SCRIPT`
- ONNX 转 `.rknn` 的脚本路径
- `MNN_RKNN_OUTPUT_DIR`
- `.rknn` 和 manifest 的输出目录

示例:

```bash
export MNN_RKNN_TARGET=rv1126b
export MNN_RKNN_PYTHON=/path/to/python
export MNN_RKNN_SCRIPT=/path/to/to_rknn.py
export MNN_RKNN_OUTPUT_DIR=/path/to/output/sidecar

${BUILD_DIR}/MNNConvert \
-f ONNX \
--modelFile model.onnx \
--MNNModel model.mnn \
--rknn
```

执行成功后会生成:
- `model.mnn`
- RKNN wrapper 模型
- `${MNN_RKNN_OUTPUT_DIR}/model_<target>.rknn`
- `${MNN_RKNN_OUTPUT_DIR}/model.rknn.bundle.json`

### Device,运行

运行时必须设置:
- `MNN_RKNN_RUNTIME_LIB`
- 指向目标板上的 `librknnrt.so`

并在创建 Session 时选择:
- backend type = `MNN_FORWARD_CPU`

**注意:在 RK 板上执行任何真正调用 NPU 的命令时,必须使用 `sudo`。**

如果 `.rknn` 路径在 wrapper `.mnn` 中是相对路径,则需要确保模型外部路径设置正确,使 MNN 能解析 sidecar 所在目录。

### Device,Profiling

RKNN internal profiling 通过 MNN 的公开 hint / info 接口暴露:

- 开启 profiling:
- `Interpreter::setSessionHint(Interpreter::RKNN_PROFILE, 1)`
- 或 `Executor::RuntimeManager::setHint(Interpreter::RKNN_PROFILE, 1)`
- 读取 profiling 文本:
- `Interpreter::getSessionInfo(session, Interpreter::BACKEND_PROFILE, &ptr)`
- 或 `Executor::RuntimeManager::getInfo(Interpreter::BACKEND_PROFILE, &ptr)`

其中:
- `RKNN_PROFILE` 会在 RKNN plugin 内部打开 `RKNN_FLAG_COLLECT_PERF_MASK`
- `BACKEND_PROFILE` 返回的是 `const char*`,内容包含 RKNN 导出的 `npu_run` 和 `perf_detail` 文本
- 因为它是普通文本,所以应用层可以直接打印,也可以原样写入文件做持久化
- 如果当前 backend 不支持 profiling,或者尚未产生 profile,返回值可能为空

### 当前限制

- 当前 RKNN 路径执行 `Plugin(type="RKNN")` 节点,不支持逐算子 RKNN backend。
- 当前实现走 host buffer copy 路径,尚未做 zero-copy。
- 当前输出路径按 `float32` 处理。
- 当前主目标是板端运行;PC 侧如果没有可用的 x86 `librknnrt.so`,则不能直接用 MNN runtime 在 Host 上模拟执行 RKNN backend。
11 changes: 10 additions & 1 deletion express/Executor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -283,11 +283,20 @@ bool Executor::RuntimeManager::getInfo(Interpreter::SessionInfoCode code, void*
auto dst = (int*)ptr;
if (!mInside->mRuntime.first.empty()) {
*dst = mInside->mRuntime.first.begin()->first;
return true;
}
} break;
case Interpreter::RESIZE_STATUS: {
auto dst = (int*)ptr;
*dst = mInside->mResizeStatus;
return true;
} break;
case Interpreter::BACKEND_PROFILE: {
for (auto& r : mInside->mRuntime.first) {
if (r.second != nullptr && r.second->onGetRuntimeInfo((int)code, ptr)) {
return true;
}
}
} break;
default: {
// Do nothing
Expand Down Expand Up @@ -694,4 +703,4 @@ void Executor::setLazyComputeMode(uint32_t mode) {
}

} // namespace Express
} // namespace MNN
} // namespace MNN
8 changes: 7 additions & 1 deletion include/MNN/Interpreter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,10 @@ class MNN_PUBLIC Interpreter {
CPU_SME2_NEON_DIVISION_RATIO = 17,

// Set SME cores, default is 2, if supports sme
CPU_SME_CORES = 18
CPU_SME_CORES = 18,

// Enable backend-side profiling export for runtimes that support it.
RKNN_PROFILE = 19
};

enum ExternalPathType {
Expand Down Expand Up @@ -463,6 +466,9 @@ class MNN_PUBLIC Interpreter {
/** Mode / NumberThread, int* */
THREAD_NUMBER = 4,

/** Backend-specific profile text, const char** */
BACKEND_PROFILE = 5,

ALL
};

Expand Down
19 changes: 19 additions & 0 deletions source/backend/rknn/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
file(GLOB BACKEND_SRCS ${CMAKE_CURRENT_LIST_DIR}/backend/*.cpp)
set(MNN_RKNN_SRCS ${BACKEND_SRCS})

set(_RKNN_API_INCLUDE "$ENV{RKNN_API_INCLUDE_DIR}")
if (DEFINED RKNN_API_INCLUDE_DIR AND NOT "${RKNN_API_INCLUDE_DIR}" STREQUAL "")
set(_RKNN_API_INCLUDE "${RKNN_API_INCLUDE_DIR}")
endif()

if ("${_RKNN_API_INCLUDE}" STREQUAL "")
message(FATAL_ERROR "MNN_RKNN=ON requires RKNN_API_INCLUDE_DIR (or env RKNN_API_INCLUDE_DIR) to point to the directory containing rknn_api.h")
endif()

if (NOT MNN_WITH_PLUGIN)
message(FATAL_ERROR "MNN_RKNN=ON requires MNN_WITH_PLUGIN=ON because RKNN is implemented as Plugin(RKNN) + CPU Plugin kernels")
endif()

add_library(MNN_RKNN OBJECT ${MNN_RKNN_SRCS})
target_include_directories(MNN_RKNN PRIVATE ${CMAKE_CURRENT_LIST_DIR}/backend/)
target_include_directories(MNN_RKNN PRIVATE ${_RKNN_API_INCLUDE})
Loading
Loading