异步执行Graph
本章节给出使用异步执行接口,并使用Device内存运行Graph的示例。
功能介绍
Atlas 200/300/500 推理产品、Atlas 200/500 A2推理产品不支持该特性。
构建完Graph之后,如果您希望编译并异步运行Graph,得到图的执行结果,可以参考本节内容。涉及的主要接口为:
- 调用GEInitialize进行系统初始化(也可在Graph构建前调用),申请系统资源。
- 调用Session构造函数创建Session类对象,申请Session资源。
- 调用AddGraph在Session类对象中添加定义好的图。
- 调用aclInit接口,初始化AscendCL。
- 调用BuildGraph编译图。
- 调用AscendCL aclrtSetDevice指定运行的Device,调用aclrtCreateStream创建stream,然后调用aclrtMallocHost、aclrtMalloc分别申请Host和Device内存。
- 调用RunGraphWithStreamAsync异步执行接口,运行Graph。
- 调用aclrtSynchronizeStream阻塞程序运行,直到指定Stream中的所有任务都完成。
- 调用aclrtFree、aclrtFreeHost释放内存;调用GEFinalize,释放系统资源;调用aclFinalize释放AscendCL相关资源。
开发示例
- 包含的头文件,包括AscendCL、C或C++标准库的头文件。
1 2 3
#include "ge_api.h" #include "acl.h" #include "acl_rt.h"
- 申请系统资源。
Graph定义完成后,调用GEInitialize进行系统初始化(也可在Graph定义前调用),申请系统资源。示例代码如下:
1 2 3
std::map<AscendString, AscendString>config = {{"ge.exec.deviceId", "0"}, {"ge.graphRunMode", "1"}}; Status ret = ge::GEInitialize(config);
可以通过config配置传入ge运行的初始化信息,当前必选的配置参数为示例代码中的ge.exec.deviceId和ge.graphRunMode,分别用于指定GE实例运行设备,图执行模式(在线推理请配置为0,训练请配置为1)。更多配置请参考options参数说明。
GE options中的dump信息,与后续调用AscendCL初始化接口时配置的dump信息,建议两者不要同时配置,否则可能导致异常。
- 添加Graph对象并运行Graph。
若想使定义好的Graph运行起来,首先,要创建一个session对象,然后调用AddGraph接口添加图。示例代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
std::map <AscendString, AscendString> options; ge::Session *session = new Session(options); if(session == nullptr) { std::cout << "Create session failed." << std::endl; ... ... //释放资源 ge::GEFinalize(); return FAILED; } Status ret = session->AddGraph(conv_graph_id, conv_graph); if(ret != SUCCESS) { ... ... //释放资源 ge::GEFinalize(); delete session; return FAILED; }
用户可以通过传入options配置图运行相关配置信息,相关配置请参考Session构造函数。其中图运行完之后的数据保存在Tensor output_cov中。
- AscendCL资源初始化。
1 2 3 4 5
aclError retInit = aclInit(aclConfigPath); if (retInit != ACL_ERROR_NONE) { ... ... return FAILED;
- 编译Graph。
1 2 3 4 5 6 7 8 9
ret = session->BuildGraph(graph_id, input); if(ret != SUCCESS) { ... ... //释放资源 ge::GEFinalize(); delete session; return FAILED; }
- 指定运行的Device,创建Stream,申请内存。
//指定用于运算的Device int32_t deviceId = 0; retInit = aclrtSetDevice(deviceId); //创建一个Stream aclrtStream stream = nullptr; aclError aclRet = aclrtCreateStream(&stream); //申请Host上内存 void* hostPtrA = NULL; aclRet = aclrtMallocHost(&hostPtrA, size); //申请Device上的内存 void* devPtrB = NULL; aclRet = aclrtMalloc(&devPtrB, size, ACL_MEM_MALLOC_NORMAL_ONLY); //内存复制,将Host上数据传输到Device //hostPtrA表示Host上源内存地址指针,devPtrB表示Device上目的内存地址指针,size表示内存大小 aclrtMemcpy(devPtrB, size, hostPtrA, size, ACL_MEMCPY_HOST_TO_DEVICE);
- 异步执行Graph,输出执行结果。
ret = session->RunGraphWithStreamAsync(graph_id, stream, input, output); //调用aclrtSynchronizeStream接口,阻塞应用程序运行,直到指定Stream中的所有任务都完成 aclRet = aclrtSynchronizeStream(stream); // 内存复制,将Device数据传回Host //devPtrA表示Device上源内存地址指针,hostPtrB表示Host上目的内存地址指针,size表示内存大小 aclrtMemcpy(hostPtrB, size, devPtrA, size, ACL_MEMCPY_DEVICE_TO_HOST);
- 释放资源。
1 2 3 4 5 6 7
//释放内存 ret = aclrtFree(devPtrB); ret = aclrtFreeHost(hostPtrA); //释放Graph资源 ret = ge::GEFinalize(); //AscendCL去初始化 ret = aclFinalize();
父主题: 编译并运行Graph