已关闭
[Requirement|需求建议]: Quantize算子补齐ascend910b原生AscendC 实现 #4047
zhaohujie创建于  7月12日关闭于  8月8日
zhaohujie
zhaohujie
7月12日 创建

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

Backgroud(背景信息)

Quantize 算子在本仓当前仅覆盖 ascend950:

  • kernel 入口 quant/quantize/op_kernel/quantize_apt.cpp 只 #include arch35/*_regbase.h,并以 __NPU_ARCH__ == 3510 守护;
  • host tiling 仅存在于 quant/quantize/op_host/arch35/;
  • 二进制配置仅有 quant/quantize/op_host/config/ascend950/;
  • AICore().AddConfig 也只声明了 ascend950。

因此在 ascend910b(Atlas A2 / DAV_2201) 上没有可用的 Quantize kernel。与此同时,Quantize 在 CANN 9.0.0
部署包中对所有 SoC 均未部署 builtin(aic-*-ops-info-*.json 中查无此 OpType)。两者叠加的结果是:在 910b 上
既没有开源实现、也没有内置实现可回退,aclnnQuantize 无法落到实际 kernel。

需求:为 Quantize 补齐 ascend910b 的原生 AscendC 实现(DAV_2201 标准编程模型,非 regbase 路径),
使其在 910b 上能通过既有的 aclnnQuantize 两段式接口正常调用,行为与 ascend950 侧保持一致。

Origin(信息来源)

基础软件Agent算子迁移

Benefit / Necessity (价值/作用)

  • 量化是 LLM / CV 推理的基础算子,而 Atlas A2(910b)是当前主力训练与推理硬件。Quantize 在该平台缺失,
    会导致依赖它的量化子图无法下沉为单算子调用。
  • 消除上层的 SoC 分支:补齐后 910b 与 950 共用同一 OpType (Quantize) 与同一 aclnnQuantize 两段式接口,
    调用方无需按芯片做条件分支或退化实现。
  • 典型应用场景:per-tensor / per-channel 的权重与激活量化(INT8 / UINT8 / INT32 输出),
    例如 W8A8 推理的量化节点、量化感知训练前向的 quantize 节点。

Design(设计方案)

落点:experimental/quant/quantize/(新增算子按仓库约定先落 experimental/)。复用源算子 SoC 无关的
aclnn / L0 接口层,仅补 910b 的 kernel + tiling + 配置。

计算语义:y = saturate_cast_to(dtype)( round( x / scales + zero_points ) ),
固定 RoundMode = round-to-nearest、DivMode = div、SqrtMode = none。

kernel(op_kernel/quantize.{cpp,h},DAV_2201 标准编程模型):统一 fp32 计算路径,避免 dtype 笛卡尔积膨胀:

x (DTYPE_X)  ->  fp32                  # Cast;x 本身为 fp32 时直通
fp32         ->  Muls(1 / scale)       # 标量倒数:per-tensor 取一次;per-channel 逐输出行取
fp32         ->  Adds(zero_points)     # zero_points 缺省时跳过该步
fp32         ->  DTYPE_Y               # 饱和 CastOut:int32 直接 rint;
                                       # int8/uint8 走 fp32 -> int32 -> half -> int8/uint8 饱和阶梯

tiling(op_host/quantize_tiling.{cpp,h}):两条 tiling key —
per-tensor(按元素做多核切分)与 per-channel(按输出行切分,行内共享同一组 scale / zero_points);
UB 侧按 baseLen 切分并开 double buffer。

def:op_host/quantize_def.cpp 增加 AICore().AddConfig("ascend910b");沿用同一 OpType Quantize。

接口:交付可解析、可调用的 aclnnQuantizeGetWorkspaceSize / aclnnQuantize。

关键实现点(易踩坑):kernel 二进制按 (x, scales, y) 的 dtype 组合去重分发,
而可选输入 zero_points 的 dtype 不在分发键内。因此 zero_points 必须按其运行时真实 dtype 读取
(dtype 码由 tiling 携带),不能依赖 kernel 的编译期占位类型 —— 否则 INT32 的 zero_points 会被分发到
以 INT8 编译的二进制、并以 1 字节步长误读;该错误在 per-channel(索引 > 0)下会取到错误字节,
而在 per-tensor(索引 0)下因低字节恰好正确而不易暴露。

支持范围(首版):

  • 模式:per-tensor、per-channel(axis 语义);
  • dtype:x ∈ {FLOAT, FLOAT16, BFLOAT16}、scales ∈ {FLOAT, BFLOAT16}、
    zero_points ∈ {INT8, UINT8, INT32, BFLOAT16, 缺省}、y ∈ {INT8, UINT8, INT32};
  • 属性:dtype(必选)、axis(可选,默认 1)。

暂不支持(后续扩展):fp8 输出(HIFLOAT8 / FLOAT8_E5M2 / FLOAT8_E4M3FN —— ascend910b 无 fp8 能力)、
per-head、per-channel-nddma、FP32 zero_points。

验收方式:

  • UT:tests/ut/op_host(tiling + infershape)、tests/ut/op_api(aclnn dtype 与错误码矩阵)、
    tests/ut/op_kernel(ICPU_RUN_KF 对 numpy golden);
  • ST:tests/st/aclnnQuantize/ ATK 用例集,判据 stand_quantize(|diff| <= 1),对 CPU golden
    saturate_cast_to_y(rint(x / scales + zero_points)),覆盖 per-tensor / per-channel、三种 x dtype、
    三种输出 dtype、饱和边界与空 tensor。
likedislike
zhaohujie
zhaohujie
7月12日 评论:

/assign @zhaohujie

likedislike
CANN-robotCANN-robot成员
7月12日 将 zhaohujie 设为负责人
zhaohujiezhaohujie
7月12日 修改标题为 “[Requirement|需求建议]: Quantize算子补齐ascend910b原生AscendC 实现”,原标题为“[Requirement|需求建议]: Quantize 算子补齐 ascend910b 原生 AscendC 实现”
CANN-robotCANN-robot成员
8月8日 关闭了 issue
CANN-robotCANN-robot成员
8月8日 添加了label:resolved