已关闭
[Requirement|需求建议]: 【社区任务】tile算子需求 #897
刘十一创建于 3月6日关闭于 6月8日
3月6日 关联了pull request:【社区任务】AscendC实现tile算子开发任务贡献
3月7日 关联了pull request:【社区任务】AscendC实现tile算子开发任务贡献
sunchun
3月9日 评论:
3月9日 评论:
/assign @ElevenLiu


3月9日 将 ElevenLiu 设为负责人
sunday
3月19日 评论:
3月19日 评论:
/assign @ElevenLiu


CANN-robot
3月19日 评论:
3月19日 评论:
sunday
3月19日 评论:
3月19日 评论:
/assign @ElevenLiu


CANN-robot
3月19日 评论:
3月19日 评论:
4月24日 关联了pull request:【社区任务】02-03 Tile算子开发任务贡献
6月8日 issue状态由 进行中 改变为 已完成
6月8日 关闭了 issue
Thanks for sending an requirement! Please fill in the following template to help quickly solve your problem.
一、背景信息 (必填)
使用AscendC对TBE实现的tile算子进行重构,实现了AscendC实现的Sqrt算子对Atlas 800I/T A2硬件的适配。
二、价值/作用 (必填)
“Tile算子”是高性能AI计算中用于分块(tiling)优化的核心编程抽象,广泛应用于GEMM、FlashAttention等关键算子的开发。实现了tile算子的AscendC实现,替代原有TBE算子在昇腾硬件上的适配。
三、设计方案 (必填)
3.1 使能方式
通过 ACLNN 框架使能,对应接口为
aclnnRepeat。调用流程为标准的两段式接口:aclnnRepeatGetWorkspaceSize:计算 workspace 大小aclnnRepeat:执行 Tile 计算底层通过 ACL runtime 调用 AscendC kernel(
tile_kernel_<dtype>)完成计算。3.2 需求总体设计
3.2.1 Host 侧设计
3.2.1.1 分核策略
采用两级自适应分核策略,根据数据规模动态选择:
策略一:按 outerCount 均分(默认)
将输出张量视为
outerCount × outputInnerDim的二维结构,其中outputInnerDim = inputShape[N-1] × multiples[N-1],outerCount = totalOutputElems / outputInnerDim。将 outerCount 行均分到各 AI Core:策略二:按 mult 维度细粒度切分(splitByMult)
当
outerCount < blockDim且innerMult > 1时,仅按外层行数分核会导致大量核空闲。此时将工作量按outerCount × innerMult二维展开,每个核负责若干(row, mult)组合:3.2.1.2 数据分块和内存优化策略
数据分块策略:
Tile 算子将输入数据视为多维张量,经 Host 侧维度合并优化后,简化为最多 8 维的等价问题。数据按最内层维度(innerDim)为基本处理单位进行分块:
innerDim = inputShape[N-1]:最内层维度大小innerMult = multiples[N-1]:最内层重复倍数outputInnerDim = innerDim × innerMult:输出最内层维度大小outerCount = totalOutputElems / outputInnerDim:外层循环次数维度合并优化:
Host 侧在 tiling 计算前对 shape 和 multiples 做等价变换,减少 kernel 内循环次数:
multiples[i] == 1,将维度 i 合并入维度 i-1(shape[i-1] *= shape[i]),扩大 innerDimshape[i] == 1 && multiples[i] == 1的维度合并示例:
LocalMemory(UB)使用策略:
每个 AI Core 分配 3 个 buffer,Host 侧通过 PlatformAscendC 动态获取 UB 大小后三等分:
单次可处理的最大元素数(bufElems)计算公式:
数据对齐处理:
DataCopy 要求搬运元素数为 32 字节对齐(即 C0Count 的整数倍),处理策略为:
innerDimAligned = ceil(innerDim / C0Count) × C0Count3.2.1.3 tilingKey 规划策略
当前 Tile 算子使用统一的 tiling 结构体
TileTilingData,kernel 侧根据运行时参数动态选择处理路径,不使用 tilingKey 区分编译时分支。TileTilingData 结构体包含以下字段:kernel 侧根据以下运行时条件动态选择 5 条处理路径:
outerCount < blockDim && innerMult > 1innerDim 对齐 && innerMult >= 4 && innerDim*2 <= bufElemsoutputInnerDim 对齐可放入 UB && innerDim 对齐 && innerMult > 2 && 不走 Doubling3.2.2 Kernel 侧设计
3.2.2.1 Kernel 侧实现描述
AscendC Tile kernel 采用模板化设计,通过
TileOpImpl<T>类封装,支持 12 种数据类型的统一处理。每种类型通过宏DEFINE_TILE_KERNEL生成独立的 kernel 入口函数。整体流程:
Init 阶段:从 GM 读取 TileTilingData,初始化形状、步长等参数;根据分核策略计算当前核的工作范围
[myStartRow, myEndRow);初始化 GM 指针和 UB buffer(inQue、outQue、tmpBuf)。Process 阶段:根据运行时参数选择最优处理路径(5 条路径),核心思路是将输出张量按
outerCount × outputInnerDim展开,每次处理若干外层行,对每行在最内层维度上做 innerMult 次重复拼接。5 条优化路径详述:
路径 1:ProcessSplitMult(多核分 mult)
outerCount < blockDim && innerMult > 1outerCount × innerMult展开,每个核处理若干(row, mult)组合路径 2:ProcessDoubling(UB 内倍增写出)
innerDim 对齐 && innerMult >= 4 && innerDim * 2 <= bufElemsinnerDim → 2×innerDim → 4×innerDim → ...),达到 bufElems 上限后一次性大块写出到 GMceil(outputInnerDim / maxDoubledSize)次路径 3:ProcessBuild(UB 内构建完整行)
outputInnerDim 对齐可放入 UB && innerDim 对齐 && innerMult > 2 && 不走 Doubling路径 4:ProcessGather(Gather 元素重排)
innerDim 非对齐 && innerMult > 1 && innerDim <= 16 && outputInnerDim <= 32Gather指令(VEC 管线)的元素级重排能力,绕过 32B 对齐限制。预先构建字节偏移表(offset table),一次 Gather 调用将多行 input 重排为完整的 tile 输出路径 5:ProcessPerRow(逐行处理)
源地址计算(SrcOff 函数):
对于第
outerIdx行输出,其对应的输入起始地址通过多维坐标映射计算:3.2.2.2 AscendC 实现流程图
ProcessGather 详细流水线:
3.2.2.3 AscendC 实现流程图与 TBE 流程图存在的差异点和原因
tbe.broadcast+auto_schedule自动生成调度3.3 支持硬件
3.4 算子约束限制
四、特性交叉分析
五、可维可测分析
5.1 精度标准 / 性能标准
精度标准:
Tile 为纯数据搬运算子(无浮点计算),精度误差恒为 0。具体验收标准:
测试覆盖:12 种数据类型 × 13 种 shape = 156 组,全部通过。
aclnn 端到端验证:8 种类型 × 12 种 shape = 96 组,通过 torch_npu tensor.repeat() 全部通过。
性能标准:
使用所有核计算时,性能不低于原有 TBE 算子的 95%。
测试环境:Atlas A2 系列, blockDim=24, warmup=50, repeat=200
6 种数据类型 × 4 个基准场景 = 24 组对比,全部达标(≥ 95%):
最低比率 102%(float32 large_3D),最高 423%(int8 large_3D),24 组全部 ≥ 95%。