已关闭
[Requirement|需求建议]: 【社区任务】KLDivV2算子AscendC实现贡献 #2276
Xzz创建于  7月21日关闭于  8月4日
Xzz
Xzz
7月21日 创建

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

一、背景信息

KLDivV2算子实现Kullback-Leibler散度的计算,对应PyTorch中的torch.nn.functional.kl_div接口。该算子用于度量两个概率分布之间的差异,是训练知识蒸馏、变分自编码器(VAE)、强化学习中策略优化等场景的核心损失函数。

当前CANN内置的KLDiv实现仅支持ascend950平台,本需求为Atlas A2/A3训练系列产品提供高性能的AscendC实现。

二、价值/作用

  • 训练场景刚需:KL散度是知识蒸馏(Knowledge Distillation)中教师-学生模型对齐的标准损失函数,广泛应用于大模型压缩、模型轻量化部署
  • 框架对齐:PyTorch的F.kl_div在训练流程中被大量使用,缺少该算子会导致模型无法在昇腾平台上训练或需要走CPU回退路径
  • 性能收益:自定义AscendC实现相比AICPU实现有数量级的性能提升,对训练吞吐量有直接贡献

三、设计方案

3.1 使能方式
  • Aclnn直调:通过aclnnKlDiv两段式接口调用
  • 图模式:通过GE IR构图调用(OpType: KLDivV2)
3.2 总体设计

计算公式:

  • 默认模式(log_target=false):output = target * (log(target) - input),其中target≤0的位置输出置零
  • log_target模式(log_target=true):output = exp(target) * (target - input)

归约方式(reduction属性):

  • none(0):逐元素输出,output shape与input相同
  • mean(1):输出所有元素的均值,output为标量
  • sum(2):输出所有元素的求和,output为标量
  • batchmean(3):输出求和后除以batch维度(第0维),output为标量
3.2.1 算子支持的数据类型
输入/输出 数据类型 数据格式
x (input) float32, float16, bfloat16 ND
target float32, float16, bfloat16 ND
y (output) float32, float16, bfloat16 ND

x和target的数据类型必须一致,输出类型与输入一致。

3.2.2 host侧设计

InferShape:

  • reduction=none时,输出shape与输入x相同
  • reduction=mean/sum/batchmean时,输出shape为[1](标量)

Tiling策略:

  • 通过platform_ascendc::PlatformAscendC动态获取核数和UB大小
  • 多核均分:按元素总数在AIV核间均匀切分(大核/小核策略),精确切分避免尾部越界
  • UB分块:根据数据类型计算每tile可处理的元素数
    • float32: UB / (6 × BLOCK_SIZE × BUFFER_NUM) 个block(6份:2输入+1输出+2计算缓存+1归约缓存)
    • float16/bf16: UB / (8 × BLOCK_SIZE × BUFFER_NUM) 个block(8份:额外需要fp32临时缓存)
  • 归约场景单核快路径:当总元素数≤8192且reduction≠none时,使用单核避免跨核SyncAll开销
  • 模板参数(tiling key):按数据类型分3个模板实例(float16=0, float32=1, bfloat16=2)
3.2.3 kernel侧设计

整体流水:CopyIn → ComputePointwise → CopyOut(三级流水,双缓冲)

精度保障:

  • float16/bfloat16输入先Cast到float32进行所有计算(Log/Exp/Mul/Sub),避免低精度下的数值不稳定
  • 计算完成后再Cast回原精度输出
  • fp32→fp16转换使用CAST_NONE(round-to-nearest-even,与PyTorch一致)
  • fp32→bf16转换使用CAST_RINT(AscendC对bf16的正确舍入模式)

target≤0掩码实现(非log_target模式):

  • 使用Maxs(target, TINY) + Log避免log(0)
  • 通过max(target,0) / (max(target,0)+TINY)构造软掩码(target>0→~1, target≤0→~0)
  • 乘以掩码实现条件置零,避免分支指令

归约实现:

  • 循环内用向量Add累加各tile结果到accum缓存(避免每tile的标量同步阻断流水)
  • 循环结束后一次ReduceSum得到本核部分和
  • 多核场景:各核通过workspace写入部分和 → SyncAll → core0汇总
  • 单核快路径:直接输出,省去SyncAll和workspace往返
3.3 支持硬件
硬件平台 SoC版本 支持状态
Atlas A2训练系列产品 ascend910b ✓
Atlas A3训练系列产品 ascend910_93 ✓

3.4 算子约束限制

  • x和target的shape必须完全一致(不支持broadcast)
  • 输入维度不超过8维
  • 数据格式仅支持ND
  • 数据类型仅支持float32、float16、bfloat16,且x和target类型必须一致
  • reduction属性仅支持none/mean/sum/batchmean四种取值

💡 备注

likedislike
Xzz
Xzz
7月21日 评论:

/assign

likedislike
CANN-robotCANN-robot成员
7月21日 将 qq_64858158 设为负责人
XzzXzz
7月22日 关联了pull request:feat: add KLDivV2 operator for Atlas A2/A3
CANN-robotCANN-robot成员
8月4日 关闭了 issue
CANN-robotCANN-robot成员
8月4日 添加了label:resolved