MNN/docs/inference/npu.md

181 lines
8.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# NPU 及相应后端使用说明
目前 MNN 支持通过如下后端调用部分手机上的NPU能力
- QNN
- CoreML
- NNAPI
- HIAI
## QNN
### QNN后端整体介绍
- MNN通过调用QNN SDK的CPP API构建了MNN-QNN后端以期在能够使用高通NPU的设备上取得推理加速。
- 我们支持了两种运行模式:
- 在线构图模式在线编译和序列化QNN计算图。
- 支持静态形状的常规模型的推理。
- 离线构图模式则先借助MNN的离线工具缓存QNN计算图的序列化产物接着在运行时直接读取产物可以节省初始化时间。
- 支持静态形状/有限形状组合的常规模型的推理。
- 可支持部分llm模型的推理加速。
### 准备工作
#### 开发环境
- Host
- 在线构图模式:无要求。
- 离线构图模式一台x86_64Linux的机器链路中的部分QNN工具必须在此环境中运行
- Device
- 一台可以使用高通NPU的设备为便于陈述下文假设这是一台Android系统的设备。
#### 明确硬件架构
QNN后端的部分使用步骤如生成离线产物确定QNN的NPU库依赖等需要指定device的硬件架构对应的SOC ID以及HEXAGON ARCH。对于一些常见的硬件架构我们列举如下供你参考
| 硬件 | SOC ID | HEXAGON ARCH |
| :------ | :----- | :----------- |
| 8 Gen 1 | 36 | 69 |
| 8 Gen 2 | 43 | 73 |
| 8 Gen 3 | 57 | 75 |
| 8 Elite | 69 | 79 |
对于其他的硬件架构,你可以参考高通官网的设备支持列表。
#### 获得QNN依赖
MNN-QNN后端依赖QNN SDK中的`include/QNN`与`lib`,可通过以下步骤获取依赖:
- [注册高通账号](https://myaccount.qualcomm.com/signup)
- 访问Qualcomm AI Engine Direct SDK即QNN SDK下载SDK并解压。比如`/home/xiaying/third/qnn/qairt/2.38.0.250901`
- 修改`~/.bashrc` 增加SDK路径到环境变量, 然后运行 `source ~/.bashrc` 或者重启终端。eg
```
export QNN_SDK_ROOT=/home/xiaying/third/qnn/qairt/2.38.0.250901
export QNN_ROOT=/home/xiaying/third/qnn/qairt/2.38.0.250901
export HEXAGON_SDK_ROOT=/home/xiaying/third/qnn/qairt/2.38.0.250901
```
### 在线构图模式,推理常规模型
在线构图模式的使用步骤与其他后端基本一致,主要包含以下三部分。
#### Host交叉编译Device侧的MNN库及AI应用程序
- 参考[“主库编译”](../compile/engine.md#主库编译)配置Android系统的编译环境及CMake变量。
- 添加额外的CMake变量并编译`-DMNN_QNN=ON`、`-DMNN_QNN_CONVERT_MODE=OFF`、`-DMNN_WITH_PLUGIN=OFF`。
#### 推送资源至Device
参考下面的指令将以下资源推送到Device侧
- AI应用程序。
- 交叉编译得到的Device侧的MNN库。
- QNN库`libQnnHtp.so`、`libQnnHtpV${HEXAGON_ARCH}Stub.so`、`libQnnHtpV${HEXAGON_ARCH}Skel.so`、`libQnnHtpPrepare.so`)。
- MNN模型。
```
HEXAGON_ARCH="75" # modify this variable according to your environment
MNN_ROOT_PATH="/YOUR/MNN/ROOT/PATH" # modify this variable according to your environment
BUILD_ANDROID_PATH="/your/build/andorid/path" # modify this variable according to your environment
ANDROID_WORKING_DIR="/data/local/tmp" # modify this variable according to your environment
# push mnn libs
cd ${BUILD_ANDROID_PATH}
find . -name "*.so" | while read solib; do
adb push $solib ${ANDROID_WORKING_DIR}
done
cd -
# push your AI exe
adb push /your/AI/exe ${ANDROID_WORKING_DIR}
# push QNN libs
adb push ${QNN_SDK_ROOT}/lib/aarch64-android/libQnnHtp.so ${ANDROID_WORKING_DIR}
adb push ${QNN_SDK_ROOT}/lib/aarch64-android/libQnnHtpV${HEXAGON_ARCH}Stub.so ${ANDROID_WORKING_DIR}
adb push ${QNN_SDK_ROOT}/lib/hexagon-v${HEXAGON_ARCH}/unsigned/libQnnHtpV${HEXAGON_ARCH}Skel.so ${ANDROID_WORKING_DIR}
# The following lib is only needed in the online case.
adb push ${QNN_SDK_ROOT}/lib/aarch64-android/libQnnHtpPrepare.so ${ANDROID_WORKING_DIR}
# push MNN models
adb push model.mnn ${ANDROID_WORKING_DIR}
```
#### Device链接并运行
- 链接QNN库
- 为了动态链接到QNN HTP相关的库需要在环境变量`ADSP_LIBRARY_PATH`中添加QNN HTP库所在的目录部分机型上有效。如果这样也没法成功链接可将可执行文件QNN HTP库推送至同一目录cd到对应目录后再运行可执行文件参考如下指令。
```
adb shell "cd ${ANDROID_WORKING_DIR} && export LD_LIBRARY_PATH=.:${ANDROID_LD_LIBRARY_PATH} && export ADSP_LIBRARY_PATH=.:${ANDROID_ADSP_LIBRARY_PATH} && ./your/mnn/qnn/ai/exe"
```
- 配置MNN
- Backend Type设置为`MNN_FORWARD_NN`即5。
- 在使用Module API推理时需要设定`Module::Config`中的`shapeMutable`字段为`false`。
### 离线构图模式,推理常规模型
相较于在线构图模式离线构图模式额外包含一次编译构建生成离线产物需要的MNN库以及一个模型转换步骤将原始的MNN模型转化成QNN产物具体如下。
#### Host编译生成离线模式产物需要的的MNN库及相应MNN离线工具
- 添加额外的CMake变量并编译`-DMNN_QNN=ON`、`-DMNN_QNN_CONVERT_MODE=ON`、`-DMNN_WITH_PLUGIN=OFF`、`-DMNN_BUILD_TOOLS=ON`。
#### Host生成QNN离线构图产物
调用`MNN2QNNModel`工具针对Device的硬件架构生成QNN离线产物`model_${SOC_ID}_${HEXAGON_ARCH}.bin`)以及替代模型(`model_${SOC_ID}_${HEXAGON_ARCH}.mnn`),具体可参考[该工具的用法](../tools/convert.md#mnn2qnnmodel)。
#### Host交叉编译Device侧的MNN库及AI应用程序
- 参考[“主库编译”](../compile/engine.md#主库编译)配置Android系统的编译环境及CMake变量。
- 添加额外的CMake变量并编译`-DMNN_QNN=ON`、`-DMNN_QNN_CONVERT_MODE=OFF`、`-DMNN_WITH_PLUGIN=ON`。
#### 推送资源至Device
与[在线构图模式的情况](#推送资源至device)类似,但有以下两点不同:
- 依赖的QNN库变为`libQnnHtp.so`、`libQnnHtpV${HEXAGON_ARCH}Stub.so`、`libQnnHtpV${HEXAGON_ARCH}Skel.so`、`libQnnSystem.so`(不再依赖`libQnnHtpPrepare.so`,而是依赖`libQnnSystem.so`)。
- 不再使用原始的MNN模型而是需要QNN离线产物`model_${SOC_ID}_${HEXAGON_ARCH}.bin`)以及替代模型(`model_${SOC_ID}_${HEXAGON_ARCH}.mnn`)。
#### Device链接并运行
- 配置MNN
- 指定backend type为0CPU。读取并推理QNN离线产物的功能被封装在Plugin算子内该算子被注册在CPU后端因此此时需要指定backend type为CPU。
- 在Device侧如果你的离线产物和你的应用的工作目录不一致那么你需要在程序中通过`Executor::RuntimeManager::setExternalPath`接口设定离线产物所在的目录。
- 链接QNN库
- 离线构图模式对于链接的要求和在线构图模式一致。
## CoreML
适用于 Mac / iOS / iPad
### CoreML 后端编译
1. 编译 MNN 时打开编译宏 MNN_COREML -DMNN_COREML=ON
2. 编译App / 可执行程序时,增加链接 CoreML.framework
### CoreML 后端使用
backend type设置成MNN_FORWARD_NN
## NNAPI
适用于 Android 系统,高通/联发科芯片
### NNAPI 后端编译
打开编译宏 MNN_NNAPI 即可
```
cd ${MNN}
cd project/android
mkdir build && cd build
../build_64.sh -DMNN_USE_LOGCAT=ON -DMNN_NNAPI=ON
```
### NNAPI 后端使用
backend type设置成MNN_FORWARD_NN
## 华为 HIAI
适用于 Android 系统, Kirlin芯片
### HIAI 环境准备
1. 从如下链接下载 DDK
https://developer.huawei.com/consumer/cn/doc/hiai-Library/ddk-download-0000001053590180
2. 拷贝相对应的so和include文件到 hiai/3rdParty 目录下如果没有3rdParty目录新建一个
```
mkdir ${MNN}/source/backend/hiai/3rdParty
cp -r ${DDK}/lib ${MNN}/source/backend/hiai/3rdParty/armeabi-v7a
cp -r ${DDK}/lib64 ${MNN}/source/backend/hiai/3rdParty/arm64-v8a
cp -r ${DDK}/include ${MNN}/source/backend/hiai/3rdParty/include
```
### HIAI 编译执行
1. cmake 参数打开npu开关 -DMNN_NPU=true
2. backend type设置成MNN_FORWARD_USER_0
3. 执行可执行程序需动态加载libMNN_NPU.so, libhiai_ir_build.so, libhiai_ir.so, libhiai.so