news 2026/9/18 13:58:19

ATB Cumsum 算子深度解析:前缀和在 Ascend Transformer Boost 中的实现与调用链

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ATB Cumsum 算子深度解析:前缀和在 Ascend Transformer Boost 中的实现与调用链

ATB Cumsum 算子深度解析:前缀和在 Ascend Transformer Boost 中的实现与调用链

【免费下载链接】ascend-transformer-boost本项目是CANN提供的是一款高效、可靠的Transformer加速库,基于华为Ascend AI处理器,提供Transformer定制化场景的高性能融合算子。项目地址: https://gitcode.com/cann/ascend-transformer-boost

导读

Cumsum(累计和/前缀和)是 Transformer 推理与训练后处理中常用的基础算子,例如用于位置偏移换算、序列长度前缀和等场景。本文以 ascend-transformer-boost 仓库中的知识条目 .agent/knowledge/ops/other/cumsum/index.md 为骨架,结合路由文件与src/ops/ops_infer/cumsum/src/kernels/kernels/cumsum/的真实源码,完整讲解该算子的参数定义、合法性校验、双 Runner 执行路径(OpsRunner 与 ACLNN Runner)、Kernel 层 FP16/BF16 实现以及精度测试的 Hillis-Steele 模拟方法,帮助读者掌握在 ATB 框架下从图构建到内核执行的全链路工作原理。

一、算子定位:知识条目中的元信息

在 ATB 仓库的 Agent 知识体系中,Cumsum 被登记为一条完整的知识条目,其元数据如下(见 .agent/knowledge/ops/other/cumsum/index.md):

op: {name: "cumsum", category: "other", tier: "S", type: "single"} source: {repo_path: "src/ops/ops_infer/cumsum/"} knowledge: {status: "complete", last_extracted: "2026-07-06"}

其中:

  • category: other—— 算子不属于通信、Attention 或 Norm 等专项分类,而是归入通用基础算子集合(与 concat、slice、fill、transpose 等同目录,见 .agent/knowledge/ops/other/);
  • tier: S—— 表示该算子的知识完整度分级(S 为最高级,知识条目已 complete);
  • type: single—— 单输入单输出算子,对应源码中GetInputNum() == 1GetOutputNum() == 1
  • Runner: ops_runner / aclnn_runner—— 该算子同时具备两条执行路径:原生 Ops Runner 与基于 ACLNN 的 Runner;
  • Pipeline: 单阶段—— 无需多阶段图编排,一次运行即可完成计算。

路由文件 .agent/knowledge/routing/cumsum.md 进一步给出:分类为infer、复杂度M、共6 个源文件,并列出推荐阅读顺序(先看 Operation 定义,再看 Runner 与 Kernel)。

二、参数定义与约束:CumsumParam

算子参数定义在 include/atb/infer_op_params.h(infer::CumsumParam),其语义与取值范围如下:

字段类型默认值说明
axesSVector<int64_t>指定计算累加和的轴(维度),只能包含一个轴索引,且必须小于输入张量的维度数
exclusiveboolfalse累加结果是否从第 0 个元素开始。false:包含首元素(y[0] = x[0]);true:排他式前缀和(当前暂不支持
reverseboolfalse是否反向累加。false:正向前缀和;true:从末尾反向累加(当前暂不支持
rsvuint8_t[14]{0}预留字段,保持参数结构体大小稳定

参数创建时的校验逻辑位于 src/ops/ops_infer/cumsum/cumsum_operation.cpp 的CreateOperation<infer::CumsumParam>模板特化中,任何一项不满足都会直接返回ERROR_INVALID_PARAM并打印错误日志:

OP_PARAM_RSV_CHECK(opParam); if (opParam.axes.size() != 1) { ATB_LOG(ERROR) << "cumsumParam axes size must be 1"; return ERROR_INVALID_PARAM; } if (opParam.reverse) { ... } // "cumsum does not support reverse yet" if (opParam.exclusive) { ... } // "cumsum does not support exclusive yet"

也就是说,当前版本对外仅开放单轴、正向、包含首元素的累加能力,exclusivereverse虽然参数结构体中已预留,但传入true会直接报错。

三、源码文件清单与阅读路径

路由文件列出了 Cumsum 的全部 6 个源文件,它们构成Operation → Runner → Kernel三层结构:

文件角色
cumsum_operation.hOperation 定义:输入输出数量、InferShape 签名
cumsum_operation.cppOperation 实现:参数校验 +CreateRunner()决策
cumsum_ops_runner.h原生 Ops Runner 执行接口
cumsum_ops_runner.cpp原生 Ops 调用链:Fill + Cumsum 组合图
cumsum_aclnn_runner.hACLNN API 封装接口(两段式接口函数指针)
cumsum_aclnn_runner.cppWorkspace 计算 +aclnnCumsumV2调用

建议按路由文件的顺序阅读:先看cumsum_operation.h/.cpp理解算子对外契约,再分别跟进两条 Runner 路径,最后进入 Kernel 目录。

四、Operation 层:InferShape 与 Runner 决策

CumsumOperation继承自OperationBase(见 src/ops/ops_infer/cumsum/cumsum_operation.h),核心行为:

  • 输入/输出数量:各 1 个;
  • InferShape:输出张量 desc 直接拷贝输入 desc,即输出 shape、dtype、format 与输入完全一致outTensorDescs.at(0) = inTensorDescs.at(0),见 cumsum_operation.cpp);
  • InferShapeCheck / SetupCheck:校验axes[0]是否落在[0, dimNum)区间内,越界即报ERROR_INVALID_PARAM(cumsum_operation.cpp);
  • CreateRunner:当前实现直接创建CumsumOpsRunnerstd::make_shared<CumsumOpsRunner>(param_),cumsum_operation.cpp)。

