已关闭
[Requirement|需求建议]: quantize_add_layer_norm 增加 Ascend 950 支持 #4496
chenqi_814540创建于 8月3日关闭于 28 天前
8月3日 添加了label:requirement
8月3日 将 boes129 设为负责人
Cchen-shuai
8月3日 关联了pull request:fix quant_batch_matmul_v3_transpose_fusion_pass torchdeletegate errorlog
8月3日 关联了pull request:fix quant_batch_matmul_v3_transpose_fusion_pass torchdeletegate errorlog
Cchen-shuai
8月3日 删除了关联的pull request:fix quant_batch_matmul_v3_transpose_fusion_pass torchdeletegate errorlog
8月3日 删除了关联的pull request:fix quant_batch_matmul_v3_transpose_fusion_pass torchdeletegate errorlog
8月4日 关联了pull request:[WIP]quantize_add_layer_norm算子支持950
29 天前 修改了issue 的描述
29 天前 修改了issue 的描述
29 天前 修改了issue 的描述
29 天前 修改了issue 的描述
29 天前 修改了issue 的描述
28 天前 修改了issue 的描述
28 天前 修改了issue 的描述
28 天前 修改了issue 的描述
28 天前 关闭了 issue
28 天前 添加了label:resolved
23 天前 修改了issue 的描述
背景(需求)
quantize_add_layer_norm是 (x1 + x2 + bias) → LayerNorm(mean/rstd, gamma/beta) → 静态量化 → y(INT8) + x(残差) 的融合算子,属于 LayerNorm-quant 家族:此前该算子仅支持 910B / 910_93 / Kirin,950 缺位:
def.cpp无AddConfig("ascend950")、算子目录内grep ascend950|arch35|regbase零命中、config/ascend950/目录不存在。同族add_layer_norm_quant已全量支持 950,补齐本算子即可让 LayerNorm-quant 家族(add_layer_norm_quant / quantize_add_layer_norm / dua_quantize_add_layer_norm)在 950 上完整可用,直接服务 W8A8 量化推理的归一化段。实现进展
已由 MR #8234 实现(单提交,基于 upstream/master;初始
9b3f1af1d,2026-09-10 为过 CI pre-commit 门禁 amend 为860058449—— 当前等待人工评审,欢迎到 MR 检视。以下展开 tiling 排产与 kernel 运算的具体做法。
tiling 策略
tiling 跑在 CPU 上、kernel 启动之前,回答:分几个核、每核几行、每轮往工作台(UB,约 256KB)搬多少,产出一张 12 字段的调度表 + 一把 tiling key。决策全部在 host 完成,kernel 只照表执行。
① shape 归一:
x=[8192,4096]、gamma=[4096]→ rows=8192、cols=4096(一行 = 一个归一化单元);cols 向上对齐到 32 的倍数(DMA 最小块 32B,int8 输出按 1B 定标)。② 切行(双取整回填):
rowsPerCore = ceil(rows / 核数) // 粗分 usedCoreNum = ceil(rows / rowsPerCore) // 活少时算实际需要几核 rowsPerCore = ceil(rows / usedCoreNum) // 回填抹平 rowsPerTailCore = rows - rowsPerCore×(核数-1) // 末核兜余数例:rows=8192、50 核 → 49 核各 164 行 + 末核 156 行;rows=10、50 核 → 只用 10 核(没有第②步会点亮 50 核、40 核空转)。
③ 排工作台,两种策略二选一(整行放得下优先 full_load):
工作台(UB,约 256KB)有限,一行数据可能就超了。分界线一条:一行能不能整个放上工作台?
full_load 优先的原因:两遍法数值路径与 910B 完全一致,golden 比对友好;welford 是"装不下"的诚实兜底,用"读两遍"换"装得下"。两个都排不下 → 明确报错,不静默算错。
策略① full_load:一张预算表定每轮行数。 把 UB 摆成固定区(不随行数变,先扣)+ 行区(每装一行都要花这么多):
跟着算一遍(x=[8192,4096]、bf16 主路、scales=fp32、广播 bias、无 zp):
两本账分开记:广播 bias 整行常驻、不随行数涨,并入权重区(weightTensorNums_ +1);逐元素 bias 随行增长,才进每行开销(full_load 记在 inOutCols、welford 记在 elewiseSliceNums)——谁也不漏、谁也不重。
策略② welford:按"每列开销"记账。 full_load 排不下时,固定装 1 行 × colsPerLoop 列,预算按每列花多少字节算(所有切片 ×双缓冲):
跟着算一遍(超宽行:cols=131072、fp16、广播 bias、无 zp):
两个精修动作:均分重算——cols 恰能被轮数整除时,把 colsPerLoop 改成均分值,每轮等长、没有残缺尾巴,kernel 收尾走无分支的"对齐版"快路;对齐 64——让寄存器按整条装载。
④ 归并树参数:binaryAddNum / K / LastNum:求均值要把一行(或一片)加起来,调度表带三个"归并树形状"字段,把元素个数换算成寄存器级二叉归并树的参数:
K = ⌈log₂(部分和条数 ÷ 64)⌉:条数 >64 时每归并一级条数减半,K 级后恰好压进一条寄存器(64 个标量),末层 ReduceSum 收头。常规隐藏宽度(≤8192)全是 K=0,行宽每大 64 倍多一级(16384→K=1、65536→K=3)。设计动机:跨寄存器通道的 ReduceSum 又贵又慢,元素级 Add 便宜——先用便宜的加法把数据折半,贵的归约只在末层用一次。
⑤ 组钥匙:
key = 8000 + 策略(0/100) + bias(1 逐元素/2 广播) + 量化模式(0 mul / 10 div / 20 per_tensor);上例 bf16+广播+per_channel → 8012。kernel 运算(NPU 侧)
全链 fp32:x1/x2/bias(bf16/fp16)装载时各自 Cast 升 fp32 再相加,mean/var/仿射/量化全程 fp32,仅两头转换(残差 x 出口 Cast 降回原 dtype;y 的 int8 本是终点)。
full_load 两遍法求 mean/var:先扫一遍求均值、再扫一遍求方差,加法顺序与 910B 完全一致。行内求和使用"对折 + 归并树"。背景:整行数据摊在若干条向量寄存器里(每条 64 个数),硬件加法分两种身价:
AddReduceSum经济账(4096 例):朴素 ReduceSum×64 + 末层×1 = 65 条贵指令;对折 Add×32 + ReduceSum×32 + 1 = 32 条便宜 + 33 条贵。4096 个数加成 1 个共 4095 次加法、两种做法次数相同——省的不是次数,是把恰好一半的加法从贵引擎搬进便宜引擎。第二遍算 var 重读 x 的 fp32 副本,同一套树形再用一遍(三个归并树参数即为此下发)。
welford 单遍流式统计(宽表路径):一行放不下就切段流式——读一段、更新一次统计量、扔掉。数据流:
三行更新:
收尾用 Chan 合并公式把 P 份部分统计并成整行:
数字验证(行 [1,3,5,7],P=2、J=2):切段 [1,3] / [5,7],滚出 mean=[3,5]、M2=[8,8];合并 mean=(3+5)/2=4 ✓,var=(8+2×1 + 8+2×1)/4 = 5 ✓——不加
J·delta²修正会算成 16/4=4 ≠ 5,漏的正是列间差异。J·delta_p²是"列间差异"修正(总方差 = 组内 + 组间;M2_p 只记了组内,M2 为离差平方和、从没除过任何东西)。数值上全程只累积小偏差的乘积、不碰大数平方和,这是不用E[x²]−E[x²]朴素一遍法的原因。量化收尾:per_channel 走高精度向量除(norm ÷ scales),mul/per_tensor 走乘;标量 scale 用"GM 拷 1 元素 + DIST_BRC 广播装载"整条进向量乘。round 由三步链完成(RINT 四舍五入 → fp16 中转 → int8 截断,舍入模式定死在 CastTrait)。welford 路径统计完重读一遍输入做量化(切片未驻留,带宽换内存);x 残差在统计遍顺手写回。
源码级复用
add_layer_norm的 arch35 共享头与norm_common归约原语(编译期 include,运行时零依赖),op_host/CMakeLists 声明DEPENDENCIES(norm 族 39 算子惯例)。验证
真实 Ascend 950 环境(蓝区,CANN 9.0.0-beta.2);910B/910_93 全矩阵回归(910_93 为编译 + 注册验证);2026-09-07 环境重置后对最终提交重新 clone 复验,以下均为终态:
rms_norm_quant_v2等同此限制)。gen_data.py/compare_data.py);判据:浮点 x 严格容差,INT8 y 允许 ±1 舍入抖动且占比 ≤2%(welford 与两遍法加法顺序不同的固有差异),差 2 判错。.o与 binary.json 6 条一一对应,binary_info_config注册正确。关联
feat(norm): quantize_add_layer_norm 增加 Ascend 950 (arch35/regbase) 支持)