
算子库人工智能CANN【免费下载链接】ops-math本项目是CANN提供的数学类基础计算算子库实现网络在NPU上加速计算。项目地址https://gitcode.com/cann/ops-math点击查看免费下载本文围绕 CANN ops-math 数学算子库中的 IsPosInf 算子正无穷判断算子展开系统介绍其功能语义、产品支持矩阵、aclnnIsPosInf 两段式接口的参数约束与错误码、基于 aclnn 的完整调用示例并结合仓库源码深入剖析其算子定义、shape 推导、tiling 与 kernel DAG 的底层实现链路。读者阅读后可独立完成 IsPosInf 算子在 Ascend 平台上的应用开发与结果验证。算子概述与功能说明IsPosInf 是 CANN ops-math 项目中位于 math/is_pos_inf 目录下的基础数学算子其核心功能是逐元素判断输入张量中的每个元素是否为正无穷inf并将判断结果输出为布尔张量。功能语义算子功能判断张量中哪些元素是正无穷即为 inf。计算公式$$ out_i (input_i \infty) $$示例若 x [9, 6, inf]则 isPosInf(x) 的结果为 [False, False, True]。值得说明的是该算子与仓库中同目录族系的 is_neg_inf负无穷判断在语义上互为镜像两者常用于数值校验、NaN/Inf 过滤等场景。测试基准验证仓库在 math/is_pos_inf/tests/assets/golden.py 中给出了算子结果的黄金基准实现直接复用 NumPy 的语义等价函数def is_pos_inf_golden(x, **kwargs): return np.isposinf(x)即 IsPosInf 的输出与np.isposinf(x)完全一致这为算子正确性提供了明确的对照标准也便于开发者在本地用 NumPy 快速验证自己的理解。产品支持情况IsPosInf 算子在当前仓库版本中的产品支持矩阵如下产品是否支持Ascend 950PR/Ascend 950DT√Atlas A3 训练系列产品/Atlas A3 推理系列产品√Atlas A2 训练系列产品/Atlas A2 推理系列产品√Atlas 200I/500 A2 推理产品×Atlas 推理系列产品√Atlas 训练系列产品×从源码配置看该支持矩阵与 math/is_pos_inf/op_host/is_pos_inf_def.cpp 中算子注册的 AICore 平台配置一致——该文件为算子配置了ascend950与ascend350两个平台的 AICore 配置并在 math/is_pos_inf/op_host/config/ascend350/is_pos_inf_binary.json 与 math/is_pos_inf/op_host/config/ascend950/is_pos_inf_binary.json 中提供了对应的二进制编译配置。在开发部署时需要结合实际的硬件产品型号确认算子可用性。参数说明IsPosInf 算子的参数定义如下参数名输入/输出/属性描述数据类型数据格式x输入待进行判断的入参公式中的 input_i。FLOAT、FLOAT16、BFLOAT16NDy输出待进行判断的出参公式中的 out_i。BOOLND参数说明要点输入 x 支持 3 种浮点类型FLOATFP32、FLOAT16、BFLOAT16输出 y 恒为 BOOL 类型每个元素为 0/1 的布尔值。输入与输出均采用 ND 数据格式。输出 y 的 shape 与输入 x 完全一致逐元素一一对应。上述约束在算子定义源码中有严格体现。math/is_pos_inf/op_host/is_pos_inf_def.cpp 中通过OpDef注册this-Input(x) .ParamType(REQUIRED) .DataType({ge::DT_FLOAT16, ge::DT_FLOAT, ge::DT_BF16}) .Format({ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND}); this-Output(y) .ParamType(REQUIRED) .DataType({ge::DT_BOOL, ge::DT_BOOL, ge::DT_BOOL}) .Format({ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND});同时该算子还开启了多项动态能力标志DynamicCompileStaticFlag(true)支持动态编译静态化、DynamicRankSupportFlag(true)支持动态维度、DynamicShapeSupportFlag(true)支持动态 shape、PrecisionReduceFlag(true)允许精度降级处理并指定了 kernel 实现文件为is_pos_inf_apt。调用说明aclnn 两段式接口IsPosInf 算子支持通过aclnnAscend CANN 算子库接口进行调用。仓库提供了完整的调用样例 math/is_pos_inf/examples/test_aclnn_isposinf.cpp以及对应的接口说明文档 math/is_pos_inf/docs/aclnnIsPosInf.md。两段式接口架构aclnnIsPosInf 采用 CANN 标准的两段式接口Two-Phase API设计即必须先调用aclnnIsPosInfGetWorkspaceSize接口获取计算所需 workspace 大小以及包含了算子计算流程的执行器再调用aclnnIsPosInf接口执行计算。这与 ops-math 项目中其他 aclnn 算子的调用范式保持一致。第一段接口原型aclnnStatus aclnnIsPosInfGetWorkspaceSize( const aclTensor* self, aclTensor* out, uint64_t* workspaceSize, aclOpExecutor** executor)第二段接口原型aclnnStatus aclnnIsPosInf( void* workspace, uint64_t workspaceSize, aclOpExecutor* executor, const aclrtStream stream)第一段接口 aclnnIsPosInfGetWorkspaceSize 参数说明参数名输入/输出描述使用说明数据类型数据格式维度(shape)非连续TensorselfaclTensor*输入输入张量公式中的 self。-FLOAT、FLOAT16、DOUBLE、BFLOAT16ND0-8√outaclTensor*输出输出张量公式中的 out。数据类型为 BOOLshape 与 self 相同。BOOLND0-8√workspaceSizeuint64_t*输出返回需要在 Device 侧申请的 workspace 大小。-----executoraclOpExecutor**输出返回 op 执行器包含了算子计算流程。-----需要特别说明的是aclnn 接口层math/is_pos_inf/op_api/aclnn_isposinf.cpp在 aclnn 文档允许的输入类型范围上比算子定义更宽接口层自检支持 FLOAT、FLOAT16、DOUBLE、BFLOAT16但算子 AICore 实现仅支持 FLOAT、FLOAT16、BFLOAT16。因此文档中特别注明限制Atlas 训练系列产品、Atlas 推理系列产品不支持 BFLOAT16。且 DOUBLE 类型入参在接口层校验后会因 AICore 不支持而无法进入实际计算详见下文底层实现链路一节中对IsAiCoreSupport的说明实际以算子定义的数据类型为准。返回值与错误码两段接口均返回aclnnStatus状态码。第一段接口完成入参校验出现以下场景时报错返回码错误码描述ACLNN_ERR_PARAM_NULLPTR161001传入的 self 或 out 是空指针。ACLNN_ERR_PARAM_INVALID161002self 或 out 的数据类型不在支持范围之内。ACLNN_ERR_PARAM_INVALID161002self 和 out 的维度超过 8 维。ACLNN_ERR_PARAM_INVALID161002self 和 out 的 shape 不一致。第二段接口 aclnnIsPosInf 参数说明参数名输入/输出描述workspace输入在 Device 侧申请的 workspace 内存地址。workspaceSize输入在 Device 侧申请的 workspace 大小由第一段接口 aclnnIsPosInfGetWorkspaceSize 获取。executor输入op 执行器包含了算子计算流程。stream输入指定执行任务的 Stream。约束说明确定性计算aclnnIsPosInf 默认确定性实现同一输入在多次运行下输出结果确定。完整调用示例可运行以下示例代码来自 math/is_pos_inf/docs/aclnnIsPosInf.md具体编译和执行过程可参考 编译与运行样例。代码演示了从 ACL 环境初始化、张量创建、两段式接口调用到结果回拷与资源释放的完整流程#include iostream #include vector #include acl/acl.h #include aclnnop/aclnn_isposinf.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 shape_size 1; for (auto i : shape) { shape_size * i; } return shape_size; } 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; } templatetypename 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() { int32_t deviceId 0; aclrtStream stream; auto ret Init(deviceId, stream); CHECK_RET(ret 0, LOG_PRINT(Init acl failed. ERROR: %d\n, ret); return ret); std::vectorint64_t selfShape {4, 2}; std::vectorint64_t outShape {4, 2}; void* selfDeviceAddr nullptr; void* outDeviceAddr nullptr; aclTensor* self nullptr; aclTensor* out nullptr; std::vectorfloat selfHostData {0, 1, 2, 3, 4, 5, 6, 7}; std::vectorchar outHostData {1, 1, 1, 1, 0, 0, 0, 0}; ret CreateAclTensor(selfHostData, selfShape, selfDeviceAddr, aclDataType::ACL_FLOAT, self); CHECK_RET(ret ACL_SUCCESS, return ret); ret CreateAclTensor(outHostData, outShape, outDeviceAddr, aclDataType::ACL_BOOL, out); CHECK_RET(ret ACL_SUCCESS, return ret); uint64_t workspaceSize 0; aclOpExecutor* executor; ret aclnnIsPosInfGetWorkspaceSize(self, out, workspaceSize, executor); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclnnIsPosInfGetWorkspaceSize failed. ERROR: %d\n, ret); return ret); 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); } ret aclnnIsPosInf(workspaceAddr, workspaceSize, executor, stream); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclnnIsPosInf failed. ERROR: %d\n, ret); return ret); ret aclrtSynchronizeStream(stream); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclrtSynchronizeStream failed. ERROR: %d\n, ret); return ret); auto size GetShapeSize(outShape); std::vectorchar resultData(size, 0); ret aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), outDeviceAddr, size * sizeof(char), 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: %d\n, i, resultData[i]); } aclDestroyTensor(self); aclDestroyTensor(out); // 释放device资源需要根据具体API的接口定义修改 aclrtFree(selfDeviceAddr); aclrtFree(outDeviceAddr); if (workspaceSize 0) { aclrtFree(workspaceAddr); } aclrtDestroyStream(stream); aclrtResetDevice(deviceId); aclFinalize(); return 0; }示例执行逻辑拆解环境初始化aclInit初始化 ACL 运行环境aclrtSetDevice绑定 deviceId0 的昇腾设备aclrtCreateStream创建任务流。张量创建通过aclrtMalloc申请 Device 侧内存、aclrtMemcpy将 host 数据shape 为 {4, 2} 的 8 个 float 元素拷入 Device再用aclCreateTensor按 ND 格式与连续 strides 构造输入 self 与输出 out输出为 ACL_BOOL 类型。第一段接口aclnnIsPosInfGetWorkspaceSize完成入参校验并返回 workspace 大小与 executor若 workspaceSize 0 则用aclrtMalloc申请 workspace。第二段接口aclnnIsPosInf在指定 stream 上异步执行计算。同步与取数aclrtSynchronizeStream等待计算完成aclrtMemcpy将结果从 Device 拷回 host逐元素打印1 表示 true0 表示 false。资源释放依次销毁 tensor、释放 Device 内存与 workspace、销毁 stream、aclrtResetDevice复位设备并aclFinalize收尾。仓库同时提供了使用 RAII 智能指针管理资源、并封装aclGuard确保异常路径下资源释放的增强版示例 math/is_pos_inf/examples/test_aclnn_isposinf.cpp其核心调用流程与上述示例一致适合作为工程化改造的参考。底层实现链路从接口到 Kernel为了让读者对算子有更深的理解下面沿调用链剖析 IsPosInf 在仓库中的各层实现。整个实现遵循 CANN 算子的分层结构op_apiL0 接口层→ op_host算子定义/shape 推导/tiling→ op_kernelAscendC kernel。op_api 层L0 接口实现math/is_pos_inf/op_api/isposinf.cpp 实现了 L0 层的IsPosInf逻辑其关键流程为通过IsAiCoreSupport检查输入数据类型是否属于{DT_FLOAT, DT_FLOAT16, DT_BF16}见 math/is_pos_inf/op_api/isposinf.h 中的声明不满足则直接返回空指针——这是 DOUBLE 入参虽在接口层文档中列出、但实际无法完成计算的原因通过executor-AllocTensor依据输入 view shape 自动申请 BOOL 类型的输出张量调用IsPosInfAiCore经ADD_TO_LAUNCHER_LIST_AICORE将算子任务加入 AICore 执行列表并注册OP_TYPE_REGISTER(IsPosInf)。op_host 层算子定义与 shape 推导算子定义math/is_pos_inf/op_host/is_pos_inf_def.cpp 注册输入 xFLOAT16/FLOAT/BF16ND 格式与输出 yBOOLND 格式并为 ascend950、ascend350 两个平台添加 AICore 配置详见上文参数说明一节。shape 推导math/is_pos_inf/op_host/is_pos_inf_infershape.cpp 复用通用逐元素推导逻辑IMPL_OP_INFERSHAPE(IsPosInf).InferShape(Ops::Base::InferShape4Elewise)即 IsPosInf 被视为逐元素elementwise算子输出 shape 与输入保持一致。该文件配套的单元测试见 math/is_pos_inf/tests/ut/op_host/test_is_pos_inf_infershape.cpp。tiling 层arch35 平台切分逻辑math/is_pos_inf/op_host/arch35/is_pos_inf_tiling_arch35.cpp 实现 arch35Ascend 950 等平台下的 tiling 计算核心步骤包括CalcInputDtype/CalcOutputDtype校验输入仅支持 FLOAT16/BF16/FLOAT输出必须为 BOOL不满足时报非法数据类型错误CheckShape校验维度不超过 8 维MAX_DIM_NUM 8且输入输出 shape 必须一致RunTiling按输入数据类型分别实例化IsPosInfDAGhalf、IsPosInfDAGbfloat16_t、IsPosInfDAGfloat调用ElewiseBaseTiling::DoTiling完成切分并设置 workspace固定ASCEND_WORKSPACE 16 * 1024 * 1024即 16MB、tiling key 与 blockDim核数TilingPrepareForIsPosInf通过PlatformAscendC获取 AIV 核数与 UB 内存大小写入编译信息。kernel 层AscendC DAG 实现math/is_pos_inf/op_kernel/arch35/is_pos_inf_dag.h 以算子 DAG有向无环图形式描述计算流水这也是该算子区别于普通 AscendC 手写 kernel 的实现特点template typename U, typename T float struct IsPosInfDAG { using ConstPosInf MAKE_CONST(T, CONST_POS_INF_FP32); // 常量inf using OpCopyIn BindVec::CopyInU, Placeholder::In0U; // 1. 数据搬入 using OpCast BindVec::CastT, U, CAST_MODE, OpCopyIn; // 2. 类型转换统一到 T using CompareMask BindVec::Compareuint8_t, T, CMP_MODE, OpCast, ConstPosInf; // 3. 与 inf 比较 using SelectRes BindVec::Selectuint8_t, uint8_t, SELECT_MODE, CompareMask, DataOne, ConstZero; // 4. 选择 true/false using OpCopyOut BindVec::CopyOutuint8_t, Placeholder::Out0uint8_t, SelectRes; // 5. 结果写出 ... };其中CONST_POS_INF_FP32 INFINITY__builtin_inff()比较结果通过Select将命中 inf 的位置置 1、其余置 0最终以 BOOLuint8_t写出。整条流水将搬入 → 转换 → 比较 → 选择 → 写出五步串联配合MemOptCfgMemLevel::LEVEL_2完成二级内存优化具体内核入口见 math/is_pos_inf/op_kernel/is_pos_inf_apt.cpp。测试与验证仓库为 IsPosInf 提供了多维度的测试覆盖可用于功能验证与回归接口调用用例math/is_pos_inf/tests/ut/op_api/test_aclnn_isposinf.cpp验证 aclnn 两段式接口的调用路径shape 推导单测math/is_pos_inf/tests/ut/op_host/test_is_pos_inf_infershape.cpptiling 单测math/is_pos_inf/tests/ut/op_host/arch35/test_is_pos_inf_tiling.cppST 用例ATK 接口用例 math/is_pos_inf/tests/st/aclnnIsPosInf/atk_aclnnIsPosInf.json 与 arch35 核函数用例 math/is_pos_inf/tests/st/arch35/ttk_kernel_is_pos_inf_st.csv黄金基准math/is_pos_inf/tests/assets/golden.py 提供的is_pos_inf_golden基准实现。小结IsPosInf 是一个语义简洁但工程链路完整的数学算子功能上它对输入浮点张量逐元素判断是否为 inf 并输出 BOOL 结果接口上遵循 CANN 标准的两段式 aclnn 接口范式支持 FLOAT/FLOAT16/BFLOAT16 输入与 ND 格式、0~8 维动态 shape实现上由 op_api 的 L0 逻辑、op_host 的算子定义/shape 推导/tiling 与 op_kernel 的 DAG 流水共同支撑并配套了从单测、ST 到黄金基准的完整验证体系。开发者既可直接参考 aclnnIsPosInf 接口文档 与 调用示例 快速上手也可沿本文剖析的源码路径深入理解算子底层机制为在昇腾 NPU 上构建 NaN/Inf 检测、数值安全校验等上层能力提供坚实基础。赞分享算子库人工智能CANN【免费下载链接】ops-math本项目是CANN提供的数学类基础计算算子库实现网络在NPU上加速计算。项目地址https://gitcode.com/cann/ops-math点击查看免费下载相关推荐CANN ops-math 中 Roll 算子的 aclnnRoll 接口使用指南与实现原理CANN ops math 中 Roll 算子的 aclnnRoll 接口使用指南与实现原理 本文以 CANN ops math 开源仓库中 experimen算子库人工智能CANNCANN ops-math 算子解析IsPosInf 逐元素正无穷判定算子的原理、ACLNN 接口与源码实现CANN ops math 算子解析IsPosInf 逐元素正无穷判定算子的原理、ACLNN 接口与源码实现 导读 本文围绕 CANN ops math 数学算子库人工智能CANNCANN ops-math 算子接口指南aclnnClampMaxTensor 与 aclnnInplaceClampMaxTensor 的使用与原理CANN ops math 算子接口指南aclnnClampMaxTensor 与 aclnnInplaceClampMaxTensor 的使用与原理 本指南算子库人工智能CANN创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考