1e41f4b71Sopenharmony_ci# Neural Network Runtime对接AI推理框架开发指导 2e41f4b71Sopenharmony_ci 3e41f4b71Sopenharmony_ci## 场景介绍 4e41f4b71Sopenharmony_ci 5e41f4b71Sopenharmony_ciNeural Network Runtime作为AI推理引擎和加速芯片的桥梁,为AI推理引擎提供精简的Native接口,满足推理引擎通过加速芯片执行端到端推理的需求。 6e41f4b71Sopenharmony_ci 7e41f4b71Sopenharmony_ci本文以图1展示的`Add`单算子模型为例,介绍Neural Network Runtime的开发流程。`Add`算子包含两个输入、一个参数和一个输出,其中的`activation`参数用于指定`Add`算子中激活函数的类型。 8e41f4b71Sopenharmony_ci 9e41f4b71Sopenharmony_ci**图1** Add单算子网络示意图 10e41f4b71Sopenharmony_ci 11e41f4b71Sopenharmony_ci 12e41f4b71Sopenharmony_ci## 环境准备 13e41f4b71Sopenharmony_ci 14e41f4b71Sopenharmony_ci### 环境要求 15e41f4b71Sopenharmony_ci 16e41f4b71Sopenharmony_ciNeural Network Runtime部件的环境要求如下: 17e41f4b71Sopenharmony_ci 18e41f4b71Sopenharmony_ci- 开发环境:Ubuntu 18.04及以上。 19e41f4b71Sopenharmony_ci- 接入设备:系统定义的标准设备,系统中内置AI硬件驱动并已接入Neural Network Runtime。 20e41f4b71Sopenharmony_ci 21e41f4b71Sopenharmony_ci由于Neural Network Runtime通过Native API对外开放,需要通过Native开发套件编译Neural Network Runtime应用。在社区的每日构建中下载对应系统版本的ohos-sdk压缩包,从压缩包中提取对应平台的Native开发套件。以Linux为例,Native开发套件的压缩包命名为`native-linux-{版本号}.zip`。 22e41f4b71Sopenharmony_ci 23e41f4b71Sopenharmony_ci### 环境搭建 24e41f4b71Sopenharmony_ci 25e41f4b71Sopenharmony_ci1. 打开Ubuntu编译服务器的终端。 26e41f4b71Sopenharmony_ci2. 把下载好的Native开发套件压缩包拷贝至当前用户根目录下。 27e41f4b71Sopenharmony_ci3. 执行以下命令解压Native开发套件的压缩包。 28e41f4b71Sopenharmony_ci ```shell 29e41f4b71Sopenharmony_ci unzip native-linux-{版本号}.zip 30e41f4b71Sopenharmony_ci ``` 31e41f4b71Sopenharmony_ci 32e41f4b71Sopenharmony_ci 解压缩后的内容如下(随版本迭代,目录下的内容可能发生变化,请以最新版本的Native API为准): 33e41f4b71Sopenharmony_ci ```text 34e41f4b71Sopenharmony_ci native/ 35e41f4b71Sopenharmony_ci ├── build // 交叉编译工具链 36e41f4b71Sopenharmony_ci ├── build-tools // 编译构建工具 37e41f4b71Sopenharmony_ci ├── docs 38e41f4b71Sopenharmony_ci ├── llvm 39e41f4b71Sopenharmony_ci ├── nativeapi_syscap_config.json 40e41f4b71Sopenharmony_ci ├── ndk_system_capability.json 41e41f4b71Sopenharmony_ci ├── NOTICE.txt 42e41f4b71Sopenharmony_ci ├── oh-uni-package.json 43e41f4b71Sopenharmony_ci └── sysroot // Native API头文件和库 44e41f4b71Sopenharmony_ci ``` 45e41f4b71Sopenharmony_ci## 接口说明 46e41f4b71Sopenharmony_ci 47e41f4b71Sopenharmony_ci这里给出Neural Network Runtime开发流程中通用的接口,具体请见下列表格。 48e41f4b71Sopenharmony_ci 49e41f4b71Sopenharmony_ci### 结构体 50e41f4b71Sopenharmony_ci 51e41f4b71Sopenharmony_ci| 结构体名称 | 描述 | 52e41f4b71Sopenharmony_ci| --------- | ---- | 53e41f4b71Sopenharmony_ci| typedef struct OH_NNModel OH_NNModel | Neural Network Runtime的模型句柄,用于构造模型。 | 54e41f4b71Sopenharmony_ci| typedef struct OH_NNCompilation OH_NNCompilation | Neural Network Runtime的编译器句柄,用于编译AI模型。 | 55e41f4b71Sopenharmony_ci| typedef struct OH_NNExecutor OH_NNExecutor | Neural Network Runtime的执行器句柄,用于在指定设备上执行推理计算。 | 56e41f4b71Sopenharmony_ci| typedef struct NN_QuantParam NN_QuantParam | Neural Network Runtime的量化参数句柄,用于在构造模型时指定张量的量化参数。 | 57e41f4b71Sopenharmony_ci| typedef struct NN_TensorDesc NN_TensorDesc | Neural Network Runtime的张量描述句柄,用于描述张量的各类属性,例如数据布局、数据类型、形状等。 | 58e41f4b71Sopenharmony_ci| typedef struct NN_Tensor NN_Tensor | Neural Network Runtime的张量句柄,用于设置执行器的推理输入和输出张量。 | 59e41f4b71Sopenharmony_ci 60e41f4b71Sopenharmony_ci### 模型构造接口 61e41f4b71Sopenharmony_ci 62e41f4b71Sopenharmony_ci| 接口名称 | 描述 | 63e41f4b71Sopenharmony_ci| ------- | --- | 64e41f4b71Sopenharmony_ci| OH_NNModel_Construct() | 创建OH_NNModel类型的模型实例。 | 65e41f4b71Sopenharmony_ci| OH_NN_ReturnCode OH_NNModel_AddTensorToModel(OH_NNModel *model, const NN_TensorDesc *tensorDesc) | 向模型实例中添加张量。 | 66e41f4b71Sopenharmony_ci| OH_NN_ReturnCode OH_NNModel_SetTensorData(OH_NNModel *model, uint32_t index, const void *dataBuffer, size_t length) | 设置张量的数值。 | 67e41f4b71Sopenharmony_ci| OH_NN_ReturnCode OH_NNModel_AddOperation(OH_NNModel *model, OH_NN_OperationType op, const OH_NN_UInt32Array *paramIndices, const OH_NN_UInt32Array *inputIndices, const OH_NN_UInt32Array *outputIndices) | 向模型实例中添加算子。 | 68e41f4b71Sopenharmony_ci| OH_NN_ReturnCode OH_NNModel_SpecifyInputsAndOutputs(OH_NNModel *model, const OH_NN_UInt32Array *inputIndices, const OH_NN_UInt32Array *outputIndices) | 指定模型的输入和输出张量的索引值。 | 69e41f4b71Sopenharmony_ci| OH_NN_ReturnCode OH_NNModel_Finish(OH_NNModel *model) | 完成模型构图。| 70e41f4b71Sopenharmony_ci| void OH_NNModel_Destroy(OH_NNModel **model) | 销毁模型实例。 | 71e41f4b71Sopenharmony_ci 72e41f4b71Sopenharmony_ci 73e41f4b71Sopenharmony_ci### 模型编译接口 74e41f4b71Sopenharmony_ci 75e41f4b71Sopenharmony_ci| 接口名称 | 描述 | 76e41f4b71Sopenharmony_ci| ------- | --- | 77e41f4b71Sopenharmony_ci| OH_NNCompilation *OH_NNCompilation_Construct(const OH_NNModel *model) | 基于模型实例创建OH_NNCompilation类型的编译实例。 | 78e41f4b71Sopenharmony_ci| OH_NNCompilation *OH_NNCompilation_ConstructWithOfflineModelFile(const char *modelPath) | 基于离线模型文件路径创建OH_NNCompilation类型的编译实例。 | 79e41f4b71Sopenharmony_ci| OH_NNCompilation *OH_NNCompilation_ConstructWithOfflineModelBuffer(const void *modelBuffer, size_t modelSize) | 基于离线模型文件内存创建OH_NNCompilation类型的编译实例。 | 80e41f4b71Sopenharmony_ci| OH_NNCompilation *OH_NNCompilation_ConstructForCache() | 创建一个空的编译实例,以便稍后从模型缓存中恢复。 | 81e41f4b71Sopenharmony_ci| OH_NN_ReturnCode OH_NNCompilation_ExportCacheToBuffer(OH_NNCompilation *compilation, const void *buffer, size_t length, size_t *modelSize) | 将模型缓存写入到指定内存区域。 | 82e41f4b71Sopenharmony_ci| OH_NN_ReturnCode OH_NNCompilation_ImportCacheFromBuffer(OH_NNCompilation *compilation, const void *buffer, size_t modelSize) | 从指定内存区域读取模型缓存。 | 83e41f4b71Sopenharmony_ci| OH_NN_ReturnCode OH_NNCompilation_AddExtensionConfig(OH_NNCompilation *compilation, const char *configName, const void *configValue, const size_t configValueSize) | 为自定义硬件属性添加扩展配置,具体硬件的扩展属性名称和属性值需要从硬件厂商的文档中获取。 | 84e41f4b71Sopenharmony_ci| OH_NN_ReturnCode OH_NNCompilation_SetDevice(OH_NNCompilation *compilation, size_t deviceID) | 指定模型编译和计算的硬件,可通过设备管理接口获取。 | 85e41f4b71Sopenharmony_ci| OH_NN_ReturnCode OH_NNCompilation_SetCache(OH_NNCompilation *compilation, const char *cachePath, uint32_t version) | 设置编译模型的缓存目录和版本。 | 86e41f4b71Sopenharmony_ci| OH_NN_ReturnCode OH_NNCompilation_SetPerformanceMode(OH_NNCompilation *compilation, OH_NN_PerformanceMode performanceMode) | 设置模型计算的性能模式。 | 87e41f4b71Sopenharmony_ci| OH_NN_ReturnCode OH_NNCompilation_SetPriority(OH_NNCompilation *compilation, OH_NN_Priority priority) | 设置模型计算的优先级。 | 88e41f4b71Sopenharmony_ci| OH_NN_ReturnCode OH_NNCompilation_EnableFloat16(OH_NNCompilation *compilation, bool enableFloat16) | 是否以float16的浮点数精度计算。 | 89e41f4b71Sopenharmony_ci| OH_NN_ReturnCode OH_NNCompilation_Build(OH_NNCompilation *compilation) | 执行模型编译。 | 90e41f4b71Sopenharmony_ci| void OH_NNCompilation_Destroy(OH_NNCompilation **compilation) | 销毁编译实例。 | 91e41f4b71Sopenharmony_ci 92e41f4b71Sopenharmony_ci### 张量描述接口 93e41f4b71Sopenharmony_ci 94e41f4b71Sopenharmony_ci| 接口名称 | 描述 | 95e41f4b71Sopenharmony_ci| ------- | --- | 96e41f4b71Sopenharmony_ci| NN_TensorDesc *OH_NNTensorDesc_Create() | 创建一个张量描述实例,用于后续创建张量。 | 97e41f4b71Sopenharmony_ci| OH_NN_ReturnCode OH_NNTensorDesc_SetName(NN_TensorDesc *tensorDesc, const char *name) | 设置张量描述的名称。 | 98e41f4b71Sopenharmony_ci| OH_NN_ReturnCode OH_NNTensorDesc_GetName(const NN_TensorDesc *tensorDesc, const char **name) | 获取张量描述的名称。 | 99e41f4b71Sopenharmony_ci| OH_NN_ReturnCode OH_NNTensorDesc_SetDataType(NN_TensorDesc *tensorDesc, OH_NN_DataType dataType) | 设置张量描述的数据类型。 | 100e41f4b71Sopenharmony_ci| OH_NN_ReturnCode OH_NNTensorDesc_GetDataType(const NN_TensorDesc *tensorDesc, OH_NN_DataType *dataType) | 获取张量描述的数据类型。 | 101e41f4b71Sopenharmony_ci| OH_NN_ReturnCode OH_NNTensorDesc_SetShape(NN_TensorDesc *tensorDesc, const int32_t *shape, size_t shapeLength) | 设置张量描述的形状。 | 102e41f4b71Sopenharmony_ci| OH_NN_ReturnCode OH_NNTensorDesc_GetShape(const NN_TensorDesc *tensorDesc, int32_t **shape, size_t *shapeLength) | 获取张量描述的形状。 | 103e41f4b71Sopenharmony_ci| OH_NN_ReturnCode OH_NNTensorDesc_SetFormat(NN_TensorDesc *tensorDesc, OH_NN_Format format) | 设置张量描述的数据布局。 | 104e41f4b71Sopenharmony_ci| OH_NN_ReturnCode OH_NNTensorDesc_GetFormat(const NN_TensorDesc *tensorDesc, OH_NN_Format *format) | 获取张量描述的数据布局。 | 105e41f4b71Sopenharmony_ci| OH_NN_ReturnCode OH_NNTensorDesc_GetElementCount(const NN_TensorDesc *tensorDesc, size_t *elementCount) | 获取张量描述的元素个数。 | 106e41f4b71Sopenharmony_ci| OH_NN_ReturnCode OH_NNTensorDesc_GetByteSize(const NN_TensorDesc *tensorDesc, size_t *byteSize) | 获取基于张量描述的形状和数据类型计算的数据占用字节数。 | 107e41f4b71Sopenharmony_ci| OH_NN_ReturnCode OH_NNTensorDesc_Destroy(NN_TensorDesc **tensorDesc) | 销毁张量描述实例。 | 108e41f4b71Sopenharmony_ci 109e41f4b71Sopenharmony_ci### 张量接口 110e41f4b71Sopenharmony_ci 111e41f4b71Sopenharmony_ci| 接口名称 | 描述 | 112e41f4b71Sopenharmony_ci| ------- | --- | 113e41f4b71Sopenharmony_ci| NN_Tensor* OH_NNTensor_Create(size_t deviceID, NN_TensorDesc *tensorDesc) | 从张量描述创建张量实例,会申请设备共享内存。 | 114e41f4b71Sopenharmony_ci| NN_Tensor* OH_NNTensor_CreateWithSize(size_t deviceID, NN_TensorDesc *tensorDesc, size_t size) | 按照指定内存大小和张量描述创建张量实例,会申请设备共享内存。 | 115e41f4b71Sopenharmony_ci| NN_Tensor* OH_NNTensor_CreateWithFd(size_t deviceID, NN_TensorDesc *tensorDesc, int fd, size_t size, size_t offset) | 按照指定共享内存的文件描述符和张量描述创建张量实例,从而可以复用其他张量的设备共享内存。 | 116e41f4b71Sopenharmony_ci| NN_TensorDesc* OH_NNTensor_GetTensorDesc(const NN_Tensor *tensor) | 获取张量内部的张量描述实例指针,从而可读取张量的属性,例如数据类型、形状等。 | 117e41f4b71Sopenharmony_ci| void* OH_NNTensor_GetDataBuffer(const NN_Tensor *tensor) | 获取张量数据的内存地址,可以读写张量数据。 | 118e41f4b71Sopenharmony_ci| OH_NN_ReturnCode OH_NNTensor_GetFd(const NN_Tensor *tensor, int *fd) | 获取张量数据所在共享内存的文件描述符,文件描述符fd对应了一块设备共享内存。 | 119e41f4b71Sopenharmony_ci| OH_NN_ReturnCode OH_NNTensor_GetSize(const NN_Tensor *tensor, size_t *size) | 获取张量数据所在共享内存的大小。 | 120e41f4b71Sopenharmony_ci| OH_NN_ReturnCode OH_NNTensor_GetOffset(const NN_Tensor *tensor, size_t *offset) | 获取张量数据所在共享内存上的偏移量,张量数据可使用的大小为所在共享内存的大小减去偏移量。 | 121e41f4b71Sopenharmony_ci| OH_NN_ReturnCode OH_NNTensor_Destroy(NN_Tensor **tensor) | 销毁张量实例。 | 122e41f4b71Sopenharmony_ci 123e41f4b71Sopenharmony_ci### 执行推理接口 124e41f4b71Sopenharmony_ci 125e41f4b71Sopenharmony_ci| 接口名称 | 描述 | 126e41f4b71Sopenharmony_ci| ------- | --- | 127e41f4b71Sopenharmony_ci| OH_NNExecutor *OH_NNExecutor_Construct(OH_NNCompilation *compilation) | 创建OH_NNExecutor类型的执行器实例。 | 128e41f4b71Sopenharmony_ci| OH_NN_ReturnCode OH_NNExecutor_GetOutputShape(OH_NNExecutor *executor, uint32_t outputIndex, int32_t **shape, uint32_t *shapeLength) | 获取输出张量的维度信息,用于输出张量具有动态形状的情况。 | 129e41f4b71Sopenharmony_ci| OH_NN_ReturnCode OH_NNExecutor_GetInputCount(const OH_NNExecutor *executor, size_t *inputCount) | 获取输入张量的数量。 | 130e41f4b71Sopenharmony_ci| OH_NN_ReturnCode OH_NNExecutor_GetOutputCount(const OH_NNExecutor *executor, size_t *outputCount) | 获取输出张量的数量。 | 131e41f4b71Sopenharmony_ci| NN_TensorDesc* OH_NNExecutor_CreateInputTensorDesc(const OH_NNExecutor *executor, size_t index) | 由指定索引值创建一个输入张量的描述,用于读取张量的属性或创建张量实例。 | 132e41f4b71Sopenharmony_ci| NN_TensorDesc* OH_NNExecutor_CreateOutputTensorDesc(const OH_NNExecutor *executor, size_t index) | 由指定索引值创建一个输出张量的描述,用于读取张量的属性或创建张量实例。 | 133e41f4b71Sopenharmony_ci| OH_NN_ReturnCode OH_NNExecutor_GetInputDimRange(const OH_NNExecutor *executor, size_t index, size_t **minInputDims, size_t **maxInputDims, size_t *shapeLength) |获取所有输入张量的维度范围。当输入张量具有动态形状时,不同设备可能支持不同的维度范围。 | 134e41f4b71Sopenharmony_ci| OH_NN_ReturnCode OH_NNExecutor_SetOnRunDone(OH_NNExecutor *executor, NN_OnRunDone onRunDone) | 设置异步推理结束后的回调处理函数,回调函数定义详见接口文档。 | 135e41f4b71Sopenharmony_ci| OH_NN_ReturnCode OH_NNExecutor_SetOnServiceDied(OH_NNExecutor *executor, NN_OnServiceDied onServiceDied) | 设置异步推理执行期间设备驱动服务突然死亡时的回调处理函数,回调函数定义详见接口文档。 | 136e41f4b71Sopenharmony_ci| OH_NN_ReturnCode OH_NNExecutor_RunSync(OH_NNExecutor *executor, NN_Tensor *inputTensor[], size_t inputCount, NN_Tensor *outputTensor[], size_t outputCount) | 执行同步推理。 | 137e41f4b71Sopenharmony_ci| OH_NN_ReturnCode OH_NNExecutor_RunAsync(OH_NNExecutor *executor, NN_Tensor *inputTensor[], size_t inputCount, NN_Tensor *outputTensor[], size_t outputCount, int32_t timeout, void *userData) | 执行异步推理。 | 138e41f4b71Sopenharmony_ci| void OH_NNExecutor_Destroy(OH_NNExecutor **executor) | 销毁执行器实例。 | 139e41f4b71Sopenharmony_ci 140e41f4b71Sopenharmony_ci### 设备管理接口 141e41f4b71Sopenharmony_ci 142e41f4b71Sopenharmony_ci| 接口名称 | 描述 | 143e41f4b71Sopenharmony_ci| ------- | --- | 144e41f4b71Sopenharmony_ci| OH_NN_ReturnCode OH_NNDevice_GetAllDevicesID(const size_t **allDevicesID, uint32_t *deviceCount) | 获取对接到Neural Network Runtime的所有硬件ID。 | 145e41f4b71Sopenharmony_ci| OH_NN_ReturnCode OH_NNDevice_GetName(size_t deviceID, const char **name) | 获取指定硬件的名称。 | 146e41f4b71Sopenharmony_ci| OH_NN_ReturnCode OH_NNDevice_GetType(size_t deviceID, OH_NN_DeviceType *deviceType) | 获取指定硬件的类别信息。 | 147e41f4b71Sopenharmony_ci 148e41f4b71Sopenharmony_ci 149e41f4b71Sopenharmony_ci## 开发步骤 150e41f4b71Sopenharmony_ci 151e41f4b71Sopenharmony_ciNeural Network Runtime的开发流程主要包含**模型构造**、**模型编译**和**推理执行**三个阶段。以下开发步骤以`Add`单算子模型为例,介绍调用Neural Network Runtime接口,开发应用的过程。 152e41f4b71Sopenharmony_ci 153e41f4b71Sopenharmony_ci1. 创建应用样例文件。 154e41f4b71Sopenharmony_ci 155e41f4b71Sopenharmony_ci 首先,创建Neural Network Runtime应用样例的源文件。在项目目录下执行以下命令,创建`nnrt_example/`目录,并在目录下创建 `nnrt_example.cpp` 源文件。 156e41f4b71Sopenharmony_ci 157e41f4b71Sopenharmony_ci ```shell 158e41f4b71Sopenharmony_ci mkdir ~/nnrt_example && cd ~/nnrt_example 159e41f4b71Sopenharmony_ci touch nnrt_example.cpp 160e41f4b71Sopenharmony_ci ``` 161e41f4b71Sopenharmony_ci 162e41f4b71Sopenharmony_ci2. 导入Neural Network Runtime。 163e41f4b71Sopenharmony_ci 164e41f4b71Sopenharmony_ci 在 `nnrt_example.cpp` 文件的开头添加以下代码,引入Neural Network Runtime。 165e41f4b71Sopenharmony_ci 166e41f4b71Sopenharmony_ci ```cpp 167e41f4b71Sopenharmony_ci #include <iostream> 168e41f4b71Sopenharmony_ci #include <cstdarg> 169e41f4b71Sopenharmony_ci #include "neural_network_runtime/neural_network_runtime.h" 170e41f4b71Sopenharmony_ci ``` 171e41f4b71Sopenharmony_ci 172e41f4b71Sopenharmony_ci3. 定义日志打印、设置输入数据、数据打印等辅助函数。 173e41f4b71Sopenharmony_ci 174e41f4b71Sopenharmony_ci ```cpp 175e41f4b71Sopenharmony_ci // 返回值检查宏 176e41f4b71Sopenharmony_ci #define CHECKNEQ(realRet, expectRet, retValue, ...) \ 177e41f4b71Sopenharmony_ci do { \ 178e41f4b71Sopenharmony_ci if ((realRet) != (expectRet)) { \ 179e41f4b71Sopenharmony_ci printf(__VA_ARGS__); \ 180e41f4b71Sopenharmony_ci return (retValue); \ 181e41f4b71Sopenharmony_ci } \ 182e41f4b71Sopenharmony_ci } while (0) 183e41f4b71Sopenharmony_ci 184e41f4b71Sopenharmony_ci #define CHECKEQ(realRet, expectRet, retValue, ...) \ 185e41f4b71Sopenharmony_ci do { \ 186e41f4b71Sopenharmony_ci if ((realRet) == (expectRet)) { \ 187e41f4b71Sopenharmony_ci printf(__VA_ARGS__); \ 188e41f4b71Sopenharmony_ci return (retValue); \ 189e41f4b71Sopenharmony_ci } \ 190e41f4b71Sopenharmony_ci } while (0) 191e41f4b71Sopenharmony_ci 192e41f4b71Sopenharmony_ci // 设置输入数据用于推理 193e41f4b71Sopenharmony_ci OH_NN_ReturnCode SetInputData(NN_Tensor* inputTensor[], size_t inputSize) 194e41f4b71Sopenharmony_ci { 195e41f4b71Sopenharmony_ci OH_NN_DataType dataType(OH_NN_FLOAT32); 196e41f4b71Sopenharmony_ci OH_NN_ReturnCode ret{OH_NN_FAILED}; 197e41f4b71Sopenharmony_ci size_t elementCount = 0; 198e41f4b71Sopenharmony_ci for (size_t i = 0; i < inputSize; ++i) { 199e41f4b71Sopenharmony_ci // 获取张量的数据内存 200e41f4b71Sopenharmony_ci auto data = OH_NNTensor_GetDataBuffer(inputTensor[i]); 201e41f4b71Sopenharmony_ci CHECKEQ(data, nullptr, OH_NN_FAILED, "Failed to get data buffer."); 202e41f4b71Sopenharmony_ci // 获取张量的描述 203e41f4b71Sopenharmony_ci auto desc = OH_NNTensor_GetTensorDesc(inputTensor[i]); 204e41f4b71Sopenharmony_ci CHECKEQ(desc, nullptr, OH_NN_FAILED, "Failed to get desc."); 205e41f4b71Sopenharmony_ci // 获取张量的数据类型 206e41f4b71Sopenharmony_ci ret = OH_NNTensorDesc_GetDataType(desc, &dataType); 207e41f4b71Sopenharmony_ci CHECKNEQ(ret, OH_NN_SUCCESS, OH_NN_FAILED, "Failed to get data type."); 208e41f4b71Sopenharmony_ci // 获取张量的元素个数 209e41f4b71Sopenharmony_ci ret = OH_NNTensorDesc_GetElementCount(desc, &elementCount); 210e41f4b71Sopenharmony_ci CHECKNEQ(ret, OH_NN_SUCCESS, OH_NN_FAILED, "Failed to get element count."); 211e41f4b71Sopenharmony_ci switch(dataType) { 212e41f4b71Sopenharmony_ci case OH_NN_FLOAT32: { 213e41f4b71Sopenharmony_ci float* floatValue = reinterpret_cast<float*>(data); 214e41f4b71Sopenharmony_ci for (size_t j = 0; j < elementCount; ++j) { 215e41f4b71Sopenharmony_ci floatValue[j] = static_cast<float>(j); 216e41f4b71Sopenharmony_ci } 217e41f4b71Sopenharmony_ci break; 218e41f4b71Sopenharmony_ci } 219e41f4b71Sopenharmony_ci case OH_NN_INT32: { 220e41f4b71Sopenharmony_ci int* intValue = reinterpret_cast<int*>(data); 221e41f4b71Sopenharmony_ci for (size_t j = 0; j < elementCount; ++j) { 222e41f4b71Sopenharmony_ci intValue[j] = static_cast<int>(j); 223e41f4b71Sopenharmony_ci } 224e41f4b71Sopenharmony_ci break; 225e41f4b71Sopenharmony_ci } 226e41f4b71Sopenharmony_ci default: 227e41f4b71Sopenharmony_ci return OH_NN_FAILED; 228e41f4b71Sopenharmony_ci } 229e41f4b71Sopenharmony_ci } 230e41f4b71Sopenharmony_ci return OH_NN_SUCCESS; 231e41f4b71Sopenharmony_ci } 232e41f4b71Sopenharmony_ci 233e41f4b71Sopenharmony_ci OH_NN_ReturnCode Print(NN_Tensor* outputTensor[], size_t outputSize) 234e41f4b71Sopenharmony_ci { 235e41f4b71Sopenharmony_ci OH_NN_DataType dataType(OH_NN_FLOAT32); 236e41f4b71Sopenharmony_ci OH_NN_ReturnCode ret{OH_NN_FAILED}; 237e41f4b71Sopenharmony_ci size_t elementCount = 0; 238e41f4b71Sopenharmony_ci for (size_t i = 0; i < outputSize; ++i) { 239e41f4b71Sopenharmony_ci auto data = OH_NNTensor_GetDataBuffer(outputTensor[i]); 240e41f4b71Sopenharmony_ci CHECKEQ(data, nullptr, OH_NN_FAILED, "Failed to get data buffer."); 241e41f4b71Sopenharmony_ci auto desc = OH_NNTensor_GetTensorDesc(outputTensor[i]); 242e41f4b71Sopenharmony_ci CHECKEQ(desc, nullptr, OH_NN_FAILED, "Failed to get desc."); 243e41f4b71Sopenharmony_ci ret = OH_NNTensorDesc_GetDataType(desc, &dataType); 244e41f4b71Sopenharmony_ci CHECKNEQ(ret, OH_NN_SUCCESS, OH_NN_FAILED, "Failed to get data type."); 245e41f4b71Sopenharmony_ci ret = OH_NNTensorDesc_GetElementCount(desc, &elementCount); 246e41f4b71Sopenharmony_ci CHECKNEQ(ret, OH_NN_SUCCESS, OH_NN_FAILED, "Failed to get element count."); 247e41f4b71Sopenharmony_ci switch(dataType) { 248e41f4b71Sopenharmony_ci case OH_NN_FLOAT32: { 249e41f4b71Sopenharmony_ci float* floatValue = reinterpret_cast<float*>(data); 250e41f4b71Sopenharmony_ci for (size_t j = 0; j < elementCount; ++j) { 251e41f4b71Sopenharmony_ci std::cout << "Output index: " << j << ", value is: " << floatValue[j] << "." << std::endl; 252e41f4b71Sopenharmony_ci } 253e41f4b71Sopenharmony_ci break; 254e41f4b71Sopenharmony_ci } 255e41f4b71Sopenharmony_ci case OH_NN_INT32: { 256e41f4b71Sopenharmony_ci int* intValue = reinterpret_cast<int*>(data); 257e41f4b71Sopenharmony_ci for (size_t j = 0; j < elementCount; ++j) { 258e41f4b71Sopenharmony_ci std::cout << "Output index: " << j << ", value is: " << intValue[j] << "." << std::endl; 259e41f4b71Sopenharmony_ci } 260e41f4b71Sopenharmony_ci break; 261e41f4b71Sopenharmony_ci } 262e41f4b71Sopenharmony_ci default: 263e41f4b71Sopenharmony_ci return OH_NN_FAILED; 264e41f4b71Sopenharmony_ci } 265e41f4b71Sopenharmony_ci } 266e41f4b71Sopenharmony_ci 267e41f4b71Sopenharmony_ci return OH_NN_SUCCESS; 268e41f4b71Sopenharmony_ci } 269e41f4b71Sopenharmony_ci ``` 270e41f4b71Sopenharmony_ci 271e41f4b71Sopenharmony_ci4. 构造模型。 272e41f4b71Sopenharmony_ci 273e41f4b71Sopenharmony_ci 使用Neural Network Runtime的模型构造接口,构造`Add`单算子样例模型。 274e41f4b71Sopenharmony_ci 275e41f4b71Sopenharmony_ci ```cpp 276e41f4b71Sopenharmony_ci OH_NN_ReturnCode BuildModel(OH_NNModel** pmodel) 277e41f4b71Sopenharmony_ci { 278e41f4b71Sopenharmony_ci // 创建模型实例model,进行模型构造 279e41f4b71Sopenharmony_ci OH_NNModel* model = OH_NNModel_Construct(); 280e41f4b71Sopenharmony_ci CHECKEQ(model, nullptr, OH_NN_FAILED, "Create model failed."); 281e41f4b71Sopenharmony_ci 282e41f4b71Sopenharmony_ci // 添加Add算子的第一个输入张量,类型为float32,张量形状为[1, 2, 2, 3] 283e41f4b71Sopenharmony_ci NN_TensorDesc* tensorDesc = OH_NNTensorDesc_Create(); 284e41f4b71Sopenharmony_ci CHECKEQ(tensorDesc, nullptr, OH_NN_FAILED, "Create TensorDesc failed."); 285e41f4b71Sopenharmony_ci 286e41f4b71Sopenharmony_ci int32_t inputDims[4] = {1, 2, 2, 3}; 287e41f4b71Sopenharmony_ci auto returnCode = OH_NNTensorDesc_SetShape(tensorDesc, inputDims, 4); 288e41f4b71Sopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, OH_NN_FAILED, "Set TensorDesc shape failed."); 289e41f4b71Sopenharmony_ci 290e41f4b71Sopenharmony_ci returnCode = OH_NNTensorDesc_SetDataType(tensorDesc, OH_NN_FLOAT32); 291e41f4b71Sopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, OH_NN_FAILED, "Set TensorDesc data type failed."); 292e41f4b71Sopenharmony_ci 293e41f4b71Sopenharmony_ci returnCode = OH_NNTensorDesc_SetFormat(tensorDesc, OH_NN_FORMAT_NONE); 294e41f4b71Sopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, OH_NN_FAILED, "Set TensorDesc format failed."); 295e41f4b71Sopenharmony_ci 296e41f4b71Sopenharmony_ci returnCode = OH_NNModel_AddTensorToModel(model, tensorDesc); 297e41f4b71Sopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, OH_NN_FAILED, "Add first TensorDesc to model failed."); 298e41f4b71Sopenharmony_ci 299e41f4b71Sopenharmony_ci returnCode = OH_NNModel_SetTensorType(model, 0, OH_NN_TENSOR); 300e41f4b71Sopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, OH_NN_FAILED, "Set model tensor type failed."); 301e41f4b71Sopenharmony_ci 302e41f4b71Sopenharmony_ci // 添加Add算子的第二个输入张量,类型为float32,张量形状为[1, 2, 2, 3] 303e41f4b71Sopenharmony_ci tensorDesc = OH_NNTensorDesc_Create(); 304e41f4b71Sopenharmony_ci CHECKEQ(tensorDesc, nullptr, OH_NN_FAILED, "Create TensorDesc failed."); 305e41f4b71Sopenharmony_ci 306e41f4b71Sopenharmony_ci returnCode = OH_NNTensorDesc_SetShape(tensorDesc, inputDims, 4); 307e41f4b71Sopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, OH_NN_FAILED, "Set TensorDesc shape failed."); 308e41f4b71Sopenharmony_ci 309e41f4b71Sopenharmony_ci returnCode = OH_NNTensorDesc_SetDataType(tensorDesc, OH_NN_FLOAT32); 310e41f4b71Sopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, OH_NN_FAILED, "Set TensorDesc data type failed."); 311e41f4b71Sopenharmony_ci 312e41f4b71Sopenharmony_ci returnCode = OH_NNTensorDesc_SetFormat(tensorDesc, OH_NN_FORMAT_NONE); 313e41f4b71Sopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, OH_NN_FAILED, "Set TensorDesc format failed."); 314e41f4b71Sopenharmony_ci 315e41f4b71Sopenharmony_ci returnCode = OH_NNModel_AddTensorToModel(model, tensorDesc); 316e41f4b71Sopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, OH_NN_FAILED, "Add second TensorDesc to model failed."); 317e41f4b71Sopenharmony_ci 318e41f4b71Sopenharmony_ci returnCode = OH_NNModel_SetTensorType(model, 1, OH_NN_TENSOR); 319e41f4b71Sopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, OH_NN_FAILED, "Set model tensor type failed."); 320e41f4b71Sopenharmony_ci 321e41f4b71Sopenharmony_ci // 添加Add算子的参数张量,该参数张量用于指定激活函数的类型,张量的数据类型为int8。 322e41f4b71Sopenharmony_ci tensorDesc = OH_NNTensorDesc_Create(); 323e41f4b71Sopenharmony_ci CHECKEQ(tensorDesc, nullptr, OH_NN_FAILED, "Create TensorDesc failed."); 324e41f4b71Sopenharmony_ci 325e41f4b71Sopenharmony_ci int32_t activationDims = 1; 326e41f4b71Sopenharmony_ci returnCode = OH_NNTensorDesc_SetShape(tensorDesc, &activationDims, 1); 327e41f4b71Sopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, OH_NN_FAILED, "Set TensorDesc shape failed."); 328e41f4b71Sopenharmony_ci 329e41f4b71Sopenharmony_ci returnCode = OH_NNTensorDesc_SetDataType(tensorDesc, OH_NN_INT8); 330e41f4b71Sopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, OH_NN_FAILED, "Set TensorDesc data type failed."); 331e41f4b71Sopenharmony_ci 332e41f4b71Sopenharmony_ci returnCode = OH_NNTensorDesc_SetFormat(tensorDesc, OH_NN_FORMAT_NONE); 333e41f4b71Sopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, OH_NN_FAILED, "Set TensorDesc format failed."); 334e41f4b71Sopenharmony_ci 335e41f4b71Sopenharmony_ci returnCode = OH_NNModel_AddTensorToModel(model, tensorDesc); 336e41f4b71Sopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, OH_NN_FAILED, "Add second TensorDesc to model failed."); 337e41f4b71Sopenharmony_ci 338e41f4b71Sopenharmony_ci returnCode = OH_NNModel_SetTensorType(model, 2, OH_NN_ADD_ACTIVATIONTYPE); 339e41f4b71Sopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, OH_NN_FAILED, "Set model tensor type failed."); 340e41f4b71Sopenharmony_ci 341e41f4b71Sopenharmony_ci // 将激活函数类型设置为OH_NN_FUSED_NONE,表示该算子不添加激活函数。 342e41f4b71Sopenharmony_ci int8_t activationValue = OH_NN_FUSED_NONE; 343e41f4b71Sopenharmony_ci returnCode = OH_NNModel_SetTensorData(model, 2, &activationValue, sizeof(int8_t)); 344e41f4b71Sopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, OH_NN_FAILED, "Set model tensor data failed."); 345e41f4b71Sopenharmony_ci 346e41f4b71Sopenharmony_ci // 设置Add算子的输出张量,类型为float32,张量形状为[1, 2, 2, 3] 347e41f4b71Sopenharmony_ci tensorDesc = OH_NNTensorDesc_Create(); 348e41f4b71Sopenharmony_ci CHECKEQ(tensorDesc, nullptr, OH_NN_FAILED, "Create TensorDesc failed."); 349e41f4b71Sopenharmony_ci 350e41f4b71Sopenharmony_ci returnCode = OH_NNTensorDesc_SetShape(tensorDesc, inputDims, 4); 351e41f4b71Sopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, OH_NN_FAILED, "Set TensorDesc shape failed."); 352e41f4b71Sopenharmony_ci 353e41f4b71Sopenharmony_ci returnCode = OH_NNTensorDesc_SetDataType(tensorDesc, OH_NN_FLOAT32); 354e41f4b71Sopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, OH_NN_FAILED, "Set TensorDesc data type failed."); 355e41f4b71Sopenharmony_ci 356e41f4b71Sopenharmony_ci returnCode = OH_NNTensorDesc_SetFormat(tensorDesc, OH_NN_FORMAT_NONE); 357e41f4b71Sopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, OH_NN_FAILED, "Set TensorDesc format failed."); 358e41f4b71Sopenharmony_ci 359e41f4b71Sopenharmony_ci returnCode = OH_NNModel_AddTensorToModel(model, tensorDesc); 360e41f4b71Sopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, OH_NN_FAILED, "Add forth TensorDesc to model failed."); 361e41f4b71Sopenharmony_ci 362e41f4b71Sopenharmony_ci returnCode = OH_NNModel_SetTensorType(model, 3, OH_NN_TENSOR); 363e41f4b71Sopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, OH_NN_FAILED, "Set model tensor type failed."); 364e41f4b71Sopenharmony_ci 365e41f4b71Sopenharmony_ci // 指定Add算子的输入张量、参数张量和输出张量的索引 366e41f4b71Sopenharmony_ci uint32_t inputIndicesValues[2] = {0, 1}; 367e41f4b71Sopenharmony_ci uint32_t paramIndicesValues = 2; 368e41f4b71Sopenharmony_ci uint32_t outputIndicesValues = 3; 369e41f4b71Sopenharmony_ci OH_NN_UInt32Array paramIndices = {¶mIndicesValues, 1}; 370e41f4b71Sopenharmony_ci OH_NN_UInt32Array inputIndices = {inputIndicesValues, 2}; 371e41f4b71Sopenharmony_ci OH_NN_UInt32Array outputIndices = {&outputIndicesValues, 1}; 372e41f4b71Sopenharmony_ci 373e41f4b71Sopenharmony_ci // 向模型实例添加Add算子 374e41f4b71Sopenharmony_ci returnCode = OH_NNModel_AddOperation(model, OH_NN_OPS_ADD, ¶mIndices, &inputIndices, &outputIndices); 375e41f4b71Sopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, OH_NN_FAILED, "Add operation to model failed."); 376e41f4b71Sopenharmony_ci 377e41f4b71Sopenharmony_ci // 设置模型实例的输入张量、输出张量的索引 378e41f4b71Sopenharmony_ci returnCode = OH_NNModel_SpecifyInputsAndOutputs(model, &inputIndices, &outputIndices); 379e41f4b71Sopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, OH_NN_FAILED, "Specify model inputs and outputs failed."); 380e41f4b71Sopenharmony_ci 381e41f4b71Sopenharmony_ci // 完成模型实例的构建 382e41f4b71Sopenharmony_ci returnCode = OH_NNModel_Finish(model); 383e41f4b71Sopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, OH_NN_FAILED, "Build model failed."); 384e41f4b71Sopenharmony_ci 385e41f4b71Sopenharmony_ci // 返回模型实例 386e41f4b71Sopenharmony_ci *pmodel = model; 387e41f4b71Sopenharmony_ci return OH_NN_SUCCESS; 388e41f4b71Sopenharmony_ci } 389e41f4b71Sopenharmony_ci ``` 390e41f4b71Sopenharmony_ci 391e41f4b71Sopenharmony_ci5. 查询Neural Network Runtime已经对接的AI加速芯片。 392e41f4b71Sopenharmony_ci 393e41f4b71Sopenharmony_ci Neural Network Runtime支持通过HDI接口,对接多种AI加速芯片。在执行模型编译前,需要查询当前设备下,Neural Network Runtime已经对接的AI加速芯片。每个AI加速芯片对应唯一的ID值,在编译阶段需要通过设备ID,指定模型编译的芯片。 394e41f4b71Sopenharmony_ci ```cpp 395e41f4b71Sopenharmony_ci void GetAvailableDevices(std::vector<size_t>& availableDevice) 396e41f4b71Sopenharmony_ci { 397e41f4b71Sopenharmony_ci availableDevice.clear(); 398e41f4b71Sopenharmony_ci 399e41f4b71Sopenharmony_ci // 获取可用的硬件ID 400e41f4b71Sopenharmony_ci const size_t* devices = nullptr; 401e41f4b71Sopenharmony_ci uint32_t deviceCount = 0; 402e41f4b71Sopenharmony_ci OH_NN_ReturnCode ret = OH_NNDevice_GetAllDevicesID(&devices, &deviceCount); 403e41f4b71Sopenharmony_ci if (ret != OH_NN_SUCCESS) { 404e41f4b71Sopenharmony_ci std::cout << "GetAllDevicesID failed, get no available device." << std::endl; 405e41f4b71Sopenharmony_ci return; 406e41f4b71Sopenharmony_ci } 407e41f4b71Sopenharmony_ci 408e41f4b71Sopenharmony_ci for (uint32_t i = 0; i < deviceCount; i++) { 409e41f4b71Sopenharmony_ci availableDevice.emplace_back(devices[i]); 410e41f4b71Sopenharmony_ci } 411e41f4b71Sopenharmony_ci } 412e41f4b71Sopenharmony_ci ``` 413e41f4b71Sopenharmony_ci 414e41f4b71Sopenharmony_ci6. 在指定的设备上编译模型。 415e41f4b71Sopenharmony_ci 416e41f4b71Sopenharmony_ci Neural Network Runtime使用抽象的模型表达描述AI模型的拓扑结构。在AI加速芯片上执行前,需要通过Neural Network Runtime提供的编译模块来创建编译实例,并由编译实例将抽象的模型表达下发至芯片驱动层,转换成可以直接推理计算的格式,即模型编译。 417e41f4b71Sopenharmony_ci ```cpp 418e41f4b71Sopenharmony_ci OH_NN_ReturnCode CreateCompilation(OH_NNModel* model, const std::vector<size_t>& availableDevice, 419e41f4b71Sopenharmony_ci OH_NNCompilation** pCompilation) 420e41f4b71Sopenharmony_ci { 421e41f4b71Sopenharmony_ci // 创建编译实例compilation,将构图的模型实例或MSLite传下来的模型实例传入 422e41f4b71Sopenharmony_ci OH_NNCompilation* compilation = OH_NNCompilation_Construct(model); 423e41f4b71Sopenharmony_ci CHECKEQ(compilation, nullptr, OH_NN_FAILED, "OH_NNCore_ConstructCompilationWithNNModel failed."); 424e41f4b71Sopenharmony_ci 425e41f4b71Sopenharmony_ci // 设置编译的硬件、缓存路径、性能模式、计算优先级、是否开启float16低精度计算等选项 426e41f4b71Sopenharmony_ci // 选择在第一个设备上编译模型 427e41f4b71Sopenharmony_ci auto returnCode = OH_NNCompilation_SetDevice(compilation, availableDevice[0]); 428e41f4b71Sopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, OH_NN_FAILED, "OH_NNCompilation_SetDevice failed."); 429e41f4b71Sopenharmony_ci 430e41f4b71Sopenharmony_ci // 将模型编译结果缓存在/data/local/tmp目录下,版本号指定为1 431e41f4b71Sopenharmony_ci returnCode = OH_NNCompilation_SetCache(compilation, "/data/local/tmp", 1); 432e41f4b71Sopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, OH_NN_FAILED, "OH_NNCompilation_SetCache failed."); 433e41f4b71Sopenharmony_ci 434e41f4b71Sopenharmony_ci // 设置硬件性能模式 435e41f4b71Sopenharmony_ci returnCode = OH_NNCompilation_SetPerformanceMode(compilation, OH_NN_PERFORMANCE_EXTREME); 436e41f4b71Sopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, OH_NN_FAILED, "OH_NNCompilation_SetPerformanceMode failed."); 437e41f4b71Sopenharmony_ci 438e41f4b71Sopenharmony_ci // 设置推理执行优先级 439e41f4b71Sopenharmony_ci returnCode = OH_NNCompilation_SetPriority(compilation, OH_NN_PRIORITY_HIGH); 440e41f4b71Sopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, OH_NN_FAILED, "OH_NNCompilation_SetPriority failed."); 441e41f4b71Sopenharmony_ci 442e41f4b71Sopenharmony_ci // 是否开启FP16计算模式 443e41f4b71Sopenharmony_ci returnCode = OH_NNCompilation_EnableFloat16(compilation, false); 444e41f4b71Sopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, OH_NN_FAILED, "OH_NNCompilation_EnableFloat16 failed."); 445e41f4b71Sopenharmony_ci 446e41f4b71Sopenharmony_ci // 执行模型编译 447e41f4b71Sopenharmony_ci returnCode = OH_NNCompilation_Build(compilation); 448e41f4b71Sopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, OH_NN_FAILED, "OH_NNCompilation_Build failed."); 449e41f4b71Sopenharmony_ci 450e41f4b71Sopenharmony_ci *pCompilation = compilation; 451e41f4b71Sopenharmony_ci return OH_NN_SUCCESS; 452e41f4b71Sopenharmony_ci } 453e41f4b71Sopenharmony_ci ``` 454e41f4b71Sopenharmony_ci 455e41f4b71Sopenharmony_ci7. 创建执行器。 456e41f4b71Sopenharmony_ci 457e41f4b71Sopenharmony_ci 完成模型编译后,需要调用Neural Network Runtime的执行模块,通过编译实例创建执行器。模型推理阶段中的设置模型输入、触发推理计算以及获取模型输出等操作均需要围绕执行器完成。 458e41f4b71Sopenharmony_ci ```cpp 459e41f4b71Sopenharmony_ci OH_NNExecutor* CreateExecutor(OH_NNCompilation* compilation) 460e41f4b71Sopenharmony_ci { 461e41f4b71Sopenharmony_ci // 通过编译实例compilation创建执行器executor 462e41f4b71Sopenharmony_ci OH_NNExecutor *executor = OH_NNExecutor_Construct(compilation); 463e41f4b71Sopenharmony_ci CHECKEQ(executor, nullptr, nullptr, "OH_NNExecutor_Construct failed."); 464e41f4b71Sopenharmony_ci return executor; 465e41f4b71Sopenharmony_ci } 466e41f4b71Sopenharmony_ci ``` 467e41f4b71Sopenharmony_ci 468e41f4b71Sopenharmony_ci8. 执行推理计算,并打印推理结果。 469e41f4b71Sopenharmony_ci 470e41f4b71Sopenharmony_ci 通过执行模块提供的接口,将推理计算所需要的输入数据传递给执行器,触发执行器完成一次推理计算,获取模型的推理结果并打印。 471e41f4b71Sopenharmony_ci ```cpp 472e41f4b71Sopenharmony_ci OH_NN_ReturnCode Run(OH_NNExecutor* executor, const std::vector<size_t>& availableDevice) 473e41f4b71Sopenharmony_ci { 474e41f4b71Sopenharmony_ci // 从executor获取输入输出信息 475e41f4b71Sopenharmony_ci // 获取输入张量的个数 476e41f4b71Sopenharmony_ci size_t inputCount = 0; 477e41f4b71Sopenharmony_ci auto returnCode = OH_NNExecutor_GetInputCount(executor, &inputCount); 478e41f4b71Sopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, OH_NN_FAILED, "OH_NNExecutor_GetInputCount failed."); 479e41f4b71Sopenharmony_ci std::vector<NN_TensorDesc*> inputTensorDescs; 480e41f4b71Sopenharmony_ci NN_TensorDesc* tensorDescTmp = nullptr; 481e41f4b71Sopenharmony_ci for (size_t i = 0; i < inputCount; ++i) { 482e41f4b71Sopenharmony_ci // 创建输入张量的描述 483e41f4b71Sopenharmony_ci tensorDescTmp = OH_NNExecutor_CreateInputTensorDesc(executor, i); 484e41f4b71Sopenharmony_ci CHECKEQ(tensorDescTmp, nullptr, OH_NN_FAILED, "OH_NNExecutor_CreateInputTensorDesc failed."); 485e41f4b71Sopenharmony_ci inputTensorDescs.emplace_back(tensorDescTmp); 486e41f4b71Sopenharmony_ci } 487e41f4b71Sopenharmony_ci // 获取输出张量的个数 488e41f4b71Sopenharmony_ci size_t outputCount = 0; 489e41f4b71Sopenharmony_ci returnCode = OH_NNExecutor_GetOutputCount(executor, &outputCount); 490e41f4b71Sopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, OH_NN_FAILED, "OH_NNExecutor_GetOutputCount failed."); 491e41f4b71Sopenharmony_ci std::vector<NN_TensorDesc*> outputTensorDescs; 492e41f4b71Sopenharmony_ci for (size_t i = 0; i < outputCount; ++i) { 493e41f4b71Sopenharmony_ci // 创建输出张量的描述 494e41f4b71Sopenharmony_ci tensorDescTmp = OH_NNExecutor_CreateOutputTensorDesc(executor, i); 495e41f4b71Sopenharmony_ci CHECKEQ(tensorDescTmp, nullptr, OH_NN_FAILED, "OH_NNExecutor_CreateOutputTensorDesc failed."); 496e41f4b71Sopenharmony_ci outputTensorDescs.emplace_back(tensorDescTmp); 497e41f4b71Sopenharmony_ci } 498e41f4b71Sopenharmony_ci 499e41f4b71Sopenharmony_ci // 创建输入和输出张量 500e41f4b71Sopenharmony_ci NN_Tensor* inputTensors[inputCount]; 501e41f4b71Sopenharmony_ci NN_Tensor* tensor = nullptr; 502e41f4b71Sopenharmony_ci for (size_t i = 0; i < inputCount; ++i) { 503e41f4b71Sopenharmony_ci tensor = nullptr; 504e41f4b71Sopenharmony_ci tensor = OH_NNTensor_Create(availableDevice[0], inputTensorDescs[i]); 505e41f4b71Sopenharmony_ci CHECKEQ(tensor, nullptr, OH_NN_FAILED, "OH_NNTensor_Create failed."); 506e41f4b71Sopenharmony_ci inputTensors[i] = tensor; 507e41f4b71Sopenharmony_ci } 508e41f4b71Sopenharmony_ci NN_Tensor* outputTensors[outputCount]; 509e41f4b71Sopenharmony_ci for (size_t i = 0; i < outputCount; ++i) { 510e41f4b71Sopenharmony_ci tensor = nullptr; 511e41f4b71Sopenharmony_ci tensor = OH_NNTensor_Create(availableDevice[0], outputTensorDescs[i]); 512e41f4b71Sopenharmony_ci CHECKEQ(tensor, nullptr, OH_NN_FAILED, "OH_NNTensor_Create failed."); 513e41f4b71Sopenharmony_ci outputTensors[i] = tensor; 514e41f4b71Sopenharmony_ci } 515e41f4b71Sopenharmony_ci 516e41f4b71Sopenharmony_ci // 设置输入张量的数据 517e41f4b71Sopenharmony_ci returnCode = SetInputData(inputTensors, inputCount); 518e41f4b71Sopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, OH_NN_FAILED, "SetInputData failed."); 519e41f4b71Sopenharmony_ci 520e41f4b71Sopenharmony_ci // 执行推理 521e41f4b71Sopenharmony_ci returnCode = OH_NNExecutor_RunSync(executor, inputTensors, inputCount, outputTensors, outputCount); 522e41f4b71Sopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, OH_NN_FAILED, "OH_NNExecutor_RunSync failed."); 523e41f4b71Sopenharmony_ci 524e41f4b71Sopenharmony_ci // 打印输出张量的数据 525e41f4b71Sopenharmony_ci Print(outputTensors, outputCount); 526e41f4b71Sopenharmony_ci 527e41f4b71Sopenharmony_ci // 清理输入和输出张量以及张量描述 528e41f4b71Sopenharmony_ci for (size_t i = 0; i < inputCount; ++i) { 529e41f4b71Sopenharmony_ci returnCode = OH_NNTensor_Destroy(&inputTensors[i]); 530e41f4b71Sopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, OH_NN_FAILED, "OH_NNTensor_Destroy failed."); 531e41f4b71Sopenharmony_ci returnCode = OH_NNTensorDesc_Destroy(&inputTensorDescs[i]); 532e41f4b71Sopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, OH_NN_FAILED, "OH_NNTensorDesc_Destroy failed."); 533e41f4b71Sopenharmony_ci } 534e41f4b71Sopenharmony_ci for (size_t i = 0; i < outputCount; ++i) { 535e41f4b71Sopenharmony_ci returnCode = OH_NNTensor_Destroy(&outputTensors[i]); 536e41f4b71Sopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, OH_NN_FAILED, "OH_NNTensor_Destroy failed."); 537e41f4b71Sopenharmony_ci returnCode = OH_NNTensorDesc_Destroy(&outputTensorDescs[i]); 538e41f4b71Sopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, OH_NN_FAILED, "OH_NNTensorDesc_Destroy failed."); 539e41f4b71Sopenharmony_ci } 540e41f4b71Sopenharmony_ci 541e41f4b71Sopenharmony_ci return OH_NN_SUCCESS; 542e41f4b71Sopenharmony_ci } 543e41f4b71Sopenharmony_ci ``` 544e41f4b71Sopenharmony_ci 545e41f4b71Sopenharmony_ci9. 构建端到端模型构造-编译-执行流程。 546e41f4b71Sopenharmony_ci 547e41f4b71Sopenharmony_ci 步骤4-步骤8实现了模型的模型构造、编译和执行流程,并封装成多个函数,便于模块化开发。以下示例代码将串联这些函数, 形成一个完整的Neural Network Runtime使用流程。 548e41f4b71Sopenharmony_ci ```cpp 549e41f4b71Sopenharmony_ci int main(int argc, char** argv) 550e41f4b71Sopenharmony_ci { 551e41f4b71Sopenharmony_ci OH_NNModel* model = nullptr; 552e41f4b71Sopenharmony_ci OH_NNCompilation* compilation = nullptr; 553e41f4b71Sopenharmony_ci OH_NNExecutor* executor = nullptr; 554e41f4b71Sopenharmony_ci std::vector<size_t> availableDevices; 555e41f4b71Sopenharmony_ci 556e41f4b71Sopenharmony_ci // 模型构造 557e41f4b71Sopenharmony_ci OH_NN_ReturnCode ret = BuildModel(&model); 558e41f4b71Sopenharmony_ci if (ret != OH_NN_SUCCESS) { 559e41f4b71Sopenharmony_ci std::cout << "BuildModel failed." << std::endl; 560e41f4b71Sopenharmony_ci OH_NNModel_Destroy(&model); 561e41f4b71Sopenharmony_ci return -1; 562e41f4b71Sopenharmony_ci } 563e41f4b71Sopenharmony_ci 564e41f4b71Sopenharmony_ci // 获取可执行的设备 565e41f4b71Sopenharmony_ci GetAvailableDevices(availableDevices); 566e41f4b71Sopenharmony_ci if (availableDevices.empty()) { 567e41f4b71Sopenharmony_ci std::cout << "No available device." << std::endl; 568e41f4b71Sopenharmony_ci OH_NNModel_Destroy(&model); 569e41f4b71Sopenharmony_ci return -1; 570e41f4b71Sopenharmony_ci } 571e41f4b71Sopenharmony_ci 572e41f4b71Sopenharmony_ci // 模型编译 573e41f4b71Sopenharmony_ci ret = CreateCompilation(model, availableDevices, &compilation); 574e41f4b71Sopenharmony_ci if (ret != OH_NN_SUCCESS) { 575e41f4b71Sopenharmony_ci std::cout << "CreateCompilation failed." << std::endl; 576e41f4b71Sopenharmony_ci OH_NNModel_Destroy(&model); 577e41f4b71Sopenharmony_ci OH_NNCompilation_Destroy(&compilation); 578e41f4b71Sopenharmony_ci return -1; 579e41f4b71Sopenharmony_ci } 580e41f4b71Sopenharmony_ci 581e41f4b71Sopenharmony_ci // 销毁模型实例 582e41f4b71Sopenharmony_ci OH_NNModel_Destroy(&model); 583e41f4b71Sopenharmony_ci 584e41f4b71Sopenharmony_ci // 创建模型的推理执行器 585e41f4b71Sopenharmony_ci executor = CreateExecutor(compilation); 586e41f4b71Sopenharmony_ci if (executor == nullptr) { 587e41f4b71Sopenharmony_ci std::cout << "CreateExecutor failed, no executor is created." << std::endl; 588e41f4b71Sopenharmony_ci OH_NNCompilation_Destroy(&compilation); 589e41f4b71Sopenharmony_ci return -1; 590e41f4b71Sopenharmony_ci } 591e41f4b71Sopenharmony_ci 592e41f4b71Sopenharmony_ci // 销毁编译实例 593e41f4b71Sopenharmony_ci OH_NNCompilation_Destroy(&compilation); 594e41f4b71Sopenharmony_ci 595e41f4b71Sopenharmony_ci // 使用上一步创建的执行器,执行推理计算 596e41f4b71Sopenharmony_ci ret = Run(executor, availableDevices); 597e41f4b71Sopenharmony_ci if (ret != OH_NN_SUCCESS) { 598e41f4b71Sopenharmony_ci std::cout << "Run failed." << std::endl; 599e41f4b71Sopenharmony_ci OH_NNExecutor_Destroy(&executor); 600e41f4b71Sopenharmony_ci return -1; 601e41f4b71Sopenharmony_ci } 602e41f4b71Sopenharmony_ci 603e41f4b71Sopenharmony_ci // 销毁执行器实例 604e41f4b71Sopenharmony_ci OH_NNExecutor_Destroy(&executor); 605e41f4b71Sopenharmony_ci 606e41f4b71Sopenharmony_ci return 0; 607e41f4b71Sopenharmony_ci } 608e41f4b71Sopenharmony_ci ``` 609e41f4b71Sopenharmony_ci 610e41f4b71Sopenharmony_ci## 调测验证 611e41f4b71Sopenharmony_ci 612e41f4b71Sopenharmony_ci1. 准备应用样例的编译配置文件。 613e41f4b71Sopenharmony_ci 614e41f4b71Sopenharmony_ci 新建一个 `CMakeLists.txt` 文件,为开发步骤中的应用样例文件 `nnrt_example.cpp` 添加编译配置。以下提供简单的 `CMakeLists.txt` 示例: 615e41f4b71Sopenharmony_ci ```text 616e41f4b71Sopenharmony_ci cmake_minimum_required(VERSION 3.16) 617e41f4b71Sopenharmony_ci project(nnrt_example C CXX) 618e41f4b71Sopenharmony_ci 619e41f4b71Sopenharmony_ci add_executable(nnrt_example 620e41f4b71Sopenharmony_ci ./nnrt_example.cpp 621e41f4b71Sopenharmony_ci ) 622e41f4b71Sopenharmony_ci 623e41f4b71Sopenharmony_ci target_link_libraries(nnrt_example 624e41f4b71Sopenharmony_ci neural_network_runtime 625e41f4b71Sopenharmony_ci neural_network_core 626e41f4b71Sopenharmony_ci ) 627e41f4b71Sopenharmony_ci ``` 628e41f4b71Sopenharmony_ci 629e41f4b71Sopenharmony_ci2. 编译应用样例。 630e41f4b71Sopenharmony_ci 631e41f4b71Sopenharmony_ci 执行以下命令,在当前目录下新建build/目录,在build/目录下编译 `nnrt_example.cpp`,得到二进制文件 `nnrt_example`。 632e41f4b71Sopenharmony_ci ```shell 633e41f4b71Sopenharmony_ci mkdir build && cd build 634e41f4b71Sopenharmony_ci cmake -DCMAKE_TOOLCHAIN_FILE={交叉编译工具链的路径}/build/cmake/ohos.toolchain.cmake -DOHOS_ARCH=arm64-v8a -DOHOS_PLATFORM=OHOS -DOHOS_STL=c++_static .. 635e41f4b71Sopenharmony_ci make 636e41f4b71Sopenharmony_ci ``` 637e41f4b71Sopenharmony_ci 638e41f4b71Sopenharmony_ci3. 执行以下代码,将样例推送到设备上执行。 639e41f4b71Sopenharmony_ci ```shell 640e41f4b71Sopenharmony_ci # 将编译得到的 `nnrt_example` 推送到设备上,执行样例。 641e41f4b71Sopenharmony_ci hdc_std file send ./nnrt_example /data/local/tmp/. 642e41f4b71Sopenharmony_ci 643e41f4b71Sopenharmony_ci # 给测试用例可执行文件加上权限。 644e41f4b71Sopenharmony_ci hdc_std shell "chmod +x /data/local/tmp/nnrt_example" 645e41f4b71Sopenharmony_ci 646e41f4b71Sopenharmony_ci # 执行测试用例 647e41f4b71Sopenharmony_ci hdc_std shell "/data/local/tmp/nnrt_example" 648e41f4b71Sopenharmony_ci ``` 649e41f4b71Sopenharmony_ci 650e41f4b71Sopenharmony_ci 如果样例执行正常,应该得到以下输出。 651e41f4b71Sopenharmony_ci ```text 652e41f4b71Sopenharmony_ci Output index: 0, value is: 0.000000. 653e41f4b71Sopenharmony_ci Output index: 1, value is: 2.000000. 654e41f4b71Sopenharmony_ci Output index: 2, value is: 4.000000. 655e41f4b71Sopenharmony_ci Output index: 3, value is: 6.000000. 656e41f4b71Sopenharmony_ci Output index: 4, value is: 8.000000. 657e41f4b71Sopenharmony_ci Output index: 5, value is: 10.000000. 658e41f4b71Sopenharmony_ci Output index: 6, value is: 12.000000. 659e41f4b71Sopenharmony_ci Output index: 7, value is: 14.000000. 660e41f4b71Sopenharmony_ci Output index: 8, value is: 16.000000. 661e41f4b71Sopenharmony_ci Output index: 9, value is: 18.000000. 662e41f4b71Sopenharmony_ci Output index: 10, value is: 20.000000. 663e41f4b71Sopenharmony_ci Output index: 11, value is: 22.000000. 664e41f4b71Sopenharmony_ci ``` 665e41f4b71Sopenharmony_ci 666e41f4b71Sopenharmony_ci4. 检查模型缓存(可选)。 667e41f4b71Sopenharmony_ci 668e41f4b71Sopenharmony_ci 如果在调测环境下,Neural Network Runtime对接的HDI服务支持模型缓存功能,执行完 `nnrt_example`, 可以在 `/data/local/tmp` 目录下找到生成的缓存文件。 669e41f4b71Sopenharmony_ci 670e41f4b71Sopenharmony_ci > **说明:** 671e41f4b71Sopenharmony_ci > 672e41f4b71Sopenharmony_ci > 模型的IR需要传递到硬件驱动层,由HDI服务将统一的IR图,编译成硬件专用的计算图,编译的过程非常耗时。Neural Network Runtime支持计算图缓存的特性,可以将HDI服务编译生成的计算图,缓存到设备存储中。当下一次在同一个加速芯片上编译同一个模型时,通过指定缓存的路径,Neural Network Runtime可以直接加载缓存文件中的计算图,减少编译消耗的时间。 673e41f4b71Sopenharmony_ci 674e41f4b71Sopenharmony_ci 检查缓存目录下的缓存文件: 675e41f4b71Sopenharmony_ci ```shell 676e41f4b71Sopenharmony_ci ls /data/local/tmp 677e41f4b71Sopenharmony_ci ``` 678e41f4b71Sopenharmony_ci 679e41f4b71Sopenharmony_ci 以下为打印结果: 680e41f4b71Sopenharmony_ci ```text 681e41f4b71Sopenharmony_ci # 0.nncache 1.nncache 2.nncache cache_info.nncache 682e41f4b71Sopenharmony_ci ``` 683e41f4b71Sopenharmony_ci 684e41f4b71Sopenharmony_ci 如果缓存不再使用,需要手动删除缓存,可以参考以下命令,删除缓存文件。 685e41f4b71Sopenharmony_ci ```shell 686e41f4b71Sopenharmony_ci rm /data/local/tmp/*nncache 687e41f4b71Sopenharmony_ci ``` 688