捕获与执行实战:基于 0_simple_model 样例解析)
CANN Runtime 模型运行实例modelRI捕获与执行实战基于 0_simple_model 样例解析【免费下载链接】runtime本项目提供CANN运行时组件和维测功能组件。项目地址: https://gitcode.com/cann/runtime导读本文以 CANN runtime 仓库中的0_simple_model样例为核心讲解如何通过 AscendCL 的模型运行实例Model Runtime Instance简称 modelRI能力将 Stream 上的一段任务序列捕获为一个可复用的模型实例随后通过该实例反复异步执行推理。读完本文你将掌握aclmdlRICaptureBegin/aclmdlRICaptureEnd捕获流程、三种捕获模式GLOBAL / THREAD_LOCAL / RELAXED的差异与切换方法、aclmdlRIDebugJsonPrint维测导出手段以及完整的样例编译运行与结果验证方式。一、背景为什么需要捕获 Stream 任务在典型的 AscendCL 编程模型中开发者把算子、内存拷贝等任务依次下发到 Stream 上由 Runtime 异步调度执行。但当一段“运算序列”需要被反复执行例如推理循环中的同一组算子时每次执行都要重新下发一遍任务、重新做参数封装开销与代码量都不小。modelRI 提供了一种“先捕获、后执行”的编程范式将 Stream 置于捕获模式期间下发到该 Stream 上的任务内存拷贝、aclnn 算子等不再直接执行而是被记录下来结束捕获后得到一个aclmdlRI模型运行实例句柄后续通过aclmdlRIExecuteAsync即可反复提交整段任务序列。从源码结构看modelRI 的捕获与执行实现位于 src/runtime/feature/aclgraph/ 目录如 capture_model_utils.cc属于 Runtime 的 ACL Graph 特性族。本仓库 example/2_advanced_features/model_ri/README.md 将 modelRI 相关样例统一归类为“模型运行实例的捕获、更新与切换”其中0_simple_model是最基础的入门样例。二、样例功能概览与产品支持0_simple_model样例完成了一个典型的“捕获—执行—校验”闭环捕获阶段在 Stream 上捕获一次 H2D 异步拷贝、一个 add 算子、一个 mul 算子构成一段任务序列执行阶段循环 4 次异步执行捕获得到的 modelRI每次执行后同步 Stream 并回拷结果校验资源回收销毁 modelRI、Stream、Context并复位 Device。产品支持情况产品是否支持Ascend 950PR / Ascend 950DT√Atlas A3 训练系列产品 / Atlas A3 推理系列产品√Atlas A2 训练系列产品 / Atlas A2 推理系列产品√注以上支持矩阵以样例目录 README.md 原文为准请在目标硬件上以实际运行结果为准。三、编译与运行3.1 环境准备环境安装详情与运行详情请参见 example 目录总 README。运行前需要完成 CANN 软件包安装并确保环境变量可用。样例中的 run.sh 依赖ASCEND_INSTALL_PATH环境变量定位 CANN 安装目录。3.2 运行步骤# ${install_root} 替换为 CANN 安装根目录默认安装在 /usr/local/Ascend 目录 source ${install_root}/cann/set_env.sh # 自动识别 SOC_VERSION 和 ASCENDC_CMAKE_DIR source ${git_clone_path}/example/set_sample_env.sh # 编译运行 bash run.sh其中set_env.sh用于加载 CANN 运行环境LD 路径、工具链等example/set_sample_env.sh 用于根据当前环境自动识别SOC_VERSION与ASCENDC_CMAKE_DIR供 CMake 构建使用run.sh内部完成清理并创建build目录 →cmake -B build配置构建传入ASCEND_CANN_PACKAGE_PATH→cmake --build build -j编译 →cmake --install build安装到out目录 → 运行./build/main并将输出同时写入output_msg.txt。3.3 构建配置解读CMakeLists.txt 展示了样例的依赖关系可供自研工程参考依赖头文件目录${ASCEND_CANN_PACKAGE_PATH}/includeAscendCL 头文件、${ASCEND_CANN_PACKAGE_PATH}/aclnnaclnn 算子头文件以及仓库内example公共头文件目录链接库libascendcl.soAscendCL 运行时、libnnopbase.so算子底座、libopapi.so算子 API 封装源文件main.cpp加上公共工具 model_utils.cpp。四、程序主流程逐段解析样例入口在 main.cpp。下面按执行顺序拆解。4.1 初始化与资源准备CHECK_ERROR(aclInit(NULL)); CHECK_ERROR(aclrtSetDevice(deviceId)); CHECK_ERROR(aclrtCreateContext(context, deviceId));aclInit(NULL)初始化 AscendCL 配置aclrtSetDevice(deviceId)指定参与运算的 Device样例中为 0 号aclrtCreateContext(context, deviceId)在指定 Device 上创建 Context作为后续算子执行与内存管理的运行上下文。4.2 构建张量与算子执行器样例通过公共工具 model_utils.cpp 中的ModelUtils::CreateAclTensor创建aclTensor其内部先aclrtMalloc申请 Device 内存再按连续 ND 布局计算 stride最后调用aclCreateTensor将 shape、stride、format、地址绑定成一个张量描述。样例构造了 4 个4x2的 float 张量并准备两个算子// outTmp self other * alpha aclnnAddGetWorkspaceSize(self, other, alpha, outTmp, addWorkspaceSize, addExecutor); // out outTmp * other aclnnMulGetWorkspaceSize(outTmp, other, out, mulWorkspaceSize, mulExecutor);aclnn*GetWorkspaceSize会返回算子所需的 workspace 大小与执行器句柄。样例根据返回大小通过aclrtMalloc申请ACL_MEM_MALLOC_HUGE_FIRST内存供后续算子执行使用。整体计算的模型语义为out (self other * alpha) * other输入数据self {1..8}other {2,2,...}alpha 1.1则预期输出out (self 2.2) * 2即{6.4, 8.4, ..., 20.4}。4.3 创建 Stream 与 Host 数据aclrtCreateStream(stream); // 创建 Stream作为捕获与执行的载体 aclrtMallocHost(selfHost, size); // 申请 Host 锁页内存 aclrtMemcpy(selfHost, size, selfHostData.data(), size, ACL_MEMCPY_HOST_TO_HOST);样例先把self的输入数据准备好到 Host 锁页内存供捕获阶段入图。锁页内存pinned memory可避免 DMA 搬运时的页换出是 Host↔Device 高效拷贝的常用手段。五、核心捕获模式与模型实例创建5.1 开始捕获aclmdlRICaptureBeginCHECK_ERROR(aclmdlRICaptureBegin(stream, ACL_MODEL_RI_CAPTURE_MODE_GLOBAL));接口定义位于 include/external/acl/acl_rt.haclmdlRICaptureBegin(aclrtStream stream, aclmdlRICaptureMode mode)将指定 Stream 置于捕获模式。其后的任务不再直接执行而是记录为 modelRI 的任务序列。捕获模式由枚举aclmdlRICaptureMode描述acl_rt.h枚举值说明ACL_MODEL_RI_CAPTURE_MODE_GLOBAL 0全局捕获模式期间禁止调用非安全函数如同步内存拷贝安全函数如aclrtMemcpyAsync可正常下发并入图ACL_MODEL_RI_CAPTURE_MODE_THREAD_LOCAL线程局部捕获模式用于多线程捕获场景ACL_MODEL_RI_CAPTURE_MODE_RELAXED宽松模式允许调用非安全函数这些调用不会入图、直接执行5.2 捕获期间的任务下发// 异步复制为安全函数在 GLOBAL 模式下可调用该函数会入图 CHECK_ERROR(aclrtMemcpyAsync(selfDevice, size, selfHost, size, ACL_MEMCPY_HOST_TO_DEVICE, stream)); aclmdlRICaptureMode mode ACL_MODEL_RI_CAPTURE_MODE_RELAXED; // 切换到 RELAXED执行非安全函数 CHECK_ERROR(aclmdlRICaptureThreadExchangeMode(mode)); // 同步复制为非安全函数RELAXED 下直接执行、不会入图 CHECK_ERROR(aclrtMemcpy(otherDevice, size, otherHostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE)); // 再次调用恢复为上次设置的 ModeGLOBAL CHECK_ERROR(aclmdlRICaptureThreadExchangeMode(mode)); // 调用 aclnn 算子会入图 aclnnAdd(addWorkspaceAddr, addWorkspaceSize, addExecutor, stream); aclnnMul(mulWorkspaceAddr, mulWorkspaceSize, mulExecutor, stream);这一段同时演示了两种重要的行为约束安全函数入图aclrtMemcpyAsync属于可捕获的安全异步函数在 GLOBAL 模式下被记录进模型任务序列模式临时切换aclmdlRICaptureThreadExchangeMode(aclmdlRICaptureMode* mode)声明见 acl_rt.h是 IN/OUT 参数——传入期望切换到的模式返回上一次的模式。样例第一次调用把 GLOBAL 换成 RELAXED执行同步拷贝不入图、立即执行第二次调用再传入 RELAXED则恢复到上一次保存的 GLOBAL随后下发的两个 aclnn 算子继续入图。5.3 结束捕获aclmdlRICaptureEndCHECK_ERROR(aclmdlRICaptureEnd(stream, modelRI));接口定义见 acl_rt.h结束 Stream 捕获并输出aclmdlRI句柄。至此modelRI封装了“一次异步 H2D 拷贝 add 算子 mul 算子”的完整任务序列且入图参数与地址均已固化。补充运行期还可以用aclmdlRICaptureGetInfoacl_rt.h查询 Stream 当前的捕获状态aclmdlRICaptureStatusNONE / ACTIVE / INVALIDATED见 acl_rt.h用于判断捕获是否正在进行或被无效化。六、维测以 JSON 导出模型信息const char* jsonPath ./modelRI.json; CHECK_ERROR(aclmdlRIDebugJsonPrint(modelRI, jsonPath, 0));aclmdlRIDebugJsonPrint(aclmdlRI modelRI, const char* path, uint32_t flags)acl_rt.h将模型运行实例的结构化信息以 JSON 格式导出到指定文件便于维测排查。flags 取值acl_rt.h宏值含义ACL_MDLRI_DEBUG_JSON_PRINT_SUMMARY0x0导出摘要信息ACL_MDLRI_DEBUG_JSON_PRINT_VERBOSE0x1导出详细信息运行后可在样例工作目录生成modelRI.json其中包含捕获到的任务列表、参数等可直接打开检查模型实例是否符合预期。需要说明的是旧接口aclmdlRIDebugPrint已被标记为 deprecated见 acl_rt.h推荐统一使用 JSON 版本。七、循环执行与结果校验for (int i 0; i loopCount; i) { INFO_LOG(execute model, loop count: %d., i 1); CHECK_ERROR(aclmdlRIExecuteAsync(modelRI, stream)); // 异步执行模型实例 CHECK_ERROR(aclrtSynchronizeStream(stream)); // 阻塞等待任务完成 CHECK_ERROR(aclrtMemcpy(outHostData.data(), size, outDevice, size, ACL_MEMCPY_DEVICE_TO_HOST)); ModelUtils::PrintArray(outHostData); // 打印结果 }aclmdlRIExecuteAsync(modelRI, stream)acl_rt.h在指定 Stream 上异步提交 modelRI 的整段任务序列不阻塞主线程aclrtSynchronizeStream(stream)阻塞等待 Stream 上任务全部完成保证后续 D2H 回拷读到的是最终结果D2H 拷贝后将结果拷回 Host 并打印用于逐次校验执行正确性。样例输出如下[INFO] execute model, loop count: 1. [INFO] The vector data is: 6.4000 8.4000 10.4000 12.4000 14.4000 16.4000 18.4000 20.4000 ... [INFO] execute model, loop count: 4. [INFO] The vector data is: 6.4000 8.4000 10.4000 12.4000 14.4000 16.4000 18.4000 20.40004 次执行结果完全一致且符合理论值(self 2.2) * 2说明捕获的模型实例可稳定重复执行。八、资源释放与收尾CHECK_ERROR(aclmdlRIDestroy(modelRI)); // 销毁模型运行实例 CHECK_ERROR(aclrtDestroyStreamForce(stream)); // 强制销毁 Stream丢弃所有任务 // ... aclDestroyTensor / aclDestroyScalar / aclrtFree 释放张量、标量与 Device 内存 ... CHECK_ERROR(aclrtDestroyContext(context)); // 销毁 Context CHECK_ERROR(aclrtResetDeviceForce(deviceId)); // 强制复位 Device回收资源 CHECK_ERROR(aclFinalize()); // AscendCL 去初始化资源释放顺序与创建顺序相反遵循“先建后销”的原则。其中aclrtDestroyStreamForce强制销毁 Stream 并丢弃其上未执行完的任务适用于捕获场景下任务已被模型实例固化的情形aclrtResetDeviceForce强制复位当前 Device回收 Device 上全部资源aclFinalize完成 AscendCL 去初始化释放全局资源。九、总结与后续进阶0_simple_model完整演示了 modelRI 的“捕获—执行—销毁”生命周期关键要点如下捕获aclmdlRICaptureBegin开启捕获期间安全异步任务入图非安全同步调用需通过aclmdlRICaptureThreadExchangeMode临时切换到 RELAXED 模式执行aclmdlRICaptureEnd得到aclmdlRI句柄aclmdlRIExecuteAsync可反复异步执行维测aclmdlRIDebugJsonPrint导出 JSON 便于检查模型结构释放aclmdlRIDestroy销毁实例再按逆序释放 Stream、张量、内存、Context 并复位 Device。如需进一步探索 modelRI 的进阶能力本仓库 model_ri 系列还提供了1_model_update通过aclmdlRICaptureTaskGrpBegin/End与aclmdlRICaptureTaskUpdateBegin/End对已捕获实例进行任务更新2_model_switch模型运行实例中的 Stream 绑定、跳转与切换3_cond_modelIF/WHILE/SWITCH 条件操作的图捕获与执行4_model_sync_external跨边界同步场景下 Event 的 Record External / Wait External5_reusable_buffer_reset枚举并复用异步清零模型的 Stream/Task 结构。对应的 modelRI 全量接口声明含任务组、Stream 绑定、条件任务、属性查询等可在 include/external/acl/acl_rt.h 中以aclmdlRI前缀检索。【免费下载链接】runtime本项目提供CANN运行时组件和维测功能组件。项目地址: https://gitcode.com/cann/runtime创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考