112e714ceSopenharmony_ci# Neural Network Runtime对接AI推理框架开发指导 212e714ceSopenharmony_ci 312e714ceSopenharmony_ci## 场景介绍 412e714ceSopenharmony_ci 512e714ceSopenharmony_ciNeural Network Runtime作为AI推理引擎和加速芯片的桥梁,为AI推理引擎提供精简的Native接口,满足推理引擎通过加速芯片执行端到端推理的需求。 612e714ceSopenharmony_ci 712e714ceSopenharmony_ci本文以图1展示的`Add`单算子模型为例,介绍Neural Network Runtime的开发流程。`Add`算子包含两个输入、一个参数和一个输出,其中的`activation`参数用于指定`Add`算子中激活函数的类型。 812e714ceSopenharmony_ci 912e714ceSopenharmony_ci**图1** Add单算子网络示意图 1012e714ceSopenharmony_ci 1112e714ceSopenharmony_ci 1212e714ceSopenharmony_ci## 环境准备 1312e714ceSopenharmony_ci 1412e714ceSopenharmony_ci### 环境要求 1512e714ceSopenharmony_ci 1612e714ceSopenharmony_ciNeural Network Runtime部件的环境要求如下: 1712e714ceSopenharmony_ci 1812e714ceSopenharmony_ci- 开发环境:Ubuntu 18.04及以上。 1912e714ceSopenharmony_ci- 接入设备:系统定义的标准设备,系统中内置AI硬件驱动并已接入Neural Network Runtime。 2012e714ceSopenharmony_ci 2112e714ceSopenharmony_ci由于Neural Network Runtime通过OpenHarmony Native API对外开放,需要通过OpenHarmony的Native开发套件编译Neural Network Runtime应用。在社区的每日构建中下载对应系统版本的ohos-sdk压缩包,从压缩包中提取对应平台的Native开发套件。以Linux为例,Native开发套件的压缩包命名为`native-linux-{版本号}.zip`。 2212e714ceSopenharmony_ci 2312e714ceSopenharmony_ci### 环境搭建 2412e714ceSopenharmony_ci 2512e714ceSopenharmony_ci1. 打开Ubuntu编译服务器的终端。 2612e714ceSopenharmony_ci2. 把下载好的Native开发套件压缩包拷贝至当前用户根目录下。 2712e714ceSopenharmony_ci3. 执行以下命令解压Native开发套件的压缩包。 2812e714ceSopenharmony_ci ```shell 2912e714ceSopenharmony_ci unzip native-linux-{版本号}.zip 3012e714ceSopenharmony_ci ``` 3112e714ceSopenharmony_ci 3212e714ceSopenharmony_ci 解压缩后的内容如下(随版本迭代,目录下的内容可能发生变化,请以最新版本的Native API为准): 3312e714ceSopenharmony_ci ```text 3412e714ceSopenharmony_ci native/ 3512e714ceSopenharmony_ci ├── build // 交叉编译工具链 3612e714ceSopenharmony_ci ├── build-tools // 编译构建工具 3712e714ceSopenharmony_ci ├── docs 3812e714ceSopenharmony_ci ├── llvm 3912e714ceSopenharmony_ci ├── nativeapi_syscap_config.json 4012e714ceSopenharmony_ci ├── ndk_system_capability.json 4112e714ceSopenharmony_ci ├── NOTICE.txt 4212e714ceSopenharmony_ci ├── oh-uni-package.json 4312e714ceSopenharmony_ci └── sysroot // Native API头文件和库 4412e714ceSopenharmony_ci ``` 4512e714ceSopenharmony_ci## 接口说明 4612e714ceSopenharmony_ci 4712e714ceSopenharmony_ci这里给出Neural Network Runtime开发流程中通用的接口,具体请见下列表格。 4812e714ceSopenharmony_ci 4912e714ceSopenharmony_ci### 结构体 5012e714ceSopenharmony_ci 5112e714ceSopenharmony_ci| 结构体名称 | 描述 | 5212e714ceSopenharmony_ci| --------- | ---- | 5312e714ceSopenharmony_ci| typedef struct OH_NNModel OH_NNModel | Neural Network Runtime的模型句柄,用于构造模型。 | 5412e714ceSopenharmony_ci| typedef struct OH_NNCompilation OH_NNCompilation | Neural Network Runtime的编译器句柄,用于编译AI模型。 | 5512e714ceSopenharmony_ci| typedef struct OH_NNExecutor OH_NNExecutor | Neural Network Runtime的执行器句柄,用于在指定设备上执行推理计算。 | 5612e714ceSopenharmony_ci| typedef struct NN_QuantParam NN_QuantParam | Neural Network Runtime的量化参数句柄,用于在构造模型时指定张量的量化参数。 | 5712e714ceSopenharmony_ci| typedef struct NN_TensorDesc NN_TensorDesc | Neural Network Runtime的张量描述句柄,用于描述张量的各类属性,例如数据布局、数据类型、形状等。 | 5812e714ceSopenharmony_ci| typedef struct NN_Tensor NN_Tensor | Neural Network Runtime的张量句柄,用于设置执行器的推理输入和输出张量。 | 5912e714ceSopenharmony_ci 6012e714ceSopenharmony_ci### 模型构造接口 6112e714ceSopenharmony_ci 6212e714ceSopenharmony_ci| 接口名称 | 描述 | 6312e714ceSopenharmony_ci| ------- | --- | 6412e714ceSopenharmony_ci| OH_NNModel_Construct() | 创建OH_NNModel类型的模型实例。 | 6512e714ceSopenharmony_ci| OH_NN_ReturnCode OH_NNModel_AddTensorToModel(OH_NNModel *model, const NN_TensorDesc *tensorDesc) | 向模型实例中添加张量。 | 6612e714ceSopenharmony_ci| OH_NN_ReturnCode OH_NNModel_SetTensorData(OH_NNModel *model, uint32_t index, const void *dataBuffer, size_t length) | 设置张量的数值。 | 6712e714ceSopenharmony_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) | 向模型实例中添加算子。 | 6812e714ceSopenharmony_ci| OH_NN_ReturnCode OH_NNModel_SpecifyInputsAndOutputs(OH_NNModel *model, const OH_NN_UInt32Array *inputIndices, const OH_NN_UInt32Array *outputIndices) | 指定模型的输入和输出张量的索引值。 | 6912e714ceSopenharmony_ci| OH_NN_ReturnCode OH_NNModel_Finish(OH_NNModel *model) | 完成模型构图。| 7012e714ceSopenharmony_ci| void OH_NNModel_Destroy(OH_NNModel **model) | 销毁模型实例。 | 7112e714ceSopenharmony_ci 7212e714ceSopenharmony_ci 7312e714ceSopenharmony_ci### 模型编译接口 7412e714ceSopenharmony_ci 7512e714ceSopenharmony_ci| 接口名称 | 描述 | 7612e714ceSopenharmony_ci| ------- | --- | 7712e714ceSopenharmony_ci| OH_NNCompilation *OH_NNCompilation_Construct(const OH_NNModel *model) | 基于模型实例创建OH_NNCompilation类型的编译实例。 | 7812e714ceSopenharmony_ci| OH_NNCompilation *OH_NNCompilation_ConstructWithOfflineModelFile(const char *modelPath) | 基于离线模型文件路径创建OH_NNCompilation类型的编译实例。 | 7912e714ceSopenharmony_ci| OH_NNCompilation *OH_NNCompilation_ConstructWithOfflineModelBuffer(const void *modelBuffer, size_t modelSize) | 基于离线模型文件内存创建OH_NNCompilation类型的编译实例。 | 8012e714ceSopenharmony_ci| OH_NNCompilation *OH_NNCompilation_ConstructForCache() | 创建一个空的编译实例,以便稍后从模型缓存中恢复。 | 8112e714ceSopenharmony_ci| OH_NN_ReturnCode OH_NNCompilation_ExportCacheToBuffer(OH_NNCompilation *compilation, const void *buffer, size_t length, size_t *modelSize) | 将模型缓存写入到指定内存区域。 | 8212e714ceSopenharmony_ci| OH_NN_ReturnCode OH_NNCompilation_ImportCacheFromBuffer(OH_NNCompilation *compilation, const void *buffer, size_t modelSize) | 从指定内存区域读取模型缓存。 | 8312e714ceSopenharmony_ci| OH_NN_ReturnCode OH_NNCompilation_AddExtensionConfig(OH_NNCompilation *compilation, const char *configName, const void *configValue, const size_t configValueSize) | 为自定义硬件属性添加扩展配置,具体硬件的扩展属性名称和属性值需要从硬件厂商的文档中获取。 | 8412e714ceSopenharmony_ci| OH_NN_ReturnCode OH_NNCompilation_SetDevice(OH_NNCompilation *compilation, size_t deviceID) | 指定模型编译和计算的硬件,可通过设备管理接口获取。 | 8512e714ceSopenharmony_ci| OH_NN_ReturnCode OH_NNCompilation_SetCache(OH_NNCompilation *compilation, const char *cachePath, uint32_t version) | 设置编译模型的缓存目录和版本。 | 8612e714ceSopenharmony_ci| OH_NN_ReturnCode OH_NNCompilation_SetPerformanceMode(OH_NNCompilation *compilation, OH_NN_PerformanceMode performanceMode) | 设置模型计算的性能模式。 | 8712e714ceSopenharmony_ci| OH_NN_ReturnCode OH_NNCompilation_SetPriority(OH_NNCompilation *compilation, OH_NN_Priority priority) | 设置模型计算的优先级。 | 8812e714ceSopenharmony_ci| OH_NN_ReturnCode OH_NNCompilation_EnableFloat16(OH_NNCompilation *compilation, bool enableFloat16) | 是否以float16的浮点数精度计算。 | 8912e714ceSopenharmony_ci| OH_NN_ReturnCode OH_NNCompilation_Build(OH_NNCompilation *compilation) | 执行模型编译。 | 9012e714ceSopenharmony_ci| void OH_NNCompilation_Destroy(OH_NNCompilation **compilation) | 销毁编译实例。 | 9112e714ceSopenharmony_ci 9212e714ceSopenharmony_ci### 张量描述接口 9312e714ceSopenharmony_ci 9412e714ceSopenharmony_ci| 接口名称 | 描述 | 9512e714ceSopenharmony_ci| ------- | --- | 9612e714ceSopenharmony_ci| NN_TensorDesc *OH_NNTensorDesc_Create() | 创建一个张量描述实例,用于后续创建张量。 | 9712e714ceSopenharmony_ci| OH_NN_ReturnCode OH_NNTensorDesc_SetName(NN_TensorDesc *tensorDesc, const char *name) | 设置张量描述的名称。 | 9812e714ceSopenharmony_ci| OH_NN_ReturnCode OH_NNTensorDesc_GetName(const NN_TensorDesc *tensorDesc, const char **name) | 获取张量描述的名称。 | 9912e714ceSopenharmony_ci| OH_NN_ReturnCode OH_NNTensorDesc_SetDataType(NN_TensorDesc *tensorDesc, OH_NN_DataType dataType) | 设置张量描述的数据类型。 | 10012e714ceSopenharmony_ci| OH_NN_ReturnCode OH_NNTensorDesc_GetDataType(const NN_TensorDesc *tensorDesc, OH_NN_DataType *dataType) | 获取张量描述的数据类型。 | 10112e714ceSopenharmony_ci| OH_NN_ReturnCode OH_NNTensorDesc_SetShape(NN_TensorDesc *tensorDesc, const int32_t *shape, size_t shapeLength) | 设置张量描述的形状。 | 10212e714ceSopenharmony_ci| OH_NN_ReturnCode OH_NNTensorDesc_GetShape(const NN_TensorDesc *tensorDesc, int32_t **shape, size_t *shapeLength) | 获取张量描述的形状。 | 10312e714ceSopenharmony_ci| OH_NN_ReturnCode OH_NNTensorDesc_SetFormat(NN_TensorDesc *tensorDesc, OH_NN_Format format) | 设置张量描述的数据布局。 | 10412e714ceSopenharmony_ci| OH_NN_ReturnCode OH_NNTensorDesc_GetFormat(const NN_TensorDesc *tensorDesc, OH_NN_Format *format) | 获取张量描述的数据布局。 | 10512e714ceSopenharmony_ci| OH_NN_ReturnCode OH_NNTensorDesc_GetElementCount(const NN_TensorDesc *tensorDesc, size_t *elementCount) | 获取张量描述的元素个数。 | 10612e714ceSopenharmony_ci| OH_NN_ReturnCode OH_NNTensorDesc_GetByteSize(const NN_TensorDesc *tensorDesc, size_t *byteSize) | 获取基于张量描述的形状和数据类型计算的数据占用字节数。 | 10712e714ceSopenharmony_ci| OH_NN_ReturnCode OH_NNTensorDesc_Destroy(NN_TensorDesc **tensorDesc) | 销毁张量描述实例。 | 10812e714ceSopenharmony_ci 10912e714ceSopenharmony_ci### 张量接口 11012e714ceSopenharmony_ci 11112e714ceSopenharmony_ci| 接口名称 | 描述 | 11212e714ceSopenharmony_ci| ------- | --- | 11312e714ceSopenharmony_ci| NN_Tensor* OH_NNTensor_Create(size_t deviceID, NN_TensorDesc *tensorDesc) | 从张量描述创建张量实例,会申请设备共享内存。 | 11412e714ceSopenharmony_ci| NN_Tensor* OH_NNTensor_CreateWithSize(size_t deviceID, NN_TensorDesc *tensorDesc, size_t size) | 按照指定内存大小和张量描述创建张量实例,会申请设备共享内存。 | 11512e714ceSopenharmony_ci| NN_Tensor* OH_NNTensor_CreateWithFd(size_t deviceID, NN_TensorDesc *tensorDesc, int fd, size_t size, size_t offset) | 按照指定共享内存的文件描述符和张量描述创建张量实例,从而可以复用其他张量的设备共享内存。 | 11612e714ceSopenharmony_ci| NN_TensorDesc* OH_NNTensor_GetTensorDesc(const NN_Tensor *tensor) | 获取张量内部的张量描述实例指针,从而可读取张量的属性,例如数据类型、形状等。 | 11712e714ceSopenharmony_ci| void* OH_NNTensor_GetDataBuffer(const NN_Tensor *tensor) | 获取张量数据的内存地址,可以读写张量数据。 | 11812e714ceSopenharmony_ci| OH_NN_ReturnCode OH_NNTensor_GetFd(const NN_Tensor *tensor, int *fd) | 获取张量数据所在共享内存的文件描述符,文件描述符fd对应了一块设备共享内存。 | 11912e714ceSopenharmony_ci| OH_NN_ReturnCode OH_NNTensor_GetSize(const NN_Tensor *tensor, size_t *size) | 获取张量数据所在共享内存的大小。 | 12012e714ceSopenharmony_ci| OH_NN_ReturnCode OH_NNTensor_GetOffset(const NN_Tensor *tensor, size_t *offset) | 获取张量数据所在共享内存上的偏移量,张量数据可使用的大小为所在共享内存的大小减去偏移量。 | 12112e714ceSopenharmony_ci| OH_NN_ReturnCode OH_NNTensor_Destroy(NN_Tensor **tensor) | 销毁张量实例。 | 12212e714ceSopenharmony_ci 12312e714ceSopenharmony_ci### 执行推理接口 12412e714ceSopenharmony_ci 12512e714ceSopenharmony_ci| 接口名称 | 描述 | 12612e714ceSopenharmony_ci| ------- | --- | 12712e714ceSopenharmony_ci| OH_NNExecutor *OH_NNExecutor_Construct(OH_NNCompilation *compilation) | 创建OH_NNExecutor类型的执行器实例。 | 12812e714ceSopenharmony_ci| OH_NN_ReturnCode OH_NNExecutor_GetOutputShape(OH_NNExecutor *executor, uint32_t outputIndex, int32_t **shape, uint32_t *shapeLength) | 获取输出张量的维度信息,用于输出张量具有动态形状的情况。 | 12912e714ceSopenharmony_ci| OH_NN_ReturnCode OH_NNExecutor_GetInputCount(const OH_NNExecutor *executor, size_t *inputCount) | 获取输入张量的数量。 | 13012e714ceSopenharmony_ci| OH_NN_ReturnCode OH_NNExecutor_GetOutputCount(const OH_NNExecutor *executor, size_t *outputCount) | 获取输出张量的数量。 | 13112e714ceSopenharmony_ci| NN_TensorDesc* OH_NNExecutor_CreateInputTensorDesc(const OH_NNExecutor *executor, size_t index) | 由指定索引值创建一个输入张量的描述,用于读取张量的属性或创建张量实例。 | 13212e714ceSopenharmony_ci| NN_TensorDesc* OH_NNExecutor_CreateOutputTensorDesc(const OH_NNExecutor *executor, size_t index) | 由指定索引值创建一个输出张量的描述,用于读取张量的属性或创建张量实例。 | 13312e714ceSopenharmony_ci| OH_NN_ReturnCode OH_NNExecutor_GetInputDimRange(const OH_NNExecutor *executor, size_t index, size_t **minInputDims, size_t **maxInputDims, size_t *shapeLength) |获取所有输入张量的维度范围。当输入张量具有动态形状时,不同设备可能支持不同的维度范围。 | 13412e714ceSopenharmony_ci| OH_NN_ReturnCode OH_NNExecutor_SetOnRunDone(OH_NNExecutor *executor, NN_OnRunDone onRunDone) | 设置异步推理结束后的回调处理函数,回调函数定义详见接口文档。 | 13512e714ceSopenharmony_ci| OH_NN_ReturnCode OH_NNExecutor_SetOnServiceDied(OH_NNExecutor *executor, NN_OnServiceDied onServiceDied) | 设置异步推理执行期间设备驱动服务突然死亡时的回调处理函数,回调函数定义详见接口文档。 | 13612e714ceSopenharmony_ci| OH_NN_ReturnCode OH_NNExecutor_RunSync(OH_NNExecutor *executor, NN_Tensor *inputTensor[], size_t inputCount, NN_Tensor *outputTensor[], size_t outputCount) | 执行同步推理。 | 13712e714ceSopenharmony_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) | 执行异步推理。 | 13812e714ceSopenharmony_ci| void OH_NNExecutor_Destroy(OH_NNExecutor **executor) | 销毁执行器实例。 | 13912e714ceSopenharmony_ci 14012e714ceSopenharmony_ci### 设备管理接口 14112e714ceSopenharmony_ci 14212e714ceSopenharmony_ci| 接口名称 | 描述 | 14312e714ceSopenharmony_ci| ------- | --- | 14412e714ceSopenharmony_ci| OH_NN_ReturnCode OH_NNDevice_GetAllDevicesID(const size_t **allDevicesID, uint32_t *deviceCount) | 获取对接到Neural Network Runtime的所有硬件ID。 | 14512e714ceSopenharmony_ci| OH_NN_ReturnCode OH_NNDevice_GetName(size_t deviceID, const char **name) | 获取指定硬件的名称。 | 14612e714ceSopenharmony_ci| OH_NN_ReturnCode OH_NNDevice_GetType(size_t deviceID, OH_NN_DeviceType *deviceType) | 获取指定硬件的类别信息。 | 14712e714ceSopenharmony_ci 14812e714ceSopenharmony_ci 14912e714ceSopenharmony_ci## 开发步骤 15012e714ceSopenharmony_ci 15112e714ceSopenharmony_ciNeural Network Runtime的开发流程主要包含**模型构造**、**模型编译**和**推理执行**三个阶段。以下开发步骤以`Add`单算子模型为例,介绍调用Neural Network Runtime接口,开发应用的过程。 15212e714ceSopenharmony_ci 15312e714ceSopenharmony_ci1. 创建应用样例文件。 15412e714ceSopenharmony_ci 15512e714ceSopenharmony_ci 首先,创建Neural Network Runtime应用样例的源文件。在项目目录下执行以下命令,创建`nnrt_example/`目录,并在目录下创建 `nnrt_example.cpp` 源文件。 15612e714ceSopenharmony_ci 15712e714ceSopenharmony_ci ```shell 15812e714ceSopenharmony_ci mkdir ~/nnrt_example && cd ~/nnrt_example 15912e714ceSopenharmony_ci touch nnrt_example.cpp 16012e714ceSopenharmony_ci ``` 16112e714ceSopenharmony_ci 16212e714ceSopenharmony_ci2. 导入Neural Network Runtime。 16312e714ceSopenharmony_ci 16412e714ceSopenharmony_ci 在 `nnrt_example.cpp` 文件的开头添加以下代码,引入Neural Network Runtime。 16512e714ceSopenharmony_ci 16612e714ceSopenharmony_ci ```cpp 16712e714ceSopenharmony_ci #include <iostream> 16812e714ceSopenharmony_ci #include <cstdarg> 16912e714ceSopenharmony_ci #include "hilog/log.h" 17012e714ceSopenharmony_ci #include "neural_network_runtime/neural_network_runtime.h" 17112e714ceSopenharmony_ci ``` 17212e714ceSopenharmony_ci 17312e714ceSopenharmony_ci3. 定义日志打印、设置输入数据、数据打印等辅助函数。 17412e714ceSopenharmony_ci 17512e714ceSopenharmony_ci ```cpp 17612e714ceSopenharmony_ci #define LOG_DOMAIN 0xD002101 17712e714ceSopenharmony_ci #define LOG_TAG "NNRt" 17812e714ceSopenharmony_ci #define LOGD(...) OH_LOG_DEBUG(LOG_APP, __VA_ARGS__) 17912e714ceSopenharmony_ci #define LOGI(...) OH_LOG_INFO(LOG_APP, __VA_ARGS__) 18012e714ceSopenharmony_ci #define LOGW(...) OH_LOG_WARN(LOG_APP, __VA_ARGS__) 18112e714ceSopenharmony_ci #define LOGE(...) OH_LOG_ERROR(LOG_APP, __VA_ARGS__) 18212e714ceSopenharmony_ci #define LOGF(...) OH_LOG_FATAL(LOG_APP, __VA_ARGS__) 18312e714ceSopenharmony_ci 18412e714ceSopenharmony_ci // 返回值检查宏 18512e714ceSopenharmony_ci #define CHECKNEQ(realRet, expectRet, retValue, ...) \ 18612e714ceSopenharmony_ci do { \ 18712e714ceSopenharmony_ci if ((realRet) != (expectRet)) { \ 18812e714ceSopenharmony_ci printf(__VA_ARGS__); \ 18912e714ceSopenharmony_ci return (retValue); \ 19012e714ceSopenharmony_ci } \ 19112e714ceSopenharmony_ci } while (0) 19212e714ceSopenharmony_ci 19312e714ceSopenharmony_ci #define CHECKEQ(realRet, expectRet, retValue, ...) \ 19412e714ceSopenharmony_ci do { \ 19512e714ceSopenharmony_ci if ((realRet) == (expectRet)) { \ 19612e714ceSopenharmony_ci printf(__VA_ARGS__); \ 19712e714ceSopenharmony_ci return (retValue); \ 19812e714ceSopenharmony_ci } \ 19912e714ceSopenharmony_ci } while (0) 20012e714ceSopenharmony_ci 20112e714ceSopenharmony_ci // 设置输入数据用于推理 20212e714ceSopenharmony_ci OH_NN_ReturnCode SetInputData(NN_Tensor* inputTensor[], size_t inputSize) 20312e714ceSopenharmony_ci { 20412e714ceSopenharmony_ci OH_NN_DataType dataType(OH_NN_FLOAT32); 20512e714ceSopenharmony_ci OH_NN_ReturnCode ret{OH_NN_FAILED}; 20612e714ceSopenharmony_ci size_t elementCount = 0; 20712e714ceSopenharmony_ci for (size_t i = 0; i < inputSize; ++i) { 20812e714ceSopenharmony_ci // 获取张量的数据内存 20912e714ceSopenharmony_ci auto data = OH_NNTensor_GetDataBuffer(inputTensor[i]); 21012e714ceSopenharmony_ci CHECKEQ(data, nullptr, OH_NN_FAILED, "Failed to get data buffer."); 21112e714ceSopenharmony_ci // 获取张量的描述 21212e714ceSopenharmony_ci auto desc = OH_NNTensor_GetTensorDesc(inputTensor[i]); 21312e714ceSopenharmony_ci CHECKEQ(desc, nullptr, OH_NN_FAILED, "Failed to get desc."); 21412e714ceSopenharmony_ci // 获取张量的数据类型 21512e714ceSopenharmony_ci ret = OH_NNTensorDesc_GetDataType(desc, &dataType); 21612e714ceSopenharmony_ci CHECKNEQ(ret, OH_NN_SUCCESS, OH_NN_FAILED, "Failed to get data type."); 21712e714ceSopenharmony_ci // 获取张量的元素个数 21812e714ceSopenharmony_ci ret = OH_NNTensorDesc_GetElementCount(desc, &elementCount); 21912e714ceSopenharmony_ci CHECKNEQ(ret, OH_NN_SUCCESS, OH_NN_FAILED, "Failed to get element count."); 22012e714ceSopenharmony_ci switch(dataType) { 22112e714ceSopenharmony_ci case OH_NN_FLOAT32: { 22212e714ceSopenharmony_ci float* floatValue = reinterpret_cast<float*>(data); 22312e714ceSopenharmony_ci for (size_t j = 0; j < elementCount; ++j) { 22412e714ceSopenharmony_ci floatValue[j] = static_cast<float>(j); 22512e714ceSopenharmony_ci } 22612e714ceSopenharmony_ci break; 22712e714ceSopenharmony_ci } 22812e714ceSopenharmony_ci case OH_NN_INT32: { 22912e714ceSopenharmony_ci int* intValue = reinterpret_cast<int*>(data); 23012e714ceSopenharmony_ci for (size_t j = 0; j < elementCount; ++j) { 23112e714ceSopenharmony_ci intValue[j] = static_cast<int>(j); 23212e714ceSopenharmony_ci } 23312e714ceSopenharmony_ci break; 23412e714ceSopenharmony_ci } 23512e714ceSopenharmony_ci default: 23612e714ceSopenharmony_ci return OH_NN_FAILED; 23712e714ceSopenharmony_ci } 23812e714ceSopenharmony_ci } 23912e714ceSopenharmony_ci return OH_NN_SUCCESS; 24012e714ceSopenharmony_ci } 24112e714ceSopenharmony_ci 24212e714ceSopenharmony_ci OH_NN_ReturnCode Print(NN_Tensor* outputTensor[], size_t outputSize) 24312e714ceSopenharmony_ci { 24412e714ceSopenharmony_ci OH_NN_DataType dataType(OH_NN_FLOAT32); 24512e714ceSopenharmony_ci OH_NN_ReturnCode ret{OH_NN_FAILED}; 24612e714ceSopenharmony_ci size_t elementCount = 0; 24712e714ceSopenharmony_ci for (size_t i = 0; i < outputSize; ++i) { 24812e714ceSopenharmony_ci auto data = OH_NNTensor_GetDataBuffer(outputTensor[i]); 24912e714ceSopenharmony_ci CHECKEQ(data, nullptr, OH_NN_FAILED, "Failed to get data buffer."); 25012e714ceSopenharmony_ci auto desc = OH_NNTensor_GetTensorDesc(outputTensor[i]); 25112e714ceSopenharmony_ci CHECKEQ(desc, nullptr, OH_NN_FAILED, "Failed to get desc."); 25212e714ceSopenharmony_ci ret = OH_NNTensorDesc_GetDataType(desc, &dataType); 25312e714ceSopenharmony_ci CHECKNEQ(ret, OH_NN_SUCCESS, OH_NN_FAILED, "Failed to get data type."); 25412e714ceSopenharmony_ci ret = OH_NNTensorDesc_GetElementCount(desc, &elementCount); 25512e714ceSopenharmony_ci CHECKNEQ(ret, OH_NN_SUCCESS, OH_NN_FAILED, "Failed to get element count."); 25612e714ceSopenharmony_ci switch(dataType) { 25712e714ceSopenharmony_ci case OH_NN_FLOAT32: { 25812e714ceSopenharmony_ci float* floatValue = reinterpret_cast<float*>(data); 25912e714ceSopenharmony_ci for (size_t j = 0; j < elementCount; ++j) { 26012e714ceSopenharmony_ci std::cout << "Output index: " << j << ", value is: " << floatValue[j] << "." << std::endl; 26112e714ceSopenharmony_ci } 26212e714ceSopenharmony_ci break; 26312e714ceSopenharmony_ci } 26412e714ceSopenharmony_ci case OH_NN_INT32: { 26512e714ceSopenharmony_ci int* intValue = reinterpret_cast<int*>(data); 26612e714ceSopenharmony_ci for (size_t j = 0; j < elementCount; ++j) { 26712e714ceSopenharmony_ci std::cout << "Output index: " << j << ", value is: " << intValue[j] << "." << std::endl; 26812e714ceSopenharmony_ci } 26912e714ceSopenharmony_ci break; 27012e714ceSopenharmony_ci } 27112e714ceSopenharmony_ci default: 27212e714ceSopenharmony_ci return OH_NN_FAILED; 27312e714ceSopenharmony_ci } 27412e714ceSopenharmony_ci } 27512e714ceSopenharmony_ci 27612e714ceSopenharmony_ci return OH_NN_SUCCESS; 27712e714ceSopenharmony_ci } 27812e714ceSopenharmony_ci ``` 27912e714ceSopenharmony_ci 28012e714ceSopenharmony_ci4. 构造模型。 28112e714ceSopenharmony_ci 28212e714ceSopenharmony_ci 使用Neural Network Runtime的模型构造接口,构造`Add`单算子样例模型。 28312e714ceSopenharmony_ci 28412e714ceSopenharmony_ci ```cpp 28512e714ceSopenharmony_ci OH_NN_ReturnCode BuildModel(OH_NNModel** pmodel) 28612e714ceSopenharmony_ci { 28712e714ceSopenharmony_ci // 创建模型实例model,进行模型构造 28812e714ceSopenharmony_ci OH_NNModel* model = OH_NNModel_Construct(); 28912e714ceSopenharmony_ci CHECKEQ(model, nullptr, -1, "Create model failed."); 29012e714ceSopenharmony_ci 29112e714ceSopenharmony_ci // 添加Add算子的第一个输入张量,类型为float32,张量形状为[1, 2, 2, 3] 29212e714ceSopenharmony_ci NN_TensorDesc* tensorDesc = OH_NNTensorDesc_Create(); 29312e714ceSopenharmony_ci CHECKEQ(tensorDesc, nullptr, -1, "Create TensorDesc failed."); 29412e714ceSopenharmony_ci 29512e714ceSopenharmony_ci int32_t inputDims[4] = {1, 2, 2, 3}; 29612e714ceSopenharmony_ci returnCode = OH_NNTensorDesc_SetShape(tensorDesc, inputDims, 4); 29712e714ceSopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, -1, "Set TensorDesc shape failed."); 29812e714ceSopenharmony_ci 29912e714ceSopenharmony_ci returnCode = OH_NNTensorDesc_SetDataType(tensorDesc, OH_NN_FLOAT32); 30012e714ceSopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, -1, "Set TensorDesc data type failed."); 30112e714ceSopenharmony_ci 30212e714ceSopenharmony_ci returnCode = OH_NNTensorDesc_SetFormat(tensorDesc, OH_NN_FORMAT_NONE); 30312e714ceSopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, -1, "Set TensorDesc format failed."); 30412e714ceSopenharmony_ci 30512e714ceSopenharmony_ci returnCode = OH_NNModel_AddTensorToModel(model, tensorDesc); 30612e714ceSopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, -1, "Add first TensorDesc to model failed."); 30712e714ceSopenharmony_ci 30812e714ceSopenharmony_ci returnCode = OH_NNModel_SetTensorType(model, 0, OH_NN_TENSOR); 30912e714ceSopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, -1, "Set model tensor type failed."); 31012e714ceSopenharmony_ci 31112e714ceSopenharmony_ci // 添加Add算子的第二个输入张量,类型为float32,张量形状为[1, 2, 2, 3] 31212e714ceSopenharmony_ci tensorDesc = OH_NNTensorDesc_Create(); 31312e714ceSopenharmony_ci CHECKEQ(tensorDesc, nullptr, -1, "Create TensorDesc failed."); 31412e714ceSopenharmony_ci 31512e714ceSopenharmony_ci returnCode = OH_NNTensorDesc_SetShape(tensorDesc, inputDims, 4); 31612e714ceSopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, -1, "Set TensorDesc shape failed."); 31712e714ceSopenharmony_ci 31812e714ceSopenharmony_ci returnCode = OH_NNTensorDesc_SetDataType(tensorDesc, OH_NN_FLOAT32); 31912e714ceSopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, -1, "Set TensorDesc data type failed."); 32012e714ceSopenharmony_ci 32112e714ceSopenharmony_ci returnCode = OH_NNTensorDesc_SetFormat(tensorDesc, OH_NN_FORMAT_NONE); 32212e714ceSopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, -1, "Set TensorDesc format failed."); 32312e714ceSopenharmony_ci 32412e714ceSopenharmony_ci returnCode = OH_NNModel_AddTensorToModel(model, tensorDesc); 32512e714ceSopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, -1, "Add second TensorDesc to model failed."); 32612e714ceSopenharmony_ci 32712e714ceSopenharmony_ci returnCode = OH_NNModel_SetTensorType(model, 1, OH_NN_TENSOR); 32812e714ceSopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, -1, "Set model tensor type failed."); 32912e714ceSopenharmony_ci 33012e714ceSopenharmony_ci // 添加Add算子的参数张量,该参数张量用于指定激活函数的类型,张量的数据类型为int8。 33112e714ceSopenharmony_ci tensorDesc = OH_NNTensorDesc_Create(); 33212e714ceSopenharmony_ci CHECKEQ(tensorDesc, nullptr, -1, "Create TensorDesc failed."); 33312e714ceSopenharmony_ci 33412e714ceSopenharmony_ci int32_t activationDims = 1; 33512e714ceSopenharmony_ci returnCode = OH_NNTensorDesc_SetShape(tensorDesc, &activationDims, 1); 33612e714ceSopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, -1, "Set TensorDesc shape failed."); 33712e714ceSopenharmony_ci 33812e714ceSopenharmony_ci returnCode = OH_NNTensorDesc_SetDataType(tensorDesc, OH_NN_INT8); 33912e714ceSopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, -1, "Set TensorDesc data type failed."); 34012e714ceSopenharmony_ci 34112e714ceSopenharmony_ci returnCode = OH_NNTensorDesc_SetFormat(tensorDesc, OH_NN_FORMAT_NONE); 34212e714ceSopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, -1, "Set TensorDesc format failed."); 34312e714ceSopenharmony_ci 34412e714ceSopenharmony_ci returnCode = OH_NNModel_AddTensorToModel(model, tensorDesc); 34512e714ceSopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, -1, "Add second TensorDesc to model failed."); 34612e714ceSopenharmony_ci 34712e714ceSopenharmony_ci returnCode = OH_NNModel_SetTensorType(model, 2, OH_NN_ADD_ACTIVATIONTYPE); 34812e714ceSopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, -1, "Set model tensor type failed."); 34912e714ceSopenharmony_ci 35012e714ceSopenharmony_ci // 将激活函数类型设置为OH_NNBACKEND_FUSED_NONE,表示该算子不添加激活函数。 35112e714ceSopenharmony_ci int8_t activationValue = OH_NN_FUSED_NONE; 35212e714ceSopenharmony_ci returnCode = OH_NNModel_SetTensorData(model, 2, &activationValue, sizeof(int8_t)); 35312e714ceSopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, -1, "Set model tensor data failed."); 35412e714ceSopenharmony_ci 35512e714ceSopenharmony_ci // 设置Add算子的输出张量,类型为float32,张量形状为[1, 2, 2, 3] 35612e714ceSopenharmony_ci tensorDesc = OH_NNTensorDesc_Create(); 35712e714ceSopenharmony_ci CHECKEQ(tensorDesc, nullptr, -1, "Create TensorDesc failed."); 35812e714ceSopenharmony_ci 35912e714ceSopenharmony_ci returnCode = OH_NNTensorDesc_SetShape(tensorDesc, inputDims, 4); 36012e714ceSopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, -1, "Set TensorDesc shape failed."); 36112e714ceSopenharmony_ci 36212e714ceSopenharmony_ci returnCode = OH_NNTensorDesc_SetDataType(tensorDesc, OH_NN_FLOAT32); 36312e714ceSopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, -1, "Set TensorDesc data type failed."); 36412e714ceSopenharmony_ci 36512e714ceSopenharmony_ci returnCode = OH_NNTensorDesc_SetFormat(tensorDesc, OH_NN_FORMAT_NONE); 36612e714ceSopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, -1, "Set TensorDesc format failed."); 36712e714ceSopenharmony_ci 36812e714ceSopenharmony_ci returnCode = OH_NNModel_AddTensorToModel(model, tensorDesc); 36912e714ceSopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, -1, "Add forth TensorDesc to model failed."); 37012e714ceSopenharmony_ci 37112e714ceSopenharmony_ci returnCode = OH_NNModel_SetTensorType(model, 3, OH_NN_TENSOR); 37212e714ceSopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, -1, "Set model tensor type failed."); 37312e714ceSopenharmony_ci 37412e714ceSopenharmony_ci // 指定Add算子的输入张量、参数张量和输出张量的索引 37512e714ceSopenharmony_ci uint32_t inputIndicesValues[2] = {0, 1}; 37612e714ceSopenharmony_ci uint32_t paramIndicesValues = 2; 37712e714ceSopenharmony_ci uint32_t outputIndicesValues = 3; 37812e714ceSopenharmony_ci OH_NN_UInt32Array paramIndices = {¶mIndicesValues, 1 * 4}; 37912e714ceSopenharmony_ci OH_NN_UInt32Array inputIndices = {inputIndicesValues, 2 * 4}; 38012e714ceSopenharmony_ci OH_NN_UInt32Array outputIndices = {&outputIndicesValues, 1 * 4}; 38112e714ceSopenharmony_ci 38212e714ceSopenharmony_ci // 向模型实例添加Add算子 38312e714ceSopenharmony_ci returnCode = OH_NNModel_AddOperation(model, OH_NN_OPS_ADD, ¶mIndices, &inputIndices, &outputIndices); 38412e714ceSopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, -1, "Add operation to model failed."); 38512e714ceSopenharmony_ci 38612e714ceSopenharmony_ci // 设置模型实例的输入张量、输出张量的索引 38712e714ceSopenharmony_ci returnCode = OH_NNModel_SpecifyInputsAndOutputs(model, &inputIndices, &outputIndices); 38812e714ceSopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, -1, "Specify model inputs and outputs failed."); 38912e714ceSopenharmony_ci 39012e714ceSopenharmony_ci // 完成模型实例的构建 39112e714ceSopenharmony_ci returnCode = OH_NNModel_Finish(model); 39212e714ceSopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, -1, "Build model failed."); 39312e714ceSopenharmony_ci 39412e714ceSopenharmony_ci // 返回模型实例 39512e714ceSopenharmony_ci *pmodel = model; 39612e714ceSopenharmony_ci return OH_NN_SUCCESS; 39712e714ceSopenharmony_ci } 39812e714ceSopenharmony_ci ``` 39912e714ceSopenharmony_ci 40012e714ceSopenharmony_ci5. 查询Neural Network Runtime已经对接的AI加速芯片。 40112e714ceSopenharmony_ci 40212e714ceSopenharmony_ci Neural Network Runtime支持通过HDI接口,对接多种AI加速芯片。在执行模型编译前,需要查询当前设备下,Neural Network Runtime已经对接的AI加速芯片。每个AI加速芯片对应唯一的ID值,在编译阶段需要通过设备ID,指定模型编译的芯片。 40312e714ceSopenharmony_ci ```cpp 40412e714ceSopenharmony_ci void GetAvailableDevices(std::vector<size_t>& availableDevice) 40512e714ceSopenharmony_ci { 40612e714ceSopenharmony_ci availableDevice.clear(); 40712e714ceSopenharmony_ci 40812e714ceSopenharmony_ci // 获取可用的硬件ID 40912e714ceSopenharmony_ci const size_t* devices = nullptr; 41012e714ceSopenharmony_ci uint32_t deviceCount = 0; 41112e714ceSopenharmony_ci OH_NN_ReturnCode ret = OH_NNDevice_GetAllDevicesID(&devices, &deviceCount); 41212e714ceSopenharmony_ci if (ret != OH_NN_SUCCESS) { 41312e714ceSopenharmony_ci std::cout << "GetAllDevicesID failed, get no available device." << std::endl; 41412e714ceSopenharmony_ci return; 41512e714ceSopenharmony_ci } 41612e714ceSopenharmony_ci 41712e714ceSopenharmony_ci for (uint32_t i = 0; i < deviceCount; i++) { 41812e714ceSopenharmony_ci availableDevice.emplace_back(devices[i]); 41912e714ceSopenharmony_ci } 42012e714ceSopenharmony_ci } 42112e714ceSopenharmony_ci ``` 42212e714ceSopenharmony_ci 42312e714ceSopenharmony_ci6. 在指定的设备上编译模型。 42412e714ceSopenharmony_ci 42512e714ceSopenharmony_ci Neural Network Runtime使用抽象的模型表达描述AI模型的拓扑结构。在AI加速芯片上执行前,需要通过Neural Network Runtime提供的编译模块来创建编译实例,并由编译实例将抽象的模型表达下发至芯片驱动层,转换成可以直接推理计算的格式,即模型编译。 42612e714ceSopenharmony_ci ```cpp 42712e714ceSopenharmony_ci OH_NN_ReturnCode CreateCompilation(OH_NNModel* model, const std::vector<size_t>& availableDevice, 42812e714ceSopenharmony_ci OH_NNCompilation** pCompilation) 42912e714ceSopenharmony_ci { 43012e714ceSopenharmony_ci // 创建编译实例compilation,将构图的模型实例或MSLite传下来的模型实例传入 43112e714ceSopenharmony_ci OH_NNCompilation* compilation = OH_NNCompilation_Construct(model); 43212e714ceSopenharmony_ci CHECKEQ(compilation, nullptr, -1, "OH_NNCore_ConstructCompilationWithNNModel failed."); 43312e714ceSopenharmony_ci 43412e714ceSopenharmony_ci // 设置编译的硬件、缓存路径、性能模式、计算优先级、是否开启float16低精度计算等选项 43512e714ceSopenharmony_ci // 选择在第一个设备上编译模型 43612e714ceSopenharmony_ci returnCode = OH_NNCompilation_SetDevice(compilation, availableDevice[0]); 43712e714ceSopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, -1, "OH_NNCompilation_SetDevice failed."); 43812e714ceSopenharmony_ci 43912e714ceSopenharmony_ci // 将模型编译结果缓存在/data/local/tmp目录下,版本号指定为1 44012e714ceSopenharmony_ci returnCode = OH_NNCompilation_SetCache(compilation, "/data/local/tmp", 1); 44112e714ceSopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, -1, "OH_NNCompilation_SetCache failed."); 44212e714ceSopenharmony_ci 44312e714ceSopenharmony_ci // 设置硬件性能模式 44412e714ceSopenharmony_ci returnCode = OH_NNCompilation_SetPerformanceMode(compilation, OH_NN_PERFORMANCE_EXTREME); 44512e714ceSopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, -1, "OH_NNCompilation_SetPerformanceMode failed."); 44612e714ceSopenharmony_ci 44712e714ceSopenharmony_ci // 设置推理执行优先级 44812e714ceSopenharmony_ci returnCode = OH_NNCompilation_SetPriority(compilation, OH_NN_PRIORITY_HIGH); 44912e714ceSopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, -1, "OH_NNCompilation_SetPriority failed."); 45012e714ceSopenharmony_ci 45112e714ceSopenharmony_ci // 是否开启FP16计算模式 45212e714ceSopenharmony_ci returnCode = OH_NNCompilation_EnableFloat16(compilation, false); 45312e714ceSopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, -1, "OH_NNCompilation_EnableFloat16 failed."); 45412e714ceSopenharmony_ci 45512e714ceSopenharmony_ci // 执行模型编译 45612e714ceSopenharmony_ci returnCode = OH_NNCompilation_Build(compilation); 45712e714ceSopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, -1, "OH_NNCompilation_Build failed."); 45812e714ceSopenharmony_ci 45912e714ceSopenharmony_ci *pCompilation = compilation; 46012e714ceSopenharmony_ci return OH_NN_SUCCESS; 46112e714ceSopenharmony_ci } 46212e714ceSopenharmony_ci ``` 46312e714ceSopenharmony_ci 46412e714ceSopenharmony_ci7. 创建执行器。 46512e714ceSopenharmony_ci 46612e714ceSopenharmony_ci 完成模型编译后,需要调用Neural Network Runtime的执行模块,通过编译实例创建执行器。模型推理阶段中的设置模型输入、触发推理计算以及获取模型输出等操作均需要围绕执行器完成。 46712e714ceSopenharmony_ci ```cpp 46812e714ceSopenharmony_ci OH_NNExecutor* CreateExecutor(OH_NNCompilation* compilation) 46912e714ceSopenharmony_ci { 47012e714ceSopenharmony_ci // 通过编译实例compilation创建执行器executor 47112e714ceSopenharmony_ci OH_NNExecutor *executor = OH_NNExecutor_Construct(compilation); 47212e714ceSopenharmony_ci CHECKEQ(executor, nullptr, -1, "OH_NNExecutor_Construct failed."); 47312e714ceSopenharmony_ci return executor; 47412e714ceSopenharmony_ci } 47512e714ceSopenharmony_ci ``` 47612e714ceSopenharmony_ci 47712e714ceSopenharmony_ci8. 执行推理计算,并打印推理结果。 47812e714ceSopenharmony_ci 47912e714ceSopenharmony_ci 通过执行模块提供的接口,将推理计算所需要的输入数据传递给执行器,触发执行器完成一次推理计算,获取模型的推理结果并打印。 48012e714ceSopenharmony_ci ```cpp 48112e714ceSopenharmony_ci OH_NN_ReturnCode Run(OH_NNExecutor* executor, const std::vector<size_t>& availableDevice) 48212e714ceSopenharmony_ci { 48312e714ceSopenharmony_ci // 从executor获取输入输出信息 48412e714ceSopenharmony_ci // 获取输入张量的个数 48512e714ceSopenharmony_ci size_t inputCount = 0; 48612e714ceSopenharmony_ci returnCode = OH_NNExecutor_GetInputCount(executor, &inputCount); 48712e714ceSopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, -1, "OH_NNExecutor_GetInputCount failed."); 48812e714ceSopenharmony_ci std::vector<NN_TensorDesc*> inputTensorDescs; 48912e714ceSopenharmony_ci NN_TensorDesc* tensorDescTmp = nullptr; 49012e714ceSopenharmony_ci for (size_t i = 0; i < inputCount; ++i) { 49112e714ceSopenharmony_ci // 创建输入张量的描述 49212e714ceSopenharmony_ci tensorDescTmp = OH_NNExecutor_CreateInputTensorDesc(executor, i); 49312e714ceSopenharmony_ci CHECKEQ(tensorDescTmp, nullptr, -1, "OH_NNExecutor_CreateInputTensorDesc failed."); 49412e714ceSopenharmony_ci inputTensorDescs.emplace_back(tensorDescTmp); 49512e714ceSopenharmony_ci } 49612e714ceSopenharmony_ci // 获取输出张量的个数 49712e714ceSopenharmony_ci size_t outputCount = 0; 49812e714ceSopenharmony_ci returnCode = OH_NNExecutor_GetOutputCount(executor, &outputCount); 49912e714ceSopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, -1, "OH_NNExecutor_GetOutputCount failed."); 50012e714ceSopenharmony_ci std::vector<NN_TensorDesc*> outputTensorDescs; 50112e714ceSopenharmony_ci for (size_t i = 0; i < outputCount; ++i) { 50212e714ceSopenharmony_ci // 创建输出张量的描述 50312e714ceSopenharmony_ci tensorDescTmp = OH_NNExecutor_CreateOutputTensorDesc(executor, i); 50412e714ceSopenharmony_ci CHECKEQ(tensorDescTmp, nullptr, -1, "OH_NNExecutor_CreateOutputTensorDesc failed."); 50512e714ceSopenharmony_ci outputTensorDescs.emplace_back(tensorDescTmp); 50612e714ceSopenharmony_ci } 50712e714ceSopenharmony_ci 50812e714ceSopenharmony_ci // 创建输入和输出张量 50912e714ceSopenharmony_ci NN_Tensor* inputTensors[inputCount]; 51012e714ceSopenharmony_ci NN_Tensor* tensor = nullptr; 51112e714ceSopenharmony_ci for (size_t i = 0; i < inputCount; ++i) { 51212e714ceSopenharmony_ci tensor = nullptr; 51312e714ceSopenharmony_ci tensor = OH_NNTensor_Create(availableDevice[0], inputTensorDescs[i]); 51412e714ceSopenharmony_ci CHECKEQ(tensor, nullptr, -1, "OH_NNTensor_Create failed."); 51512e714ceSopenharmony_ci inputTensors[i] = tensor; 51612e714ceSopenharmony_ci } 51712e714ceSopenharmony_ci NN_Tensor* outputTensors[outputCount]; 51812e714ceSopenharmony_ci for (size_t i = 0; i < outputCount; ++i) { 51912e714ceSopenharmony_ci tensor = nullptr; 52012e714ceSopenharmony_ci tensor = OH_NNTensor_Create(availableDevice[0], outputTensorDescs[i]); 52112e714ceSopenharmony_ci CHECKEQ(tensor, nullptr, -1, "OH_NNTensor_Create failed."); 52212e714ceSopenharmony_ci outputTensors[i] = tensor; 52312e714ceSopenharmony_ci } 52412e714ceSopenharmony_ci 52512e714ceSopenharmony_ci // 设置输入张量的数据 52612e714ceSopenharmony_ci returnCode = SetInputData(inputTensors, inputCount); 52712e714ceSopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, -1, "SetInputData failed."); 52812e714ceSopenharmony_ci 52912e714ceSopenharmony_ci // 执行推理 53012e714ceSopenharmony_ci returnCode = OH_NNExecutor_RunSync(executor, inputTensors, inputCount, outputTensors, outputCount); 53112e714ceSopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, -1, "OH_NNExecutor_RunSync failed."); 53212e714ceSopenharmony_ci 53312e714ceSopenharmony_ci // 打印输出张量的数据 53412e714ceSopenharmony_ci Print(outputTensors, outputCount); 53512e714ceSopenharmony_ci 53612e714ceSopenharmony_ci // 清理输入和输出张量以及张量描述 53712e714ceSopenharmony_ci for (size_t i = 0; i < inputCount; ++i) { 53812e714ceSopenharmony_ci returnCode = OH_NNTensor_Destroy(&inputTensors[i]); 53912e714ceSopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, -1, "OH_NNTensor_Destroy failed."); 54012e714ceSopenharmony_ci returnCode = OH_NNTensorDesc_Destroy(&inputTensorDescs[i]); 54112e714ceSopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, -1, "OH_NNTensorDesc_Destroy failed."); 54212e714ceSopenharmony_ci } 54312e714ceSopenharmony_ci for (size_t i = 0; i < outputCount; ++i) { 54412e714ceSopenharmony_ci returnCode = OH_NNTensor_Destroy(&outputTensors[i]); 54512e714ceSopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, -1, "OH_NNTensor_Destroy failed."); 54612e714ceSopenharmony_ci returnCode = OH_NNTensorDesc_Destroy(&outputTensorDescs[i]); 54712e714ceSopenharmony_ci CHECKNEQ(returnCode, OH_NN_SUCCESS, -1, "OH_NNTensorDesc_Destroy failed."); 54812e714ceSopenharmony_ci } 54912e714ceSopenharmony_ci 55012e714ceSopenharmony_ci return OH_NN_SUCCESS; 55112e714ceSopenharmony_ci } 55212e714ceSopenharmony_ci ``` 55312e714ceSopenharmony_ci 55412e714ceSopenharmony_ci9. 构建端到端模型构造-编译-执行流程。 55512e714ceSopenharmony_ci 55612e714ceSopenharmony_ci 步骤4-步骤8实现了模型的模型构造、编译和执行流程,并封装成多个函数,便于模块化开发。以下示例代码将串联这些函数, 形成一个完整的Neural Network Runtime使用流程。 55712e714ceSopenharmony_ci ```cpp 55812e714ceSopenharmony_ci int main() 55912e714ceSopenharmony_ci { 56012e714ceSopenharmony_ci OH_NNModel* model = nullptr; 56112e714ceSopenharmony_ci OH_NNCompilation* compilation = nullptr; 56212e714ceSopenharmony_ci OH_NNExecutor* executor = nullptr; 56312e714ceSopenharmony_ci std::vector<size_t> availableDevices; 56412e714ceSopenharmony_ci 56512e714ceSopenharmony_ci // 模型构造 56612e714ceSopenharmony_ci OH_NNModel* model = nullptr; 56712e714ceSopenharmony_ci OH_NN_ReturnCode ret = BuildModel(&model); 56812e714ceSopenharmony_ci if (ret != OH_NN_SUCCESS) { 56912e714ceSopenharmony_ci std::cout << "BuildModel failed." << std::endl; 57012e714ceSopenharmony_ci OH_NNModel_Destroy(&model); 57112e714ceSopenharmony_ci return -1; 57212e714ceSopenharmony_ci } 57312e714ceSopenharmony_ci 57412e714ceSopenharmony_ci // 获取可执行的设备 57512e714ceSopenharmony_ci GetAvailableDevices(availableDevices); 57612e714ceSopenharmony_ci if (availableDevices.empty()) { 57712e714ceSopenharmony_ci std::cout << "No available device." << std::endl; 57812e714ceSopenharmony_ci OH_NNModel_Destroy(&model); 57912e714ceSopenharmony_ci return -1; 58012e714ceSopenharmony_ci } 58112e714ceSopenharmony_ci 58212e714ceSopenharmony_ci // 模型编译 58312e714ceSopenharmony_ci ret = CreateCompilation(model, availableDevices, &compilation); 58412e714ceSopenharmony_ci if (ret != OH_NN_SUCCESS) { 58512e714ceSopenharmony_ci std::cout << "CreateCompilation failed." << std::endl; 58612e714ceSopenharmony_ci OH_NNModel_Destroy(&model); 58712e714ceSopenharmony_ci OH_NNCompilation_Destroy(&compilation); 58812e714ceSopenharmony_ci return -1; 58912e714ceSopenharmony_ci } 59012e714ceSopenharmony_ci 59112e714ceSopenharmony_ci // 销毁模型实例 59212e714ceSopenharmony_ci OH_NNModel_Destroy(&model); 59312e714ceSopenharmony_ci 59412e714ceSopenharmony_ci // 创建模型的推理执行器 59512e714ceSopenharmony_ci executor = CreateExecutor(compilation); 59612e714ceSopenharmony_ci if (executor == nullptr) { 59712e714ceSopenharmony_ci std::cout << "CreateExecutor failed, no executor is created." << std::endl; 59812e714ceSopenharmony_ci OH_NNCompilation_Destroy(&compilation); 59912e714ceSopenharmony_ci return -1; 60012e714ceSopenharmony_ci } 60112e714ceSopenharmony_ci 60212e714ceSopenharmony_ci // 销毁编译实例 60312e714ceSopenharmony_ci OH_NNCompilation_Destroy(&compilation); 60412e714ceSopenharmony_ci 60512e714ceSopenharmony_ci // 使用上一步创建的执行器,执行推理计算 60612e714ceSopenharmony_ci ret = Run(executor, availableDevices); 60712e714ceSopenharmony_ci if (ret != OH_NN_SUCCESS) { 60812e714ceSopenharmony_ci std::cout << "Run failed." << std::endl; 60912e714ceSopenharmony_ci OH_NNExecutor_Destroy(&executor); 61012e714ceSopenharmony_ci return -1; 61112e714ceSopenharmony_ci } 61212e714ceSopenharmony_ci 61312e714ceSopenharmony_ci // 销毁执行器实例 61412e714ceSopenharmony_ci OH_NNExecutor_Destroy(&executor); 61512e714ceSopenharmony_ci 61612e714ceSopenharmony_ci return 0; 61712e714ceSopenharmony_ci } 61812e714ceSopenharmony_ci ``` 61912e714ceSopenharmony_ci 62012e714ceSopenharmony_ci## 调测验证 62112e714ceSopenharmony_ci 62212e714ceSopenharmony_ci1. 准备应用样例的编译配置文件。 62312e714ceSopenharmony_ci 62412e714ceSopenharmony_ci 新建一个 `CMakeLists.txt` 文件,为开发步骤中的应用样例文件 `nnrt_example.cpp` 添加编译配置。以下提供简单的 `CMakeLists.txt` 示例: 62512e714ceSopenharmony_ci ```text 62612e714ceSopenharmony_ci cmake_minimum_required(VERSION 3.16) 62712e714ceSopenharmony_ci project(nnrt_example C CXX) 62812e714ceSopenharmony_ci 62912e714ceSopenharmony_ci add_executable(nnrt_example 63012e714ceSopenharmony_ci ./nnrt_example.cpp 63112e714ceSopenharmony_ci ) 63212e714ceSopenharmony_ci 63312e714ceSopenharmony_ci target_link_libraries(nnrt_example 63412e714ceSopenharmony_ci neural_network_runtime 63512e714ceSopenharmony_ci neural_network_core 63612e714ceSopenharmony_ci ) 63712e714ceSopenharmony_ci ``` 63812e714ceSopenharmony_ci 63912e714ceSopenharmony_ci2. 编译应用样例。 64012e714ceSopenharmony_ci 64112e714ceSopenharmony_ci 执行以下命令,在当前目录下新建build/目录,在build/目录下编译 `nnrt_example.cpp`,得到二进制文件 `nnrt_example`。 64212e714ceSopenharmony_ci ```shell 64312e714ceSopenharmony_ci mkdir build && cd build 64412e714ceSopenharmony_ci cmake -DCMAKE_TOOLCHAIN_FILE={交叉编译工具链的路径}/build/cmake/ohos.toolchain.cmake -DOHOS_ARCH=arm64-v8a -DOHOS_PLATFORM=OHOS -DOHOS_STL=c++_static .. 64512e714ceSopenharmony_ci make 64612e714ceSopenharmony_ci ``` 64712e714ceSopenharmony_ci 64812e714ceSopenharmony_ci3. 执行以下代码,将样例推送到设备上执行。 64912e714ceSopenharmony_ci ```shell 65012e714ceSopenharmony_ci # 将编译得到的 `nnrt_example` 推送到设备上,执行样例。 65112e714ceSopenharmony_ci hdc_std file send ./nnrt_example /data/local/tmp/. 65212e714ceSopenharmony_ci 65312e714ceSopenharmony_ci # 给测试用例可执行文件加上权限。 65412e714ceSopenharmony_ci hdc_std shell "chmod +x /data/local/tmp/nnrt_example" 65512e714ceSopenharmony_ci 65612e714ceSopenharmony_ci # 执行测试用例 65712e714ceSopenharmony_ci hdc_std shell "/data/local/tmp/nnrt_example" 65812e714ceSopenharmony_ci ``` 65912e714ceSopenharmony_ci 66012e714ceSopenharmony_ci 如果样例执行正常,应该得到以下输出。 66112e714ceSopenharmony_ci ```text 66212e714ceSopenharmony_ci Output index: 0, value is: 0.000000. 66312e714ceSopenharmony_ci Output index: 1, value is: 2.000000. 66412e714ceSopenharmony_ci Output index: 2, value is: 4.000000. 66512e714ceSopenharmony_ci Output index: 3, value is: 6.000000. 66612e714ceSopenharmony_ci Output index: 4, value is: 8.000000. 66712e714ceSopenharmony_ci Output index: 5, value is: 10.000000. 66812e714ceSopenharmony_ci Output index: 6, value is: 12.000000. 66912e714ceSopenharmony_ci Output index: 7, value is: 14.000000. 67012e714ceSopenharmony_ci Output index: 8, value is: 16.000000. 67112e714ceSopenharmony_ci Output index: 9, value is: 18.000000. 67212e714ceSopenharmony_ci Output index: 10, value is: 20.000000. 67312e714ceSopenharmony_ci Output index: 11, value is: 22.000000. 67412e714ceSopenharmony_ci ``` 67512e714ceSopenharmony_ci 67612e714ceSopenharmony_ci4. 检查模型缓存(可选)。 67712e714ceSopenharmony_ci 67812e714ceSopenharmony_ci 如果在调测环境下,Neural Network Runtime对接的HDI服务支持模型缓存功能,执行完 `nnrt_example`, 可以在 `/data/local/tmp` 目录下找到生成的缓存文件。 67912e714ceSopenharmony_ci 68012e714ceSopenharmony_ci > **说明:** 68112e714ceSopenharmony_ci > 68212e714ceSopenharmony_ci > 模型的IR需要传递到硬件驱动层,由HDI服务将统一的IR图,编译成硬件专用的计算图,编译的过程非常耗时。Neural Network Runtime支持计算图缓存的特性,可以将HDI服务编译生成的计算图,缓存到设备存储中。当下一次在同一个加速芯片上编译同一个模型时,通过指定缓存的路径,Neural Network Runtime可以直接加载缓存文件中的计算图,减少编译消耗的时间。 68312e714ceSopenharmony_ci 68412e714ceSopenharmony_ci 检查缓存目录下的缓存文件: 68512e714ceSopenharmony_ci ```shell 68612e714ceSopenharmony_ci ls /data/local/tmp 68712e714ceSopenharmony_ci ``` 68812e714ceSopenharmony_ci 68912e714ceSopenharmony_ci 以下为打印结果: 69012e714ceSopenharmony_ci ```text 69112e714ceSopenharmony_ci # 0.nncache 1.nncache 2.nncache cache_info.nncache 69212e714ceSopenharmony_ci ``` 69312e714ceSopenharmony_ci 69412e714ceSopenharmony_ci 如果缓存不再使用,需要手动删除缓存,可以参考以下命令,删除缓存文件。 69512e714ceSopenharmony_ci ```shell 69612e714ceSopenharmony_ci rm /data/local/tmp/*nncache 69712e714ceSopenharmony_ci ```