尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

CANN ops-math 除法算子 Div 深度指南:从 aclnnDiv/aclnnInplaceDiv 两段式调用到源码实现

发布时间:2026/9/20 16:44:56

资讯中心
01
ARTICLE

CANN ops-math 除法算子 Div 深度指南:从 aclnnDiv/aclnnInplaceDiv 两段式调用到源码实现

CANN ops-math 除法算子 Div 深度指南:从 aclnnDiv/aclnnInplaceDiv 两段式调用到源码实现
CANN ops-math 除法算子 Div 深度指南从 aclnnDiv/aclnnInplaceDiv 两段式调用到源码实现【免费下载链接】ops-math本项目是CANN提供的数学类基础计算算子库实现网络在NPU上加速计算。项目地址: https://gitcode.com/cann/ops-math本篇技术指南围绕 CANN 开源数学算子库 ops-math 中的Div除法算子展开系统讲解其计算语义、产品支持范围、x1/x2/y 参数规格以及 aclnnDiv/aclnnInplaceDiv 两段式接口和图模式GE IR两种调用方式并深入到op_api、op_kernel_aicpu等目录的源码实现帮助你理解类型提升、Broadcast、AICore/AICpu 分发与整数除零/溢出防护等底层细节可直接用于算子选型、编码调用与问题定位。Div 算子功能与计算语义Div 算子在 CANN ops-math 仓库中的位置为 math/div功能定义见 math/div/README.md。其接口功能非常简单明确完成两个输入张量的逐元素除法计算。计算公式如下$$ out_i \frac{input_i}{other_i} $$即对两个 ND 格式的张量逐元素相除input是被除数除数算子中的 x1other是除数x2out是商y。两个输入支持隐式 Broadcast 广播运算即 shape 满足 NumPy 风格广播规则时低维张量会自动扩展对齐。例外说明重要当涉及 Complex复数运算且分母的模为 0 时Div 算子仍然采用通用的复数计算公式不做特殊处理。这意味着在此场景下NPU 上的计算结果与 CPU/GPU 平台存在差异。该行为在 math/div/README.md 与 math/div/docs/aclnnDivaclnnInplaceDiv.md 中均有明确说明属于设计预期而非缺陷涉及复数除法的场景需要特别留意。从 GE IR 算子的注册原型 math/div/op_graph/div_proto.h 可以确认该算子兼容 TensorFlow 的 Div 算子语义Compatible with the TensorFlow operator Div.支持广播运算输入 x1、x2 与输出 y 均为 ND Tensor且 x2 与 x1 需保持相同的数据类型与格式。产品支持情况根据 math/div/README.md 的说明Div 算子在不同产品上的支持情况如下产品是否支持Ascend 950PR/Ascend 950DT√Atlas A3 训练系列产品/Atlas A3 推理系列产品√Atlas A2 训练系列产品/Atlas A2 推理系列产品√Atlas 200I/500 A2 推理产品√Atlas 推理系列产品×Atlas 训练系列产品√可以看到除Atlas 推理系列产品310P 系列不支持外其余主流训练/推理产品均支持 Div 算子。该信息与 math/div/docs/aclnnDivaclnnInplaceDiv.md 中的逐产品声明一致。参数说明Div 算子的核心参数定义如下源自 math/div/README.md 的参数表并与算子注册 math/div/op_host/div_def.cpp 中的数据类型保持一致参数名输入/输出/属性描述数据类型数据格式x1输入公式中的 input被除数BFLOAT16、FLOAT16、FLOAT、INT32、UINT8、INT8、COMPLEX32、COMPLEX64NDx2输入公式中的 other除数BFLOAT16、FLOAT16、FLOAT、INT32、UINT8、INT8、COMPLEX32、COMPLEX64-y输出公式中的 out商BFLOAT16、FLOAT16、FLOAT、INT32、UINT8、INT8、COMPLEX32、COMPLEX64ND约束说明无该算子没有额外的使用约束。需要注意的是上表是算子GE IR / 图模式层面的类型范围。而 aclnn 单算子 APIaclnnDiv层面的支持范围更广详见下文接口章节。两种调用方式总览math/div/README.md 的调用说明给出了两种官方支持的方式调用方式样例代码说明aclnn 接口test_aclnn_div通过 AclnnDiv 接口方式调用 Div 算子图模式调用test_geir_div通过 算子IR 构图方式调用 Div 算子aclnn 接口适合在 Host 侧直接发起单算子计算走 CANN 的两段式接口GetWorkspaceSize Execute流程是算子开发、调试和上层框架适配时最常用的方式。图模式调用GE IR通过op::Div(div_graph)构建计算图节点再经由 GE 图引擎下发执行适用于需要将 Div 算子嵌入整体计算图的场景底层 IR 定义在 math/div/op_graph/div_proto.h。aclnnDiv 与 aclnnInplaceDiv 两段式接口详解接口选择普通版 vs Inplace 版aclnnDiv 与 aclnnInplaceDiv 实现完全相同的除法功能区别仅在于结果的存放方式aclnnDiv需要新建一个输出张量对象out存储计算结果aclnnInplaceDiv无需新建输出张量对象直接在输入张量 self 的内存中就地存储计算结果可以省去一次输出张量分配。两段式调用模型每个算子都遵循 CANN 的两段式接口two_phase_api设计第一段调用aclnnDivGetWorkspaceSize或aclnnInplaceDivGetWorkspaceSize获取计算所需的 workspace 大小同时返回一个包含了算子计算流程的执行器 executor第二段调用aclnnDiv或aclnnInplaceDiv真正执行计算将第一段获取的 workspace 与 executor 传入。四个接口的原型如下aclnnStatus aclnnDivGetWorkspaceSize( const aclTensor *self, const aclTensor *other, aclTensor *out, uint64_t *workspaceSize, aclOpExecutor **executor)aclnnStatus aclnnDiv( void *workspace, uint64_t workspaceSize, aclOpExecutor *executor, aclrtStream stream)aclnnStatus aclnnInplaceDivGetWorkspaceSize( aclTensor *selfRef, const aclTensor *other, uint64_t *workspaceSize, aclOpExecutor **executor)aclnnStatus aclnnInplaceDiv( void *workspace, uint64_t workspaceSize, aclOpExecutor *executor, aclrtStream stream)aclnnDivGetWorkspaceSize 参数说明参数名输入/输出描述使用说明数据类型数据格式维度(shape)非连续Tensorself输入公式中的输入 input数据类型与 other 需满足互推导关系shape 需与 other 满足 broadcast 关系FLOAT、FLOAT16、DOUBLE、INT32、INT64、INT16、INT8、UINT8、BOOL、COMPLEX128、COMPLEX64、BFLOAT16ND-√other输入公式中的输入 other数据类型与 self 需满足互推导关系shape 需与 self 满足 broadcast 关系同上ND-√out输出公式中的 out数据类型需是 self 与 other 推导之后可转换的数据类型shape 需是 broadcast 之后的 shape同上ND-√workspaceSize输出返回需要在 Device 侧申请的 workspace 大小-----executor输出返回 op 执行器包含了算子计算流程-----平台相关的数据类型差异Atlas 200I/500 A2 推理产品、Atlas 训练系列产品数据类型不支持 BFLOAT16Ascend 950PR/Ascend 950DTself 与 other 推导之后的数据类型为整数类型或布尔类型时推导结果会转换为 FLOATout 不支持 INT32、INT64、INT16、INT8、UINT8、BOOL 数据类型。aclnnDiv 参数说明第二段接口参数名输入/输出描述workspace输入在 Device 侧申请的 workspace 内存地址workspaceSize输入在 Device 侧申请的 workspace 大小由第一段接口 aclnnDivGetWorkspaceSize 获取executor输入op 执行器包含了算子计算流程stream输入指定执行任务的 Stream返回码与错误场景两个接口均返回aclnnStatus状态码具体参见 aclnn 返回码。第一段接口完成入参校验出现以下场景时报错返回码错误码描述ACLNN_ERR_PARAM_NULLPTR161001传入的 self、other 或 out 是空指针ACLNN_ERR_PARAM_INVALID161002self 和 other 的数据类型和数据格式不在支持的范围之内ACLNN_ERR_PARAM_INVALID161002self 和 other 不满足数据类型推导规则ACLNN_ERR_PARAM_INVALID161002推导出的数据类型无法转换为指定输出 out 的类型ACLNN_ERR_PARAM_INVALID161002self 和 other 的 shape 无法做 broadcastACLNN_ERR_PARAM_INVALID161002self 和 other 的维度大于 8对于aclnnInplaceDivGetWorkspaceSize空指针场景为 selfRef、other 是空指针错误码 161002 对应的场景为selfRef 和 other 数据类型/格式不在支持范围、不满足数据类型推导规则、shape 无法 broadcast、维度大于 8Inplace 版本无需校验 out 类型转换因为结果就地写回 selfRef。此外Ascend 950PR/950DT 上 selfRef 不支持 INT32、INT64、INT16、INT8、UINT8、BOOL。约束与确定性计算aclnnDiv 与 aclnnInplaceDiv 均为默认确定性实现见 math/div/docs/aclnnDivaclnnInplaceDiv.md 的约束说明即相同输入在多次执行下结果可复现对精度敏感的推理/训练场景友好。完整调用示例C 语言风格 aclnn 接口调用以下示例代码来自仓库的 examples/test_aclnn_div.cpp保留了核心流程去掉版权头它同时演示了 aclnnDiv 与 aclnnInplaceDiv 的完整调用。具体编译与执行过程可参考编译与运行样例。#include iostream #include vector #include acl/acl.h #include aclnnop/aclnn_div.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); aclFinalize(); return ret); ret aclrtCreateStream(stream); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclrtCreateStream failed. ERROR: %d\n, ret); aclrtResetDevice(deviceId); aclFinalize(); 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 selfShape {4, 2}; std::vectorint64_t otherShape {4, 2}; std::vectorint64_t outShape {4, 2}; void* selfDeviceAddr nullptr; void* otherDeviceAddr nullptr; void* outDeviceAddr nullptr; aclTensor* self nullptr; aclTensor* other nullptr; aclTensor* out nullptr; std::vectorfloat selfHostData {0, 1, 2, 3, 4, 5, 6, 7}; std::vectorfloat otherHostData {1, 1, 1, 2, 2, 2, 3, 3}; std::vectorfloat outHostData(8, 0); ret CreateAclTensor(selfHostData, selfShape, selfDeviceAddr, aclDataType::ACL_FLOAT, self); CHECK_RET(ret ACL_SUCCESS, return ret); ret CreateAclTensor(otherHostData, otherShape, otherDeviceAddr, aclDataType::ACL_FLOAT, other); CHECK_RET(ret ACL_SUCCESS, return ret); ret CreateAclTensor(outHostData, outShape, outDeviceAddr, aclDataType::ACL_FLOAT, out); CHECK_RET(ret ACL_SUCCESS, return ret); uint64_t workspaceSize 0; aclOpExecutor* executor; // ---- aclnnDiv 接口调用示例 ---- LOG_PRINT(test aclnnDiv\n); // 3. 调用aclnnDiv第一段接口 ret aclnnDivGetWorkspaceSize(self, other, out, workspaceSize, executor); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclnnDivGetWorkspaceSize 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); } // 调用aclnnDiv第二段接口 ret aclnnDiv(workspaceAddr, workspaceSize, executor, stream); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclnnDiv 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侧 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]); } // ---- aclnnInplaceDiv 接口调用示例 ---- LOG_PRINT(\ntest aclnnInplaceDiv\n); // 调用aclnnInplaceDiv第一段接口不需要out结果写回self ret aclnnInplaceDivGetWorkspaceSize(self, other, workspaceSize, executor); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclnnInplaceDivGetWorkspaceSize failed. ERROR: %d\n, ret); return ret); 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 aclnnInplaceDiv(workspaceAddr, workspaceSize, executor, stream); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclnnInplaceDiv 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); // 结果在self的内存中从selfDeviceAddr取回 ret aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), selfDeviceAddr, 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与Device资源 aclDestroyTensor(self); aclDestroyTensor(other); aclDestroyTensor(out); aclrtFree(selfDeviceAddr); aclrtFree(otherDeviceAddr); aclrtFree(outDeviceAddr); if (workspaceSize 0) { aclrtFree(workspaceAddr); } aclrtDestroyStream(stream); aclrtResetDevice(deviceId); aclFinalize(); return 0; }示例中使用 shape 均为{4, 2}的 FLOAT 张量self {0,1,2,3,4,5,6,7}other {1,1,1,2,2,2,3,3}可预期 aclnnDiv 输出为{0/1, 1/1, 2/1, 3/2, 4/2, 5/2, 6/3, 7/3}。仓库中还提供了一个使用std::unique_ptr做资源管理的 C RAII 版本示例位于 math/div/examples/test_aclnn_div.cpp更适合直接嵌入工程代码。调用流程中的关键点aclnnDivGetWorkspaceSize第一段接口完成全部入参校验并构图workspaceSize 可能为 0此时无需申请 workspace 内存代码中if (workspaceSize 0)判断即为此意workspace 内存在 Device 侧申请生命周期需覆盖第二段接口的执行第二段aclnnDiv是异步提交务必通过aclrtSynchronizeStream(stream)同步后再读取结果。图模式GE IR调用 Div对于图模式调用仓库提供了 examples/test_geir_div.cpp。核心构图思路如下摘自该示例#include array_ops.h #include ge_api.h #include ge_api_types.h #include ge_ir_build.h #include graph.h #include tensor.h #include types.h #include ../op_graph/div_proto.h // 创建图节点 auto div_op op::Div(div_graph); std::vectorint64_t input_shape {4, 2}; auto x1 op::Data(x1).set_attr_index(0); TensorDesc x1_desc(Shape(input_shape), FORMAT_ND, DT_DOUBLE); x1_desc.SetPlacement(ge::kPlacementHost); // ... 构造 x1/x2 输入 Tensor 与 Data 节点、设置 div_op 输入输出、构建 Graph 并完成图编译与执行GE IR 的算子原型注册于 math/div/op_graph/div_proto.hREG_OP(Div) .INPUT(x1, TensorType({DT_FLOAT, DT_FLOAT16, DT_INT8, DT_UINT8, DT_INT32, DT_DOUBLE, DT_INT64, DT_UINT16, DT_INT16, DT_COMPLEX64, DT_COMPLEX128, DT_BF16, DT_COMPLEX32})) .INPUT(x2, TensorType({DT_FLOAT, DT_FLOAT16, DT_INT8, DT_UINT8, DT_INT32, DT_DOUBLE, DT_INT64, DT_UINT16, DT_INT16, DT_COMPLEX64, DT_COMPLEX128, DT_BF16, DT_COMPLEX32})) .OUTPUT(y, TensorType({DT_FLOAT, DT_FLOAT16, DT_INT8, DT_UINT8, DT_INT32, DT_DOUBLE, DT_INT64, DT_UINT16, DT_INT16, DT_COMPLEX64, DT_COMPLEX128, DT_BF16, DT_COMPLEX32})) .OP_END_FACTORY_REG(Div)IR 层面的支持类型比 aclnn 接口更宽包含 DOUBLE、INT64、UINT16、INT16、COMPLEX128、COMPLEX32并允许 NCHW、NHWC、ND 等格式proto 注释中声明而 aclnn 接口按产品能力做了更细的收敛。图模式下 Div 的 shape 推导使用通用的 Broadcast 推导实现见 math/div/op_host/div_infershape.cpp 中的IMPL_OP_INFERSHAPE(Div).InferShape(Ops::Base::InferShape4Broadcast)。源码级实现原理1. aclnn 接口层的类型提升与校验op_api/aclnn_div.cppmath/div/op_api/aclnn_div.cpp 中实现了aclnnDivGetWorkspaceSize/aclnnDiv以及配套的 Divs、DivMod 系列接口。aclnnDivGetWorkspaceSize的执行流程可以归纳为创建 Executor并调用CheckParams完成五步校验空指针检查 → shape 与 broadcast 检查维度上限MAX_SUPPORT_DIMS_NUMS即不超过 8 维→ 数据类型支持范围检查 → 类型推导promote及输出可转换性检查 → 数据格式禁止私有格式检查分别对应返回码 161001/161002 的各条错误描述空 Tensor 特判如果 self 或 other 为空 TensorIsEmpty()kernel 侧天然支持直接返回workspaceSize 0且不构图类型提升根据芯片架构IsRegBase/ 非 RegBase调用不同的推导逻辑。核心策略见CompatibleInferDivDtype与InferDivModeDtype是浮点/复数类型按op::PromoteType提升整数除 int32 在 910B/910C 上 L0 算子支持外与布尔一律提升为FLOAT参与计算以对齐 CUDA 的精度行为fp16/bf16 也会被提升到 float 计算PromoteLowPrecToFloat混合 dtype 特判对于 910B/910C 平台上的部分混合类型组合如 fp16fp32、bf16fp32 等定义在AllowedMixDtypePairs跳过 Cast 直接走 RealDiv避免不必要的类型转换开销构图与落盘按需对输入做Contiguous转连续与Cast类型转换调用 L0 算子l0op::RealDiv完成除法再用l0op::Cast将结果转回 out 的目标类型最后用l0op::ViewCopy写回非连续输出返回executor-GetWorkspaceSize()作为第一段接口的输出。2. L0 算子层的 AICore/AICpu 分发op_api/div.cppmath/div/op_api/div.cpp 定义了 L0 算子l0op::Div。它先通过BroadcastInferShape推导广播后的输出 shape然后按数据类型决定执行后端若 self 的 dtype 在 AICore 支持列表内910 系列FLOAT、FLOAT16、INT32、INT8、UINT8910B/RegBase 系列额外支持 BF16见GetAiCoreDtypeSupportListBySocVersion走AICore kernelDivAiCore通过ADD_TO_LAUNCHER_LIST_AICORE入队否则走AICpu kernelDivAiCpu通过ADD_TO_LAUNCHER_LIST_AICPU入队例如 DOUBLE、INT64、COMPLEX 等类型在部分平台会落到 CPU 侧计算。在 Ascend 950ascend950产品上Div 算子注册了专用 AICore 配置见 math/div/op_host/div_def.cpp 中的OpAICoreConfig支持动态 shapeDynamicShapeSupportFlag(true)、动态 rankDynamicRankSupportFlag(true)并开启精度降低豁免PrecisionReduceFlag(true)kernel 文件指向div_apt。对应的静态二进制注册表 math/div/op_host/config/ascend950/div_binary.json 列出了 FLOAT16/FLOAT32/INT32/INT8/UINT8/BFLOAT16/COMPLEX32/COMPLEX64 等 ND 格式的 bin 组合shape 使用-2表示动态维度。3. AICpu Kernel 的数值安全处理op_kernel_aicpu/div_aicpu.cppmath/div/op_kernel_aicpu/div_aicpu.cpp 中的DivCpuKernel是 AICpu 后端的核心实现除了常规的逐元素除法*(output i) lhs_getter(i) / rhs_getter(i)之外还包含三类值得注意的数值防护逻辑整数除零检查DivParamCheckZero与ComputeIntDivValue会在除数为 0 时打印Division by zero.错误并返回KERNEL_STATUS_INNER_ERROR有符号整数溢出检查IsDivOverflow检测INT_MIN / -1这一唯一会触发整数除法溢出的组合CheckNoBcastDivOverflow/CheckBcastDivOverflow会在广播场景SAME_SHAPE / X_ONE_ELEMENT / Y_ONE_ELEMENT下逐元素预检向零取整修正NeedFloorAdjust在整数除法余数非零且被除数与除数异号时执行lhs / rhs - 1修正保证整数除法结果与浮点语义一致地向零舍入。此外 kernel 内部对大数据量场景使用aicpu::CpuKernelUtils::ParallelFor并行切分阈值常量kParallelDataNum 2 * 1024、kParallelDataNumSameShape 7 * 1024等并对中小规模数据限制最大并行核数为 4说明 Div 的 AICpu 实现具备多核并行能力。测试与验证仓库为 Div 算子提供了多层次的测试资产ST 场景测试math/div/tests/st/aclnnDiv/atk_aclnnDiv.json 是标准的 ATK 测试描述文件全部用例以torch.div为对标基准name: torch.div, aclnn_name: Div精度标准为high_performance覆盖 int8/int16/int32/int64、fp16/fp32/fp64、bf16、bool、complex64/complex128 等多种 dtype以及多维 shape、0 维标量、1x1x1x1极简 shape、大 shape如[1,1,20,131073]与边界值inf/nan/-inf等用例UT 单测math/div/tests/ut/op_api/test_aclnn_div.cpp、math/div/tests/ut/op_host/test_div_infershape.cpp、math/div/tests/ut/op_kernel_aicpu/test_div.cpp 分别覆盖 op_api、infershape 与 aicpu kernel 三个层面AICore kernel CSVmath/div/tests/st/arch35/ttk_kernel_div_st.csv 用于 arch35950平台的 kernel 级测试。小结Div 算子是 CANN ops-math 中最基础的逐元素数学算子之一语义上等价于 PyTorch 的torch.div/ TensorFlow 的Div。本文从 math/div/README.md 出发梳理了其计算语义、产品支持矩阵、x1/x2/y 参数规格完整给出了 aclnnDiv/aclnnInplaceDiv 两段式接口的原型、参数、返回码与可直接运行的示例代码并沿调用链向下展开到 op_api 类型提升、L0 算子 AICore/AICpu 分发、AICpu kernel 的整数除零/溢出防护以及 ATK/UT 测试资产可作为你在 NPU 上使用或排查 Div 除法计算的直接参考。【免费下载链接】ops-math本项目是CANN提供的数学类基础计算算子库实现网络在NPU上加速计算。项目地址: https://gitcode.com/cann/ops-math创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。