值得注意的是,源码中同时存在并注册了CumsumOpsRunnerCumsumAclnnRunner两个 Runner(分别通过REG_RUNNER_TYPE注册,见 cumsum_ops_runner.cpp 与 cumsum_aclnn_runner.cpp),这与知识条目中“Runner: ops_runner / aclnn_runner”的记载一致——ACLNN 路径为算子提供了基于 CANN 统一算子的备选/并行实现。

五、Runner 层:两条执行路径

5.1 OpsRunner:Fill + Cumsum 的组合内核图

CumsumOpsRunner 在构造时构建了一个包含2 个节点的 KernelGraph:

kernelGraph_.nodes.resize(2); // nodes: 2 auto &fillNode = kernelGraph_.nodes[0]; // "FillOperation":按输入 shape 填充输出 auto &cumsumNode = kernelGraph_.nodes[1]; // "CumsumOperation":真正的前缀和内核
  • Fill 节点opDesc = {0, "FillOperation", AsdOps::OpParam::Fill()},通过inferShapePreFunc在 Launch 时依据输入 dims 动态设置Fill({false, {0}, inDim}),负责先把输出张量按 shape 填零(Kernel 层同时设置了MemsetInfo,见下文);
  • Cumsum 节点opDesc = {0, "CumsumOperation", asdParam},其中asdParam由 ATB 参数转换而来:
AsdOps::OpParam::Cumsum asdParam; asdParam.exclusive = param_.exclusive; asdParam.reverse = param_.reverse; for (std::size_t i = 0; i < param_.axes.size(); ++i) { asdParam.axis.push_back(param_.axes[i]); } cumsumNode.inTensors = {&xTensor}; cumsumNode.outTensors = {&resultTensor};

该 Runner 通过REG_OP_PARAM同时注册了FillCumsum两类算子参数,运行时由 Ops Runner 基础设施按图调度。

5.2 AclnnRunner:两段式 aclnnCumsumV2 封装

CumsumAclnnRunner 采用 CANN ACLNN 标准的两段式接口,通过函数指针在运行时从共享库动态加载:

  • aclnnGetWorkspaceSizeFunc_:签名(input, dim, exclusive, reverse, output, workspaceSize, executor),在SetAclNNWorkspaceExecutor()中调用,用于申请 workspace 并创建 executor;
  • aclnnExecuteFunc_:签名(workspace, workspaceSize, executor, stream),在LaunchAclnnKernel()中真正下发执行。

动态加载发生在LoadMethod()(cumsum_aclnn_runner.cpp),加载的符号为aclnnCumsumV2GetWorkspaceSize/aclnnCumsumV2。关键实现细节:

// 注意:cumsum支持多个轴,这里取第一个轴,因为aclnn接口只支持单个维度 int64_t dim = param_.axes.empty() ? 0 : param_.axes[0]; aclnnStatus ret = aclnnGetWorkspaceSizeFunc_( aclnnVariantPack_.aclInTensors.at(0)->tensor, // 输入tensor dim, // cumsum维度 param_.exclusive, // exclusive参数 param_.reverse, // reverse参数 aclnnVariantPack_.aclOutTensors.at(0)->tensor, // 输出tensor &(atbVariantPack_.workspaceBufferSize), // workspace大小 &raw_executor_ptr); // executor

