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!["Add单算子网络示意图"](figures/02.png)
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 = {&paramIndicesValues, 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, &paramIndices, &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