图编译和图执行
单算子模型执行是指基于图IR执行算子,先编译算子(例如,使用OMG工具将Ascend IR定义的单算子描述文件编译成算子omc模型文件),再调用模型加载推理接口执行单算子网络。下文仅提供单算子模型执行的样例和基础内容讲解,详细内容请参考端侧部署章节。
HarmonyOS Next暂不支持图编译与图执行,仅支持通过AI框架算子适配方式集成自定义算子,以下步骤仅供参考。
环境要求
-
已参考环境准备,完成DDK驱动和软件的安装,配置DDK软件所需基本环境变量。
安装DDK软件后,使用DDK运行开发者进行编译、运行时,需要以DDK运行开发者登录环境,执行source ${install_path}/ddk/tools/tools_ascendc/set_ascendc_env.sh命令设置环境变量。其中${install_path}为DDK软件的安装目录,例如:/home。
-
已参考完成算子的开发和部署。
准备验证代码工程
在执行NPU调试命令时,例如:
ascendebug kernel --backend npu --chip-version kirin9020 --repo-type customize --json-file ./temp.json --core-type AiCore
命令行参数详见NPU调测参数,会在${debug_workspace} /${op_type} /npu/src下生成验证样例工程,代码工程目录结构如下。
src
├── BuildIRGraph.cpp // 生成单算子图源文件
├── BuildIRGraph.h // 单算子图入口:CreateCustomIRGraph
├── build.sh // omc 模型编译脚本
├── CMakeLists.txt
├── custom_graph.omc // 编译后得到的omc模型
└── op_proto.h // 算子编译输出的算子原型定义头文件
生成单算子离线模型文件
执行验证样例工程下的build.sh。
./build.sh
以上命令执行后,会在当前路径下生成custom_graph.omc的离线模型文件。
生成输入数据
在样例工程目录下,执行如下命令:
python3 scripts/gen_data.py
会在input目录下生成两个shape为(8,2048),数据类型为float16的数据文件input_0.bin与input_1.bin,用于进行AddCustom算子的验证。
代码样例如下。
import numpy as np
a = np.random.randint(100, size=(8, 2048,)).astype(np.float16)
b = np.random.randint(100, size=(8, 2048,)).astype(np.float16)
a.tofile('input_0.bin')
b.tofile('input_1.bin')
APP集成代码
开发者可以参考如下样例编写模型加载、执行的代码逻辑。完整集成流程请参考应用开发。
以下是关键步骤的代码示例,不可以直接拷贝编译运行,仅供参考,调用接口后,需增加异常处理的分支,并记录报错日志、提示日志,此处不一一列举。
int RunModel(void* modelData, size_t modelSize)
{
// 1.加载omc模型
auto modelDescV1 = std::make_shared<hiai::AiModelDescription>("model", 3, 0, 0, 0);
modelDescV1->SetModelBuffer(modelData, modelSize);
std::vector<std::shared_ptr<hiai::AiModelDescription>> modelDescVec;
modelDescVec.push_back(modelDescV1);
auto clientV1 = std::make_shared<hiai::AiModelMngerClient>();
if (clientV1->Init(nullptr) != hiai::SUCCESS) {
LOGE("client Init() failed.");
return FAILURE;
}
if (clientV1->Load(modelDescVec) != hiai::SUCCESS) {
LOGE("client Load() failed.");
return FAILURE;
}
LOGI("load model success");
std::vector<hiai::TensorDimension> inDimVecV1;
std::vector<hiai::TensorDimension> outDimVecV1;
std::vector<std::shared_ptr<hiai::AiTensor>> inTensorVecV1;
std::vector<std::shared_ptr<hiai::AiTensor>> outTensorVecV1;
if (clientV1->GetModelIOTensorDim(modelDescV1->GetName(), inDimVecV1, outDimVecV1) != hiai::SUCCESS) {
LOGE("client GetModelIOTensorDim() failed.");
clientV1->UnLoadModel();
return FAILURE;
}
// 2、设置模型输入、输出
for (size_t i = 0; i < INPUT_NUM && i < inDimVecV1.size(); ++i) {
void *data = nullptr;
size_t size = 0;
LOGI("open input file inputFile: %s ", INPUT_LIST[i].c_str());
if (!ReadData(INPUT_LIST[i], &data, size)) {
LOGE("open input file failed! inputFile: %s ", INPUT_LIST[i].c_str());
clientV1->UnLoadModel();
return FAILURE;
}
auto inputV1 = std::make_shared<hiai::AiTensor>();
inputV1->Init(&inDimVecV1[i], INPUT_TYPE);
if (inputV1->GetSize() != size) {
LOGE("inputSize: %d != fileSize: %zu ", inputV1->GetSize(), size);
clientV1->UnLoadModel();
free(data);
data = nullptr;
return FAILURE;
}
memcpy(inputV1->GetBuffer(), data, size);
inTensorVecV1.push_back(inputV1);
free(data);
data = nullptr;
}
LOGI("load input success");
for (size_t i = 0; i < outDimVecV1.size(); i++) {
auto outputV1 = std::make_shared<hiai::AiTensor>();
outputV1->Init(&outDimVecV1[i], OUTPUT_TYPE);
outTensorVecV1.push_back(outputV1);
}
LOGI("init output success");
// 3、进行模型推理
hiai::AiContext context;
context.AddPara("model_name", "model");
int32_t istamp = 0;
auto retCode = clientV1->Process(context, inTensorVecV1, outTensorVecV1, 1000, istamp);
if (retCode != hiai::SUCCESS) {
LOGE("process failed.");
clientV1->UnLoadModel();
return retCode;
}
LOGI("process success");
for (size_t i = 0; i < outTensorVecV1.size(); i++) {
char* data = reinterpret_cast<char*>(outTensorVecV1[i]->GetBuffer());
DumpBufferToFile(data, outTensorVecV1[i]->GetSize(), OUTPUT_PATH);
}
LOGI("dump output success");
// 4、模型卸载
clientV1->UnLoadModel();
return retCode;
}