ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

CANN ops-math 数学算子解析:CumulativeLogsumexp 累积 log-sum-exp 的原理、参数与 Ascend 950 实现

CANN ops-math 数学算子解析:CumulativeLogsumexp 累积 log-sum-exp 的原理、参数与 Ascend 950 实现 CANN ops-math 数学算子解析CumulativeLogsumexp 累积 log-sum-exp 的原理、参数与 Ascend 950 实现【免费下载链接】ops-math本项目是CANN提供的数学类基础计算算子库实现网络在NPU上加速计算。项目地址: https://gitcode.com/cann/ops-mathCumulativeLogsumexp累积 log-sum-exp是 CANN ops-math 数学算子库中负责沿指定维度对输入张量做前缀/后缀 log-sum-exp 累积的算子常用于软标签解码、粒子滤波、状态序列归一化等以数值稳定性为关键诉求的算法链路。本文以 math/cumulative_logsumexp/README.md 为主线结合算子定义、tiling、kernel 与测试源码完整讲解其数学语义、输入输出参数、约束条件、Ascend 950 上的 SIMT 并行实现以及 GE 图模式调用方法帮助你快速上手并理解其底层原理。算子功能与数学定义CumulativeLogsumexp 的功能是对输入张量x沿axis指定的维度计算累积 log-sum-exp并把结果写入输出张量y。设i是axis维度上的下标S_i是参与第i个输出元素计算的前缀或后缀下标集合则每个输出元素满足$$ y_i \log \sum_{j \in S_i} e^{x_j} $$集合S_i的形态由两个布尔属性共同决定详细语义见 op_kernel/arch35/cumulative_logsumexp_simt.h 中count、start、step的推导逻辑exclusive falseS_i包含当前位置i即输出为前缀和y[i] logsumexp(x[0..i])exclusive trueS_i不包含当前位置i即输出为严格前缀和y[i] logsumexp(x[0..i-1])首个位置输出-infreverse false按下标递增方向累积正向reverse true按下标递减方向累积反向即从axis维度末位向首位扫描。以示例中的输入x [-3.0, -2.0, -1.0, -0.5]axis1exclusivefalsereversefalse为例输出依次为y[0] log(e^-3) -3.0y[1] log(e^-3 e^-2) ≈ -1.873y[2] log(e^-3 e^-2 e^-1) ≈ -0.903y[3] log(e^-3 e^-2 e^-1 e^-0.5) ≈ -0.386其中累积操作使用稳定的LogAddExp递推实现m log1p(exp(-|a-b|))见 examples/test_geir_cumulative_logsumexp.cpp避免大数指数溢出导致的计算精度损失。参数说明算子共包含 2 个输入、2 个属性与 1 个输出与官方定义 op_host/cumulative_logsumexp_def.cpp 中的OpDef注册保持一致参数名输入/输出/属性描述数据类型数据格式x输入输入 Tensor。shape 支持 1~6 维指定 axis 维度长度必须大于 0FLOAT、FLOAT16NDaxis输入需要进行累积 log-sum-exp 的维度必须为编译期常量标量取值范围为[-rank(x), rank(x)-1]INT32、INT64、INT16NDexclusive属性默认值为false。false表示包含当前位置true表示不包含当前位置BOOL-reverse属性默认值为false。false表示正向累积true表示反向累积BOOL-y输出输出 Tensorshape 与 x 相同FLOAT、FLOAT16ND底层参数绑定要点从算子定义源码可以看出几个容易被忽略的细节axis输入被声明为ValueDepend(OPTIONAL)即其值依赖关系参与编译期常量解析配合 tiling 阶段直接从常量 tensor 读取数值使用x/y均为AutoContiguous()输入输出按连续内存布局处理输入类型组合在定义中被显式展开为 6 种(FLOAT, INT32)、(FLOAT, INT64)、(FLOAT, INT16)、(FLOAT16, INT32)、(FLOAT16, INT64)、(FLOAT16, INT16)与编译配置 op_host/config/ascend950/cumulative_logsumexp_binary.json 中 6 个op_list条目一一对应。约束说明axis必须为编译期常量标量。若在 tiling 阶段取不到常量值GetInputTensor返回空会直接报错 axis must be a compile-time constant scalar.见 cumulative_logsumexp_tiling.cpp。x不支持标量输入axis指定维度长度为 0 时返回参数错误tiling 中通过axisNum 0校验同上文件 L111-L124。y的 shape 和数据类型需要与x一致由 shape 推导与数据类型推导逻辑保证见 cumulative_logsumexp_infershape.cpp。当前仅支持 ND 格式不支持标量输入axis的合法区间为[-rank, rank-1]负数会在 tiling 阶段被归一化为axis rank。产品支持情况算子当前仅对特定产品使能编译期通过SUPPORT_COMPUTE_UNIT声明见 math/cumulative_logsumexp/CMakeLists.txt产品是否支持Ascend 950PR / Ascend 950DT√Atlas A3 训练系列产品 / Atlas A3 推理系列产品×Atlas A2 训练系列产品 / Atlas A2 推理系列产品×Atlas 200I/500 A2 推理产品×Atlas 推理系列产品×Atlas 训练系列产品×需要说明的是该支持矩阵来自仓库当前 README.md 的记录实际可用性以发布版本的配套产品文档为准。调用说明README 提供了一种官方调用方式图模式GE调用样例代码为 examples/test_geir_cumulative_logsumexp.cpp。同时从仓库结构可以推断该算子还配套了TensorFlow 插件通路framework/cumulative_logsumexp_tf_plugin.cpp与图融合推导通路op_graph/cumulative_logsumexp_graph_infer.cpp而按 tests/assets/golden.py 的注释说明该算子未暴露 aclnn 公开 APIACLNNTYPE aclnn_exclude也未新增 torch_npu eager 绑定因此当前不提供 aclnn/e2e 调用方式。图模式调用示例// 1. 初始化 GE mapAscendString, AscendString globalOptions {{ge.exec.deviceId, 0}, {ge.graphRunMode, 1}}; ge::GEInitialize(globalOptions); // 2. 构图输入 x (shape[2,4], FLOAT) 与 axis (shape[1], INT32, 值为 1) auto op ge::op::CumulativeLogsumexp(cumulative_logsumexp1); auto x ge::op::Data(x).set_attr_index(0); auto axis ge::op::Data(axis).set_attr_index(1); op.set_input_x(x); op.set_input_axis(axis); op.set_attr_exclusive(false); // 包含当前位置 op.set_attr_reverse(false); // 正向累积 op.update_output_desc_y(yDesc); // yDesc shape 与 x 相同 // 3. 建 Session 并运行 Session* session new Session(buildOptions); session-AddGraph(graphId, graph, graphOptions); session-RunGraph(graphId, input, output);完整流程含GenTensor辅助构造 host 侧 Tensor、输出结果校验请直接阅读 test_geir_cumulative_logsumexp.cpp其中示例数据为vectorint64_t xShape {2, 4}; vectorfloat xData {-3.0f, -2.0f, -1.0f, -0.5f, 0.25f, -0.75f, 1.0f, -4.0f}; vectorint32_t axisData {1};运行结束后程序会对每个输出元素与Golden()参考实现做容差校验|diff| 1e-4 1e-4 * |gold|全部通过则打印GE cumulative_logsumexp PASS。数值稳定实现与 SIMT 并行内核CumulativeLogsumexp 在 NPU 上的核心实现是 Ascend 950 上的 SIMTSingle Instruction, Multiple Threads内核位于 op_kernel/arch35/cumulative_logsumexp_simt.h。1. LogAddExp 数值稳定计算朴素计算log(e^a e^b)在a、b较大时会指数溢出。内核采用业界标准的稳定形式m max(a, b) return m log1p(exp(min(a, b) - m))并对 NaN、±inf 做了显式处理任一输入为 NaN 时直接返回a b最大值为inf时返回inf见 L48-L59。累积扫描的初始累加值取-inf保证首元素结果等于其自身log(e^x) x。2. 一维线性化与三因子分解tiling 阶段把输入按axis维分解为outerNum × axisNum × innerNum三个因子并写入共享 tiling 数据结构体定义见 cumulative_logsumexp_tiling_data.houterNumaxis之前各维的乘积axisNumaxis维长度innerNumaxis之后各维的乘积。kernel 通过线程索引线性化计算(outerIdx, axisIdx, innerIdx)每个输出元素y[outerIdx][axisIdx][innerIdx]独立扫描其前缀/后缀区间reverse决定扫描方向start axisNum-1, step -1exclusive决定扫描长度count axisIdx或axisIdx1随后用LogAddExp逐元素递推累加。3. 线程级并行与分块调度每个 block 启动THREAD_NUM 512个 SIMT 线程通过Simt::VF_CALLCumulativeLogsumexpKernelT(Simt::Dim3(THREAD_NUM), ...)派发见 L100-L110全局采用 grid-stride 循环linear blockIdx * threadNum threadIdx; linear threadNum * blockNum一个输出元素恰好由唯一线程计算天然无竞争、无需同步FP16 输入在加载时转成 FP32 参与计算__half2float累加结果写回时再转回 FP16__float2half_rn中间精度损失被控制在较低水平。4. 编译期模板分发内核通过schMode模板参数在编译期选择 FP32 / FP16 两种调度模式tiling key 定义见 cumulative_logsumexp_tiling_key.hTILING_KEY_FP32 0→ProcessfloatTILING_KEY_FP16 1→Processhalf。入口 op_kernel/arch35/cumulative_logsumexp.cpp 根据 tiling key 用if constexpr编译期选择分支避免运行期类型判断开销。Host 侧 Tiling 与 Shape 推导Tiling 流程Host 侧 tiling 函数CumulativeLogsumexpTilingFuncop_host/arch35/cumulative_logsumexp_tiling.cpp完成以下工作从平台信息获取 AIV 核数coreNumGetCoreNumAiv核数为 0 时报错读取axis常量值并校验区间[-dimNum, dimNum-1]负数归一化为axis rank解析x的 shape计算totalNum / outerNum / axisNum / innerNum校验axisNum 0读取exclusive、reverse两个属性写入 tiling 数据按ceilDiv(totalNum, coreNum)决定实际使用核数usedCoreNum调用SetBlockDim设置 block 维度依据数据类型设置 tiling keyFP32/FP16并通过TilingInputsDataDependency({1})声明 tiling 依赖 1 号输入即axis的常量数据。Shape 推导shape 推导op_host/cumulative_logsumexp_infershape.cpp非常直接输出y的维度数与每一维大小均与输入x完全一致输出数据类型等于输入数据类型图融合通路 op_graph/cumulative_logsumexp_graph_infer.cpp 中同样只推导数据类型shape 由框架层传递。测试与 golden 参考实现仓库在 tests/ 下提供了完整的验证配套Host 侧单测tests/ut/op_host/arch35/test_cumulative_logsumexp_tiling.cpp 验证 tiling 输出outerNum/axisNum/innerNum/exclusive/reverse与 block 维度tests/ut/op_host/test_cumulative_logsumexp_infershape.cpp 验证 shape 推导结果。golden 参考实现tests/assets/golden.py 基于torch.logcumsumexp实现参考输出reverse通过torch.flip先翻转再累积exclusive通过前置-inf列并narrow截尾实现二者与 README 的语义定义完全一致。tolerance 配置为cross_check标准、L1级别。# golden.py 中 exclusive/reverse 的等价实现逻辑 if reverse: tensor torch.flip(tensor, dims(axis,)) result torch.logcumsumexp(tensor, dimaxis) if exclusive: first torch.full([..., 1, ...], -float(inf)) result torch.cat((first, result.narrow(axis, 0, result.shape[axis] - 1)), dimaxis) if reverse: result torch.flip(result, dims(axis,))总结CumulativeLogsumexp 算子在 CANN ops-math 中以README 语义 OpDef 注册 Host tiling SIMT kernel golden 测试的标准算子工程结构落地exclusive与reverse两个属性通过 tiling 数据透传给 kernel分别控制前缀集合的包含性与扫描方向内核以 512 线程 SIMT 并行 稳定 LogAddExp 递推实现数值安全的累积计算当前仅支持 Ascend 950PR/950DT 上的 ND 格式 FLOAT/FLOAT16 数据。若要深入阅读源码推荐按 算子定义 → tiling → SIMT kernel → 图模式示例 的顺序展开可在数分钟内建立从算子语义到NPU 执行的完整认知链路。【免费下载链接】ops-math本项目是CANN提供的数学类基础计算算子库实现网络在NPU上加速计算。项目地址: https://gitcode.com/cann/ops-math创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表