由于 ACLNN 接口只支持单维,源码取axes[0]传入(与参数层强制axes.size() == 1的约束呼应)。BuildAclnnVariantPack()负责把 ATB Tensor 通过CallAclCreateTensor转换为aclTensor,并设置needUpdateTensorDataPtr = true以便复用 tensor 句柄。执行流通过GetExecuteStream(atbVariantPack_.context)获取,保证与 ATB 上下文中的 Stream 对齐。

六、Kernel 层:FP16/BF16 内核与确定性变体

算子内核位于 src/kernels/kernels/cumsum/cumsum_kernel.cpp,核心类CumsumKernel继承自KernelBase

  • CanSupport:校验参数类型为OpParam::Cumsum,且输入输出均为 1 个 tensor;
  • GetTilingSize:计算 tiling buffer 大小与轴常量张量(int64_t)之和;
  • InitImpl:调用CumsumTiling()完成 tiling,将输出 tensor 索引TENSOR_CUMSUM_OUTPUT_IDX = 2设置为Memset 目标SetMemsetInfo,即先清零输出),并把轴索引TENSOR_CUMSUM_AXIS_IDX = 1作为常量张量写入 kernelInfo。

针对不同数据类型派生了多个内核并注册:

内核类支持 dtype用途
CumsumF16KernelTENSOR_DTYPE_FLOAT16FP16 前缀和
CumsumBF16KernelTENSOR_DTYPE_BF16BF16 前缀和
CumsumF16DtmKernelFP16deterministic(确定性)变体
CumsumBF16DtmKernelBF16deterministic(确定性)变体

内核选择逻辑在 src/kernels/kernels/cumsum/cumsum_operation.cpp 的GetBestKernel()中:依据输出 dtype 与param.deterministic标志二选一。若输出 dtype 既不是 FP16 也不是 BF16,则返回nullptr并记录错误日志——当前内核仅支持 FP16 与 BF16 两种精度

InferShape 层同样校验axis.size() != 1直接失败("null or multi axis is not support now"),并规定输出与输入保持相同 dtype、format、dims。

Tiling 过程

src/kernels/kernels/cumsum/tiling/cumsum_tiling.cpp 中的CumsumTiling()通过TbeTilingRunner在 Host 侧完成形状与策略计算:

auto runner = AsdOpsGeRt::TbeTilingRunner() .SetName("Cumsum") .SetKernelName(kernelName) .AddInput(tensorDesc0.dtype, tensorDesc0.format, tensorDesc0.dims) .AddConstInput(TENSOR_DTYPE_INT64, TENSOR_FORMAT_ND, axisShape, axis.data(), ...) .AddOutput(tensorDescOut.dtype, tensorDescOut.format, tensorDescOut.dims) .AddAttrBool(param.exclusive) .AddAttrBool(param.reverse); return GetTilingFromRunner(kernelInfo, runner, binHandle);

即:输入张量 + 轴常量(ND 格式 int64)+ 输出张量 +exclusive/reverse两个布尔属性一起交给 TBE Tiling Runner,结果回填到kernelInfo供内核加载。

七、精度与测试验证:Hillis-Steele 前缀和

Cumsum 的测试位于 tests/apitest/kernelstest/cumsum/test_cumsum.py,其中对 FP16 路径的 golden 计算做了非常精细的处理——逐位模拟算子的 Hillis-Steele 并行前缀和算法,而不是直接使用np.cumsum

def hillis_steele_fp16(x, axis): # CumsumF16Kernel 的 fp16 累加实现是 Hillis-Steele 并行前缀和, # golden 必须逐位模拟该算法(实测与算子输出 maxAbs=0), # 用顺序 np.cumsum 或 fp32 累加都会与算子输出产生 fp16 ULP 级偏差。 x = np.array(x, dtype=np.float16, copy=True) n = x.shape[axis] d = 1 while d < n: cur = [slice(None)] * x.ndim; cur[axis] = slice(d, None) prev = [slice(None)] * x.ndim; prev[axis] = slice(None, -d) x[tuple(cur)] = np.float16(x[tuple(cur)] + x[tuple(prev)]) d *= 2 return x

测试覆盖四个用例,并带平台过滤注解(skip_310bskip_910aonly_910b):

用例shape参数平台限制
test_cumsum(128, 2222){"axis": [1]}跳过 310b/910a
test_cumsum_dtm(128, 1111){"axis": [1], "deterministic": True}跳过 310b/910a
test_cumsum_bf16(128, 2222){"axis": [1]}仅 910b
test_cumsum_bf16_dtm(128, 1111){"axis": [1], "deterministic": True}仅 910b

