已关闭
[Requirement|需求建议]: LpLoss算子AscendC实现贡献 #2392
洋-----创建于  4月28日关闭于  5月6日
洋-----
洋-----
4月28日 创建

Thanks for sending an requirement! Please fill in the following template to help quickly solve your problem.

Backgroud(背景信息)

使用AscendC对LpLoss算子进行开发与重构,实现了AscendC实现的LpLoss算子对Atlas A2 训练系列产品(Atlas 800I/T A2)硬件的适配。

Origin(信息来源)

浙工大-智能计算研究所

Benefit / Necessity (价值/作用)

LpLoss算子的主要功能是计算预测值(predict)与标签值(label)之间的Lp范数损失。该算子当前主要支持p=1的场景,即计算逐元素的绝对值误差(L1 Loss)。在模型训练和评估场景中,该算子常用于回归任务或作为各种正则化项的基础计算模块,以衡量预测结果与真实情况的偏差。

该算子支持灵活的规约模式(reduction),包括不规约输出逐元素损失(none)、输出所有元素损失的平均值(mean)以及输出求和值(sum)。实现了LpLoss算子的AscendC实现,有效替代原有算子在对应昇腾硬件路径上的实现,且进一步优化了在bfloat16和float16下的计算精度与性能。

Design(设计方案)

host侧设计

Host侧由算子定义、推导与tiling三部分构成,核心职责是把输入约束、并行策略和kernel运行参数固化为可直接消费的tiling数据。

(1) 算子定义与推导行为

在定义侧,输入为predict和label,输出为y;输入和输出dtype支持float16、float32、bfloat16。Shape推导依赖于属性reduction:当reduction="none"时,输出y的shape与输入predict完全一致;当reduction="mean"或"sum"时,输出y的shape被推导为0维标量。AICore配置启用动态shape与动态rank能力。

(2) 输入合法性与广播约束

输入张量predict和label的shape必须完全一致,底层Kernel不支持广播机制(若需要广播,在上层aclnn API封装处会提前调用BroadcastTo小算子进行处理)。此外,输入和输出的数据类型必须保持严格一致,且数据格式仅支持ND。

(3) 分核策略与数据切分

分核与切分由Tiling阶段自动根据硬件Unified Buffer (UB) 大小和输入数据类型推算。策略如下:

首先根据数据类型(fp32、fp16/bf16)以及是否需要规约(reduction),计算每个数据元素所需的UB空间比例(ubDataNumber)。

根据实际的UB空间上限,评估采用双缓冲(Double Buffer)还是单缓冲(Single Buffer),以此作为生成TilingKey的依据。

结合系统总数据量和多核数量,使用大核(bigCore)和小核(smallCore)策略来进行任务均匀分配。大核处理更多的Block数据,小核处理剩余部分,从而保证在数据量无法整除核数时的负载均衡。

(4) 规约内存规划

如果算子属性为规约模式("mean"或"sum"),Host侧不仅会配置Tiling参数,还会为Kernel申请额外的Workspace内存,用于跨核数据同步(SyncAll)以及暂存每个Core计算的局部累加结果(Partial Sum)。

kernel侧设计

kernel采用模板类 + TilingKey分发设计,整体执行链路针对是否需要规约拆分为ProcessNone与ProcessReduce两条执行路径。内部按tile循环执行CopyIn、Compute、CopyOut。

(1) 入口分发与数据类型路径

Kernel入口通过TilingKey(区分双缓冲和单缓冲模式schMode)分发到对应的具体实现,再根据预测值、标签值的类型实例化对应模板。根据算子是否需要Reduce,模板会分别初始化不同的内部结构与队列。

(2) Init阶段

Init根据Host下发的Tiling数据(大核/小核切分参数),计算当前核处理的全局偏移(globalBufferIndex)和实际处理的数据量(coreDataNum)。

随后完成GM(Global Memory)窗口绑定。

本地资源方面,初始化双缓冲/单缓冲的输入队列(TPipe)和输出队列。若是float16或bfloat16类型,还会额外申请float32格式的计算缓冲区(calcBuf),以便提升计算精度;若是规约模式,还会初始化用于跨核同步和Reduce的Buffer。

(3) Process与tile循环

根据IS_REDUCE的值走不同流程。对每个Core分配的数据量,按tileDataNum切分为多个tile进行循环。满tile直接处理,尾块(tail block)则根据动态长度限制处理量。

(4) CopyIn阶段

从predict和label的GM地址向Local Tensor搬运数据。满tile直接DataCopy;对于尾块(Tail tile),通过设置DataCopyPad按实际剩余长度搬运并补齐数据,避免越界访问。

(5) Compute阶段

核心逻辑是计算 y = |predict - label|。

对于float32路径:直接对输入执行Sub(相减)和Abs(绝对值)操作。

对于float16与bfloat16路径:为保证精度,先将输入使用Cast转换为float32格式放入临时计算缓冲,执行Sub和Abs后,再将结果Cast回对应的原始数据类型(bfloat16使用CAST_RINT,float16使用CAST_ROUND)。

如果处于规约模式(ProcessReduce):不会立即进行格式回退,而是在当前核内调用ReduceSum,将各个Tile的float32格式差值累加到该核局部的累加器中。

(6) CopyOut与Global Reduction阶段

对于ProcessNone模式:计算结果写回输出队列,并通过DataCopy写回至GM对应的偏移位置中。

对于ProcessReduce模式:在核内所有的Tile处理完毕后,执行全局归约操作。首先通过SyncAll执行全表屏障同步;接着由0号核(Core 0)从Workspace中读取其他所有核的局部累加和,执行全局ReduceSum;如果是"mean"模式,则将结果乘以meanFactor(1.0 / totalNum);最后将结果Cast为输出数据类型并写回GM的首地址。

算子支持的数据类型

float16、float32、bfloat16

likedislike
洋-----洋-----
4月28日 关联了pull request:AscendC实现LpLoss算子贡献
oscillatedoscillated成员
4月28日 将 m0_59314318 设为负责人
洋-----洋-----
4月28日 关联了pull request:AscendC实现LpLoss算子贡献
Ffulltower成员
4月29日 将 chenfeng61 设为负责人
Ffulltower成员
4月29日 移除了负责人 m0_59314318
fulltower成员
5月6日 评论:

需求已合入,此issue关闭

likedislike
Ffulltower成员
5月6日 issue状态由 进行中 改变为 已完成
Ffulltower成员
5月6日 关闭了 issue
CANN-robotCANN-robot成员
5月6日 添加了label:Accepted