新闻详情

新闻详情

首页 / 资讯中心 / 详情

CANN ops-math 中 aclnnComplex 算子详解:用实部与虚部张量构造复数

发布时间:2026/9/20 17:11:32来源:尧图网络
CANN ops-math 中 aclnnComplex 算子详解:用实部与虚部张量构造复数
算子库人工智能CANN【免费下载链接】ops-math本项目是CANN提供的数学类基础计算算子库实现网络在NPU上加速计算。项目地址https://gitcode.com/cann/ops-math点击查看免费下载本篇技术指南围绕 CANN 数学算子库 ops-math 中Complex算子的 aclnn 两层接口展开完整讲解aclnnComplex/aclnnComplexGetWorkspaceSize的函数原型、参数约束、返回码、平台支持情况与调用示例并结合仓库源码aclnn_complex.cpp剖析其入参校验、广播推导与 kernel 分发机制。读完本文你将掌握如何在 NPU 上通过两个实数 Tensor 构造复数 Tensor并能独立编写、编译和运行基于两段式接口的 aclnn 调用程序。一、功能说明从实部、虚部到复数aclnnComplex是 CANN ops-math 提供的数学类基础算子接口用于将实部 Tensor与虚部 Tensor组合成一个复数 Tensor。接口功能要求输入两个 Shape 满足 broadcast 关系、Dtype 一致的 Tensor逐元素生成复数输出。其计算公式为$$ \text{out}[i] \text{real}[i] \text{imag}[i]\times \mathrm{j} $$其中 $\mathrm{j}$ 为虚数单位real代表复数的实部imag代表复数的虚部out为复数类型输出。该算子的官方功能说明与公式定义见 math/complex/docs/aclnnComplex.md其 aclnn 接口的对外声明位于 aclnn_complex.h接口实现位于 aclnn_complex.cpp。数据类型映射关系输入实部/虚部与输出复数的数据类型存在严格的一一对应关系输入 Dtypereal / imag输出 DtypeoutFLOATCOMPLEX64FLOAT16COMPLEX32DOUBLECOMPLEX128这一映射关系在源码中有明确体现。aclnn_complex.cpp 中定义了DTYPE_PAIRstatic const std::initializer_liststd::pairop::DataType, op::DataType DTYPE_PAIR { {DataType::DT_FLOAT16, DataType::DT_COMPLEX32}, {DataType::DT_FLOAT, DataType::DT_COMPLEX64}, {DataType::DT_DOUBLE, DataType::DT_COMPLEX128} };同时第一段接口在入参校验阶段会强制校验该配对关系见CheckDtypeValid若 real 为 FLOAT 而 out 为 COMPLEX128 等不配对组合将直接返回参数非法错误。二、产品支持情况依据官方文档aclnnComplex在不同硬件平台上的支持情况如下产品型号支持情况Ascend 950PR / Ascend 950DT支持Atlas A3 训练系列产品 / Atlas A3 推理系列产品支持Atlas A2 训练系列产品 / Atlas A2 推理系列产品支持Atlas 200I/500 A2 推理产品不支持Atlas 推理系列产品支持Atlas 训练系列产品支持此外针对 Atlas A3 训练/推理系列产品与 Ascend 950PR/950DT官方文档明确 out 的数据类型支持 COMPLEX64输入只能是 FLOAT、COMPLEX32输入只能是 FLOAT16、COMPLEX128输入只能是 DOUBLE。从源码结构可以进一步印证平台差异算子的 AICore 配置在 complex_def.cpp 中通过OpAICoreConfig仅注册了ascend950平台并将DynamicShapeSupportFlag、DynamicRankSupportFlag置为 true表明 950 平台走动态 shape/rank 的 AICore 执行路径而 complex.cpp 中针对不同 SoC 版本定义了不同的 AICore dtype 支持列表如 910B 支持 FLOAT/FLOAT16950 支持 FLOAT/FLOAT16不满足条件时则回退到 AICPUtf_kernel路径。三、两段式接口与函数原型与 CANN aclnn 体系一致aclnnComplex采用两段式接口设计必须先调用aclnnComplexGetWorkspaceSize获取计算所需的 workspace 大小以及包含算子计算流程的执行器executor再调用aclnnComplex执行计算。第一段接口原型aclnnStatus aclnnComplexGetWorkspaceSize( const aclTensor* real, const aclTensor* imag, aclTensor* out, uint64_t* workspaceSize, aclOpExecutor** executor)第二段接口原型aclnnStatus aclnnComplex( void* workspace, uint64_t workspaceSize, aclOpExecutor* executor, aclrtStream stream)两段接口的详细声明同样可以在头文件 aclnn_complex.h 中查阅其中标注了参数类型、所属域aclnn_math与基本约束。四、aclnnComplexGetWorkspaceSize 参数说明第一段接口负责入参校验、构建算子计算流程并返回 workspace 大小其参数说明如下参数名输入/输出描述使用说明数据类型数据格式维度(shape)非连续Tensorreal (aclTensor*)输入公式中的输入 real代表复数的实部shape 需要与 imag 满足 broadcast 关系FLOAT、FLOAT16、DOUBLEND-√imag (aclTensor*)输入公式中的输入 imag代表复数的虚部shape 需要与 real 满足 broadcast 关系FLOAT、FLOAT16、DOUBLEND-√out (aclTensor*)输出公式中的 out复数类型的 Tensorshape 需要是 real 与 imag broadcast 之后的 shapeCOMPLEX64、COMPLEX32、COMPLEX128ND-√workspaceSize (uint64_t*)输出返回需要在 Device 侧申请的 workspace 大小-----executor (aclOpExecutor**)输出返回 op 执行器包含了算子计算流程-----注意参数表中非连续 Tensor一栏为 √表示 real、imag、out 均支持非连续 Tensor 输入数据格式为 ND。从实现层面看aclnn_complex.cpp 中第一段接口的执行流程为创建OpExecutorCREATE_EXECUTOR()通过CheckNotNull校验 real、imag、out 三个指针非空处理空 Tensor 场景若 real 或 imag 为空直接返回workspaceSize 0并成功退出通过CheckParams完成 dtype、shape/广播、format 校验分别用l0op::Contiguous将 real、imag 转为连续 Tensor调用l0op::Complex构建计算节点用l0op::ViewCopy将计算结果写入 out兼容非连续 out通过GetWorkspaceSize汇总返回 workspace 大小。返回值与入参校验错误码aclnnStatus返回状态码的具体含义参见 aclnn 返回码。第一段接口完成入参校验出现以下场景时报错返回码错误码描述ACLNN_ERR_PARAM_NULLPTR161001传入的 real、imag 或 out 是空指针ACLNN_ERR_PARAM_INVALID161002real 和 imag 的数据类型和数据格式不在支持的范围之内ACLNN_ERR_PARAM_INVALID161002real 和 imag 的 shape 无法做 broadcastACLNN_ERR_PARAM_INVALID161002real 和 imag 的维度大于 8ACLNN_ERR_PARAM_INVALID161002real 和 imag 的数据类型不一样上述校验逻辑在源码中均有对应实现空指针检查CheckNotNullaclnn_complex.cppdtype 支持范围、real/imag dtype 一致性、输入输出 dtype 配对CheckDtypeValidaclnn_complex.cpp最大维度8 维与广播推断、out shape 一致性CheckOutShapeaclnn_complex.cpp其中MAX_DIM 8通过OP_CHECK_BROADCAST_AND_INFER_SHAPE完成广播 shape 推导format 校验CheckFormataclnn_complex.cpp要求 real、imag、out 三者 format 一致且为非私有格式ND 系列该检查仅在 Ascend 950 平台上生效见CheckParams中GetCurrentPlatformInfo().GetSocVersion() SocVersion::ASCEND950分支。五、aclnnComplex 参数说明第二段接口执行实际计算参数说明如下参数名输入/输出描述workspace输入在 Device 侧申请的 workspace 内存地址workspaceSize输入在 Device 侧申请的 workspace 大小由第一段接口 aclnnComplexGetWorkspaceSize 获取executor输入op 执行器包含了算子计算流程stream输入指定执行任务的 Stream返回值为aclnnStatus状态码具体参见 aclnn 返回码。实现上第二段接口直接调用框架统一的执行入口CommonOpExecutorRun(workspace, workspaceSize, executor, stream)见 aclnn_complex.cpp由框架完成计算调度。六、约束说明确定性计算aclnnComplex默认采用确定性实现即相同输入在相同环境下多次执行结果可复现。关于确定性计算的更多背景可参考 确定性计算说明。七、源码级实现原理7.1 算子定义与注册算子通过 complex_def.cpp 完成 OpDef 注册输入real、imagFLOAT/FLOAT16ND 格式必选输出outCOMPLEX64/COMPLEX32ND 格式属性Tout可选Int默认 0。同时该文件为 AICore 配置了ascend950平台并开启动态 shape、动态 rank 支持。7.2 底层 L0 接口与执行路径选择l0op::Complex见 complex.cpp内部首先通过BroadcastInferShape推导广播后的输出 shape再按输入 dtype 推导输出 dtypeFLOAT16 → COMPLEX32否则默认 COMPLEX64最后根据平台与 dtype 选择执行路径IsAiCoreSupport返回 true 时走ComplexAiCoreAICore kernel通过ADD_TO_LAUNCHER_LIST_AICORE加入任务队列否则走ComplexAiCpuAICPU tf_kernel通过ADD_TO_LAUNCHER_LIST_AICPU加入任务队列但 COMPLEX32 输出在 AICPU 路径不被支持会直接报错返回。其中 AICore kernel 入口由 complex_apt.cpp 提供分派至arch35架构实现kernel_operator.harch35/complex.h。7.3 算子二进制配置在 complex_binary.json 中算子按输入 dtype 拆分为两个二进制配置项Complex_float32float32 → complex64与Complex_float16float16 → complex32shape 均标记为-2动态 shapeformat 为 NDcomplex_simplified_key.ini 则给出简化 key 的默认值。7.4 框架插件在 TensorFlow 框架侧complex_tf_plugin.cpp 通过REGISTER_CUSTOM_OP(Complex)将 TF 原算子Complex映射到本实现并使用AutoMappingByOpFn自动完成参数映射ImplyType::TVM表明其映射方式。八、调用示例以下示例代码来自官方文档完整可运行版本也可参考仓库中的 test_aclnn_complex.cpp该版本使用 RAII 智能指针管理资源。具体编译和执行过程请参考 编译与运行样例。#include iostream #include vector #include complex #include acl/acl.h #include aclnnop/aclnn_complex.h #define CHECK_RET(cond, return_expr) \ do { \ if (!(cond)) { \ return_expr; \ } \ } while (0) #define LOG_PRINT(message, ...) \ do { \ printf(message, ##__VA_ARGS__); \ } while (0) int64_t GetShapeSize(const std::vectorint64_t shape) { int64_t shapeSize 1; for (auto i : shape) { shapeSize * i; } return shapeSize; } int Init(int32_t deviceId, aclrtStream* stream) { // 固定写法资源初始化 auto ret aclInit(nullptr); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclInit failed. ERROR: %d\n, ret); return ret); ret aclrtSetDevice(deviceId); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclrtSetDevice failed. ERROR: %d\n, ret); return ret); ret aclrtCreateStream(stream); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclrtCreateStream failed. ERROR: %d\n, ret); return ret); return 0; } template typename T int CreateAclTensor(const std::vectorT hostData, const std::vectorint64_t shape, void** deviceAddr, aclDataType dataType, aclTensor** tensor) { auto size GetShapeSize(shape) * sizeof(T); // 调用aclrtMalloc申请device侧内存 auto ret aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclrtMalloc failed. ERROR: %d\n, ret); return ret); // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上 ret aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclrtMemcpy failed. ERROR: %d\n, ret); return ret); // 计算连续tensor的strides std::vectorint64_t strides(shape.size(), 1); for (int64_t i shape.size() - 2; i 0; i--) { strides[i] shape[i 1] * strides[i 1]; } // 调用aclCreateTensor接口创建aclTensor *tensor aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, shape.data(), shape.size(), *deviceAddr); return 0; } int main() { // 1.固定写法device/stream初始化参考acl API手册 // 根据自己的实际device填写deviceId int32_t deviceId 0; aclrtStream stream; auto ret Init(deviceId, stream); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(Init acl failed. ERROR: %d\n, ret); return ret); // 2. 构造输入与输出需要根据API的接口自定义构造 std::vectorint64_t realShape {4, 2}; std::vectorint64_t imagShape {4, 2}; std::vectorint64_t outShape {4, 2}; void* realDeviceAddr nullptr; void* imagDeviceAddr nullptr; void* outDeviceAddr nullptr; aclTensor* real nullptr; aclTensor* imag nullptr; aclTensor* out nullptr; std::vectorfloat realHostData {0, 1, 2, 3, 4, 5, 6, 7}; std::vectorfloat imagHostData {1, 1, 1, 2, 2, 2, 3, 3}; std::vectorstd::complexfloat outHostData(8, 0); // 创建real aclTensor ret CreateAclTensor(realHostData, realShape, realDeviceAddr, aclDataType::ACL_FLOAT, real); CHECK_RET(ret ACL_SUCCESS, return ret); // 创建imag aclTensor ret CreateAclTensor(imagHostData, imagShape, imagDeviceAddr, aclDataType::ACL_FLOAT, imag); CHECK_RET(ret ACL_SUCCESS, return ret); // 创建out aclTensor ret CreateAclTensor(outHostData, outShape, outDeviceAddr, aclDataType::ACL_COMPLEX64, out); CHECK_RET(ret ACL_SUCCESS, return ret); // 3. 调用CANN算子库API需要修改为具体的API名称 uint64_t workspaceSize 0; aclOpExecutor* executor; // 调用aclnnComplex第一段接口 ret aclnnComplexGetWorkspaceSize(real, imag, out, workspaceSize, executor); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclnnComplexGetWorkspaceSize failed. ERROR: %d\n, ret); return ret); // 根据第一段接口计算出的workspaceSize申请device内存 void* workspaceAddr nullptr; if (workspaceSize 0) { ret aclrtMalloc(workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(allocate workspace failed. ERROR: %d\n, ret); return ret); } // 调用aclnnComplex第二段接口 ret aclnnComplex(workspaceAddr, workspaceSize, executor, stream); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclnnComplex failed. ERROR: %d\n, ret); return ret); // 4.固定写法同步等待任务执行结束 ret aclrtSynchronizeStream(stream); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclrtSynchronizeStream failed. ERROR: %d\n, ret); return ret); // 5. 获取输出的值将device侧内存上的结果拷贝至host侧需要根据具体API的接口定义修改 auto size GetShapeSize(outShape); std::vectorfloat resultData(size, 0); ret aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), outDeviceAddr, size * sizeof(resultData[0]), ACL_MEMCPY_DEVICE_TO_HOST); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(copy result from device to host failed. ERROR: %d\n, ret); return ret); for (int64_t i 0; i size; i) { LOG_PRINT(result[%ld] is: %f\n, i, resultData[i]); } // 6. 释放aclTensor和aclScalar需要根据具体API的接口定义修改 aclDestroyTensor(real); aclDestroyTensor(imag); aclDestroyTensor(out); // 7. 释放device资源 aclrtFree(realDeviceAddr); aclrtFree(imagDeviceAddr); aclrtFree(outDeviceAddr); if (workspaceSize 0) { aclrtFree(workspaceAddr); } aclrtDestroyStream(stream); aclrtResetDevice(deviceId); aclFinalize(); return 0; }示例关键步骤解读资源初始化aclInit→aclrtSetDevice→aclrtCreateStream固定写法构造输入输出示例中 real 与 imag 均为{4, 2}的 FLOAT Tensor数据分别为{0..7}与{1,1,1,2,2,2,3,3}out 为{4, 2}的 COMPLEX64 Tensor。由于 real/imag shape 完全相同广播后的输出 shape 仍为{4, 2}两段式调用先调用aclnnComplexGetWorkspaceSize获取workspaceSize与executor按需用aclrtMalloc申请 workspace 内存注意workspaceSize 0时才需要申请再调用aclnnComplex执行同步与取数aclrtSynchronizeStream等待任务结束随后将结果从 Device 拷贝回 Host 并打印资源释放依次销毁aclTensor、释放 Device 内存、销毁 Stream、重置 Device 并aclFinalize。按公式计算示例输出的复数应为01j, 11j, 21j, 32j, 42j, 52j, 63j, 73j。九、单元测试验证仓库在 test_aclnn_complex.cpp 中提供了基于 gtest 的接口级单元测试覆盖以下场景complex64 正常路径FLOAT 输入 COMPLEX64 输出期望ACLNN_SUCCESScomplex32 正常路径FLOAT16 输入 COMPLEX32 输出期望ACLNN_SUCCESSdtype 配对校验COMPLEX32 输入 COMPLEX128 输出期望ACLNN_ERR_PARAM_INVALID输入 dtype 不支持输出 dtype 校验DOUBLE 输入 COMPLEX64 输出期望ACLNN_ERR_PARAM_INVALIDdtype 不配对空 Tensorshape 含 0 维的空输入期望ACLNN_SUCCESS对应第一段接口中的空 Tensor 短路处理。这些用例与文档中的错误码表格一一对应可作为复现入参校验报错行为的快捷验证手段。十、相关文档导航两段式接口说明了解 aclnn 接口为什么分两段调用broadcast 关系说明理解 real/imag 之间广播规则aclnn 返回码查询ACLNN_ERR_PARAM_NULLPTR、ACLNN_ERR_PARAM_INVALID等状态码含义编译与运行样例示例代码的编译与运行指引确定性计算说明了解默认确定性实现的背景。赞分享算子库人工智能CANN【免费下载链接】ops-math本项目是CANN提供的数学类基础计算算子库实现网络在NPU上加速计算。项目地址https://gitcode.com/cann/ops-math点击查看免费下载相关推荐CANN ops-math 算子详解Pow2 张量指数运算的 aclnn 接口与 AscendC 实现剖析CANN ops math 算子详解Pow2 张量指数运算的 aclnn 接口与 AscendC 实现剖析 本文是 CANN 开源数学算子库 ops math算子库人工智能CANNCANN ops-math ComplexV3 算子全解析实数张量组合为复数张量的实现、编译与调优CANN ops math ComplexV3 算子全解析实数张量组合为复数张量的实现、编译与调优 ComplexV3 是 CANN ops math 数学算算子库人工智能CANNCANN ops-math MatrixDiagV3 算子详解对角线张量构建的原理、参数与图模式调用实战CANN ops math MatrixDiagV3 算子详解对角线张量构建的原理、参数与图模式调用实战 本文围绕 CANN ops math 仓库中 con算子库人工智能CANN创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