容差上,BF16 用rtol/atol = 2^-7,FP16 用rtol/atol = 2^-8torch.allclose比较。这个测试文件的价值在于:它揭示了内核实际的累加实现是Hillis-Steele 并行扫描而非顺序扫描,这对任何关心 FP16 前缀和逐位精度的开发者都是第一手证据。

八、如何在 ATB 中配置与使用 Cumsum

结合前述参数约束,在 ATB 图中挂载 Cumsum 的要点如下:

  1. 参数构造infer::CumsumParamaxes必须且只能包含一个轴索引,取值范围[0, 输入维度数)exclusivereverse保持默认false
  2. 输入输出:各 1 个 tensor,输出 shape/dtype/format 与输入完全一致(InferShape 直通),运行时输出张量会先被清零再写入累加结果;
  3. 精度要求:内核当前仅支持FP16 与 BF16输入输出,其他 dtype 在GetBestKernel()阶段会失败;
  4. 运行路径:通过CreateOperation(param, &operation)创建(内部完成上述全部校验),再由框架根据配置选择 OpsRunner 图路径或 ACLNN 路径执行;
  5. 调试辅助:算子支持ATB_LOG(INFO/DEBUG)日志(如 variantPack 打印、workspaceSize 打印),可在日志与调试指南(见 docs/日志与调试.md)中定位问题。

九、总结

从知识条目到源码,Cumsum 在 ascend-transformer-boost 中呈现出一条清晰的分层实现链路:

  • 契约层(infer_op_params.h + cumsum_operation.cpp):单轴、正向、包含首元素,shape 直通,参数严格校验;
  • 执行层(cumsum_ops_runner.cpp 与 cumsum_aclnn_runner.cpp):提供 Fill+Cumsum 组合内核图与aclnnCumsumV2两段式封装两种路径;
  • 内核层(cumsum_kernel.cpp + cumsum_tiling.cpp):FP16/BF16 两类内核、确定性变体、TBE Tiling;
  • 验证层(test_cumsum.py):Hillis-Steele 逐位模拟 golden,平台差异化覆盖。

对于需要在 Ascend 上做序列前缀和、位置偏移累计等后处理计算的开发者,这份从知识条目到内核的完整链路即是可直接参考的实战蓝本。

【免费下载链接】ascend-transformer-boost本项目是CANN提供的是一款高效、可靠的Transformer加速库,基于华为Ascend AI处理器,提供Transformer定制化场景的高性能融合算子。项目地址: https://gitcode.com/cann/ascend-transformer-boost

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/18 13:58:16

DNN-GOP3抗噪口语评测:中学生英语发音鲁棒性建模

简介&#xff1a;本资源是一篇聚焦教育智能化落地的学术论文&#xff0c;面向英语教学研究者、语音技术开发者及中高考考试系统建设者&#xff0c;着力解决大规模口语考试中因设备差异、环境噪音与非母语发音特征导致的自动评分不准问题。论文提出两种基于深度神经网络声学模型…

作者头像 李华
网站建设 2026/9/18 13:53:14

Flutter跨平台开发家庭药箱App的健康报告功能实践

1. 项目概述&#xff1a;家庭药箱管理App的健康报告功能作为一名长期从事移动应用开发的工程师&#xff0c;我最近在基于Flutter for OpenHarmony平台开发一款家庭药箱管理应用时&#xff0c;遇到了一个有趣的需求&#xff1a;如何将零散的健康数据转化为有价值的健康洞察&…

作者头像 李华
网站建设 2026/9/18 13:52:25

容器技术演进:从内核隔离到Docker镜像与Kubernetes编排

简介&#xff1a;一份系统梳理容器发展历史的Word文档&#xff0c;适合正在学习容器与Kubernetes的开发者、运维人员及架构师阅读&#xff0c;帮助理解容器技术真正要解决的问题及其在软件工程演进中的历史定位。资源围绕开发过程&#xff08;瀑布式、敏捷式、DevOps&#xff0…

作者头像 李华
网站建设 2026/9/18 13:51:56

如何十分钟把公众号搬进 RSS 阅读器?WeWe RSS 开源部署指南

如何十分钟把公众号搬进 RSS 阅读器&#xff1f;WeWe RSS 开源部署指南 【免费下载链接】wewe-rss &#x1f917;更优雅的微信公众号订阅方式&#xff0c;支持私有化部署、微信公众号RSS生成&#xff08;基于微信读书&#xff09; 项目地址: https://gitcode.com/GitHub_Tren…

作者头像 李华