按 Agent Plan 教程手动填 Base URL 报 401?TaoToken 地址别加 /v1 2026/9/20 18:05:46

按 Agent Plan 教程手动填 Base URL 报 401?TaoToken 地址别加 /v1

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
OpenRGB:跨平台硬件级RGB统一控制中枢解析 2026/9/20 18:05:46

OpenRGB:跨平台硬件级RGB统一控制中枢解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
NetBox Front Port 完全指南:面板穿通端口(Pass-Through Port)建模与前后端口映射实践 2026/9/20 18:05:46

NetBox Front Port 完全指南:面板穿通端口(Pass-Through Port)建模与前后端口映射实践

后端网络数据建模 【免费下载链接】netbox The premier source of truth powering network automation. Open source under Apache 2. Try NetBox Cloud free: https://netboxlabs.com/products/free-netbox-cloud/ 项目地址: https://gitcode.com/gh_mirrors/ne/ne…

阅读更多 →
3 条命令跑起开源库存管理系统:InvenTree 从部署到首单入库 2026/9/20 18:05:46

3 条命令跑起开源库存管理系统:InvenTree 从部署到首单入库

3 条命令跑起开源库存管理系统:InvenTree 从部署到首单入库 【免费下载链接】InvenTree Open Source Inventory Management System 项目地址: https://gitcode.com/GitHub_Trending/in/InvenTree 周五贴板,电容库存查不到,采购单状态全…

阅读更多 →
在 python-sdk 中使用 MCP Prompts 编写用户驱动消息模板的完整指南 2026/9/20 18:05:46

在 python-sdk 中使用 MCP Prompts 编写用户驱动消息模板的完整指南

在 python-sdk 中使用 MCP Prompts 编写用户驱动消息模板的完整指南 【免费下载链接】python-sdk The official Python SDK for Model Context Protocol servers and clients 项目地址: https://gitcode.com/gh_mirrors/pythonsd/python-sdk Prompts 是 MCP(…

阅读更多 →
vCenter证书过期实战:从5.5到8.0的自动巡检与重置方案 2026/9/20 18:02:45

vCenter证书过期实战:从5.5到8.0的自动巡检与重置方案

简介:VMware证书过期是虚拟化运维中常见且棘手的问题,轻则出现安全警告,重则导致vCenter管理界面无法访问、ESXi主机失去连接,甚至影响业务连续性。这套脚本专门面向VMware管理员和虚拟化运维人员,聚焦vSphere/vCenter…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