本文へ移動
cccskills
無料GitHub で公開

quantization-dev

量化格式契约与位级对齐:从设备字节反推量化器的**编码公式、舍入模式、scale 粒度、退化块规则**, 并据此重实现/融合量化器(MXFP8 e8m0、int8 perblock、fp8 perchannel 等), 用「同进程同数据 + 独立参考实现 + 中点与退化输入全覆盖」做到**逐字节精确**。 当自研量化 kernel 与框架算子**对不上**、需要逆向某个量化器的数值契约、需要判断 「量化残差算不算可接受」、或要在融合内核里复现 aclnn 量化语义时使用此 skill。 即使用户只说「量化结果和参考不一致」「这个 scale 怎么算出来的」「融合量化器精度对不上」 而未提"契约",也应触发。**注意**:单纯选量化档位/配置(该不该开量化、开哪一档)走 dit-perf-opt;算子级性能调优与 DSL 选型走 operator-dev; 并行作用域导致的静默失效(DiT 侧「改了并行但不报错也没生效」的判定)走 dit-parallel-opt。

インストール方法を見る

含まれるファイル(5)

  • SKILL.md35.7 KB
  • evals/evals.json14.5 KB
  • references/contract-reverse-engineering.md10.5 KB
  • references/lora-merge-and-precision.md15.8 KB
  • references/online-quant-contract.md6.1 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

量化契约与位级对齐

0. ⚠️ 适用范围:本 skill 的结论硬绑定到具体环境,必须先复测再采信

本文档所有公式、常量、数字与"最优参数",都来自一次特定环境的实测(下表各维度的具体取值 见会话产物归档 {run_results_dir}/archive/,正文只留取数方式):

维度来源环境
芯片目标设备 —— 现场查 core 数 / UB 容量(设备属性 / 算子 UT)
软件栈特定版本的 CANN / triton-ascend / torch_npu / MindIE-SD
模型本案例模型(hidden / heads / head_dim 等几何见归档),少步蒸馏
形状每 rank (1, S, N/world, D) 符号形态(N = head 数,world = 并行度);S 的具体取值见归档

换任何一项,本文档的数字都不保证成立。 具体分四类:

  1. 硬规格(grid 上限、core 数、UB 容量)—— 可查文档确认,但要确认;
  2. 该版本的软件行为(round_mode 取值限制、支持的后端布局、triton 对 cast 的优化、量化算子的 tiling 边界、退化块规则)—— 换版本必须重跑;
  3. 性能与收益数字(加速比、耗时、占比)—— 随拓扑、并发、机器负载变化,不可移植;
  4. 阈值与容差(字节一致率门限、"多少差异算正常")—— 是该模型/该任务类型的属性,不可跨任务类型迁移。

特别提醒:"某方案快 / 某方案被证伪"同样依赖环境。 本 skill §七 的已证伪清单在新环境值得各复测一次 —— 证伪结论可能只在原形状/原版本下成立 (例如 kernel 形态、tile 大小、是否压 UB 上限,都会随硬件改变结论)。


0.1 默认动作:枚举多个方案、逐一实测、择优使用

不要照抄本文档的参数值(BLOCK_S、tile 形状、DSL 选择、是否用库算子…)。默认流程:

  1. 列出候选(≥2):包括本文档推荐的、以及本文档证伪的;
  2. 统一口径测量:同一进程内交错 / ABBA,避免热漂移(细则见 ../perf-gate/references/measurement-discipline.md §2);
  3. 先比正确性,再比性能:性能最快但数值错的配置必须淘汰 —— 来源环境真实出现过"看起来最快却数值错误(匹配率不足 100%)"的配置, 这是"很容易误采纳的改动";
  4. 记录两侧:落败方案的读数也要留档,才能说明"在本环境确实更差";
  5. 形成本环境自有基线,后续比较一律以此为参照;
  6. 只有在本环境复测过的结论才写进交付。

同理:本 skill 的契约本身也是"待验证的假设"而不是"标准答案"。 正确用法是照着 §五 的位级对拍 SOP 去验证,而不是假定成立 —— 这正是 §一/§二 标注证据等级的原因。

同理,契约与"为对齐它而生的技巧"也都是有寿命的:本 skill 记录的量化契约(scale 粒度、舍入模式、退化块规则) 与为匹配契约而必须做的动作(除数必须从内存载入、bf16 整数 RNE 技巧、大 tile + 64 行子块 amax、 补零对齐…),都是特定版本下逆向/试出来的 —— 下个版本可能把契约写进文档、暴露成原生 API, 或直接修掉逼出该技巧的工具链行为(例如常量除数的强度削减)。 因此套用本 skill 的任何绕行之前,先在本版本复测它是否仍然必需(一条探针 / 一个最小复现即可); 一旦不再需要就删除该条,不要留「以防万一」—— 否则会做无用绕行,甚至拒绝走已经可用的原生路径。

绕行的"存在方式"同样有纪律(单点在 ../README.md §7「禁止把一次性缺陷固化成结构」): 一次性缺陷的绕行一律走可一键关闭、可整体删除的开关,不长期分裂代码路径、不写兼容 shim, 以便确认修复后整块删掉——把绕行固化成结构,等于让"下个版本已修好"这条信息永远无法生效。


为什么需要单独一份契约

量化器是没有文档的二进制语义。它的三个自由度——scale 粒度、舍入模式、溢出行为——任何一个猜错, 结果都会"看起来差不多"(payload 99% 相符、PSNR 只掉一点),却在逐字节验收时全盘失败。

实践中猜错这三项的代价(示例):

猜错的东西后果
scale 粒度(每 tile 一个 vs 每 64-token 块一个)三种舍入模式一律 ~58% 字节不同 —— 让人误以为"舍入不是原因"
舍入模式(截断 vs RNE)差近一半的字节,不是小误差
除数用法(kernel 内重算 vs 从内存载入)常除数被强度削减成倒数乘法(~2 ulp)→ 静默污染千分之一以下的 payload 字节
溢出行为(假定饱和 vs 实际回绕)去钳位后产生静默回绕垃圾,而不是饱和值
bf16 舍入来源(x.to(bf16).to(fp32))triton-ascend 上被静默消除(no-op)→ 损失个位数百分比的 payload

一句话结论:契约必须从设备字节反推,不能猜、不能从"合理"推。


一、MXFP8(e8m0 scale)契约

证据等级:强。有独立逆向文档 + 独立推导 + 独立 numpy 参考实现逐字节完全相符(对拍规模见会话产物归档 {run_results_dir}/archive/)。

1.1 字节编码

byte = 127 + floor(log2(amax)) - 8 = 119 + floor(log2(amax))     clamped to [0, 254]
value(byte) = 2 ** (byte - 127)

语义:amax 被归一化进 [256, 512) —— 即选 scale 使最大元素至多需要 1.xxx * 2^8 表示。 因此一个值可以落在 (448, 512),必须饱和。

判别性测量(amax = 448 * 2**k 扫描):

amax0.43753.52244488967168458752
byte117121126127128131137

实现要点(承重):用 fp32 指数域取整,不要用 log2:

expf = (bits >> 23) & 0xFF
byte = clamp(expf - 8, 0, 254)

这是精确的(无 log2 舍入风险),且对 0 与 fp32 次正规数自然给出 byte 0(expf = 0 → -8 → clamp 0),与算子一致。

⚠️ 被证伪的公式:ceil(log2(amax/448)) 仅在约八成的组上相符, 在 amax = 450 / 1000 / 230 上失败。floor(log2(amax)) - 8 全部解释。

1.2 scale 布局

shape = [T, ceil(K/32/2), 2]      # 连续行主序
swizzle = 恒等映射                # group g 就在扁平偏移 g

用标记法实测(给 group g 一个唯一可识别的 2 的幂 amax,再查该字节的扁平位置):

group预期 byte实测扁平偏移(g//2, g%2)
01190(0,0)
11231(0,1)
21272(1,0)
8413384(42,0)
167135167(83,1)

结论:[T, ceil(c/2), 2] 只是形状标注,不是置换。 这一发现"removes a whole class of would-be bugs" —— 不要假设它需要 deswizzle。

1.3 payload 舍入 = RNE,饱和于 ±448

单块 amax = 440(scale = 1.0),设备原始 payload 字节:

value1.06251.18751.2520044051210001e30bf16 max-440
byte565858116126126126126126254
decoded1.01.251.25192448448448448448-448
  • 1.0625 是 1.0/1.125 的精确中点 → 1.0(偶数尾数)⇒ RNE,不是 round-half-away
  • 1.1875 是 1.125/1.25 的中点 → 1.25(偶数尾数)⇒ RNE
  • 有限溢出直接钳到 ±448(无 inf/NaN payload)
  • 由完整 e4m3 幅值表 + 全部 165 个中点及其负值构成的独立参考,在两个指数域下完全相符(100%)

1.4 退化块规则(逐条实测,容易漏)

块内容scale bytepayload
全零0全 0
amax < 2^-119(如 1e-38)0全 0
amax = 2^-110(byte 9)9正常 RNE
任意位置 ±inf255整块全 0
任意位置 nan255整块全 0

byte 0 的真实语义是 flush-to-zero(byte 0 要求 amax < 2^-119 ⇒ 块内每个值都是 bf16 次正规数)。

融合内核应采用:组 byte 为 0 或 255 ⇒ 该组 payload 全 0;byte 1..254 走 RNE(bf16_value / 2**(byte-127)) + ±448 饱和。

1.5 被量化的对象是 bf16 结果,不是 fp32 中间值(承重)

生产链路是 norm(...) -> bf16 tensor -> quant ⇒ amax 与 payload 都基于 bf16 舍入后的值。 改用 fp32 中间值会"在块 amax 跨越 2 的幂时改变指数 —— 随机数据约每 100 块 1 块"。这是设计承重点。


二、int8 契约

⚠️ 证据等级:弱(必须如实标注)。int8 没有同强度的逆向文档;结论只有零散来源(实验脚本与单句记录), 且其中一部分仍处于「待完成的阶段」。引用时必须带上这个不确定性。

项值证据等级
scale 粒度每 (head, 64-token block) 一个(每 scale 归约 64×128 = 8192 元素)源码 + reshape 机制,较强
舍入RNE(magic-number 手法 12582912.0 = 1.5*2^23)较弱:核心数字(truncate 差近一半)仅有单一来源的一句话记录、未经独立复现,原始日志不在手、无交叉验证
饱和±127脚本实现,中等
除数必须 LOADED(不得在内核内重算)强(有隔离实验,见 §3.1)
尾块S % 64 != 0(序列长不被块尺寸整除)时必然存在尾块 ⇒ 必须精确复现 F.pad-then-slice(本案例的余数见归档)未完成(尚无已验证的复现实现)

关键陷阱(值得单独记):粒度错误时三种舍入模式一律落到 ~58% 差异字节 ⇒ 若你在粒度还错的情况下比较舍入模式,会得到"舍入不是原因"的错误结论。先对粒度,再比舍入。

RNE 的整数实现手法(可迁移):

magic = tl.full((1,), 12582912.0, tl.float32)   # 1.5 * 2**23
q = tl.cast((v + magic) - magic, tl.int32)
q = tl.minimum(tl.maximum(q, -127), 127)        # ±127 饱和

三、三条实现普适规则(比具体公式更重要)

3.1 除(divide),不要乘倒数;除数必须从内存载入

在内核内计算 amax / 448.0 会被 triton-ascend 强度削减为倒数乘法(约 2 ulp 偏差), 而 2 ulp 的 scale 误差会翻转千分之一以下的 e4m3 payload 字节 —— 静默、且看起来只差一点点。

隔离实验(分母 2 097 152):

写法差异 fp8 字节
torch x / (amax/448)0
triton x / scale(scale 从内存加载)0
triton tl.fdiv(x, scale, ieee_rounding=True)0
triton x * (1/scale)零星(个位数)
torch x * (448/amax)成百上千量级
triton/torch (x / amax) * 448成百上千量级

(表中差异只保留量级;具体字节数与实验规模见会话产物归档 {run_results_dir}/archive/。)

结论:aclnn 的 payload 是 RNE(x / (amax/448)),使用正确舍入的 fp32 除法。

3.2 需要 bf16 舍入时,用整数 RNE 位技巧

b = modulated.to(tl.int32, bitcast=True)
m = ((b + 0x7FFF + ((b >> 16) & 1)) & -65536).to(tl.float32, bitcast=True)   # == 硬件 bf16 RNE
# 不要用 modulated.to(tl.bfloat16).to(tl.float32) —— 在 triton-ascend 上是 no-op(静默消除)

证据:用 262 144 个精确 bf16 中点证明 x.to(bf16).to(fp32) 与 torch 的 bf16 cast 完全不相符(0%),且原样返回输入。使用原始 cast 让某 kernel 损失个位数百分比的 payload 字节 (≈ 8-bit 尾数输入在 e4m3 上的 1/32 中点率)。

3.3 8-bit 转换通常是回绕(wrap-around),不是饱和

不要从"未钳位结果的 min=-128 / max=127"推断会饱和 —— 任何 int8 张量都是这个范围,该推断无价值。 真证据:强制 inv = 1e5 得到 256 个大致均匀分布的不同输出值(频次峰值与均匀期望同量级) —— 这是回绕签名。

实践后果:去掉钳位只因为归一化保证了范围(scale = amax/127 ⇒ |x/scale| ≤ 127 按构造成立)才安全, 不是因为 convert 会拦截溢出。必须把这个不变式写进注释 —— 任何破坏它的后续改动会产生静默回绕垃圾,而不是饱和值。


四、组尺度耦合:为什么融合量化器天生与字节精确为敌

一个组 scale 让 32(或 64)个元素共享命运:1 ULP 的激活差异若恰好命中该组最大值, 就会翻转整组的 e8m0 指数,从而改变该组全部 payload 字节。

实测(某融合量化器;模型几何、绝对计数与对拍规模见会话产物归档 {run_results_dir}/archive/,下列只保留量级):

groups with a DIFFERENT scale byte    : 千分之几量级(全部 delta = -1)
rows with >= 1 changed group          : 三成以上
bf16 bytes differing                  : 每元素 1 ULP(占全部字节的万分之几)
payload bytes differing               : 个位数百分比

即:输入侧万分之几量级的差异 → payload 侧个位数百分比的差异(放大数百倍)。

这是任何重实现的固有属性,不是某个内核的缺陷(纯 PyTorch 参考也显示同样残差)。

诊断价值(高):错误 scale 字节全部恰好低一个指数({-1: 4374})是 "amax 取到了低一个 binade" 的签名 —— 即量化器看到的是 fp32(x) 而非 bf16(x)。 这类"全部同向、幅度恰为一个 binade"的残差比随机分布更有诊断力,优先看它的分布形状。


四·B、量化前移:把量化放到集合通信之前(组尺度对齐条件)

动机:量化后的载荷是 8-bit,而集合通信(a2a / all-gather)默认传 bf16 ⇒ 把量化搬到通信 之前,通信字节直接减半。这是"减少通信量",不是"掩盖通信",两者可叠加;本节的判据回答 「前移之后还能不能保持逐字节等价」。

关键在于每个 scale 的归约域落在哪一侧——按归约域分三类,逐类判定:

scale 类型归约域前移是否字节精确判定/代价
分片局部(如沿序列的 per-block scale,块尺寸 b)单个 rank 的分片内可以,条件是块网格对齐S % (world × b) == 0:各 rank 等长且分片起点落在全局块网格上,块成员与前移前完全一致
跨分片全局(如 per-(head,channel) 的 amax,归约域 = 整条序列)全部分片不可以,除非先补齐归约量化前对 scale 张量做一次 all_reduce(MAX)(张量极小,但这是每层每块一次的新增集合通信,必须计入收益账)
由全量数据派生的元数据(如稀疏 mask 由池化后的全序列 Q/K 生成)全部分片不可以要么把派生计算也搬到通信前(代价常吃掉收益),要么用后移数据反解(pool 块跨两个 scale 时取加权平均 (Σs₁·a₁ + Σs₂·a₂)/N),要么为它单独走小张量侧信道(pool 后仅 1/b 的字节)。⚠️ 更正:侧信道可以做到位级(不是"放弃字节精确")—— 条件是 定序归约 + 尾块感知除数(见 §四·B.1);条件不满足时才退化为 L2 数值门

不能精确时的处置(强制):报漂移清单——payload 差异计数、端到端 md5 / 相对误差、 差异归因(边界块改组 / 全局 amax / mask)。不得把「数值接近」写成「无损」; 反过来,md5 恒等也不是"没生效"(见 §五.5 的反向陷阱)。

收益账必须三头算(逐张量算,别用「减半」口头禅):

省下的字节 = Σ(被量化张量: 原字节 − 量化字节 − scale 字节)   ← 未被量化的张量一分不省
新增成本   = 新增集合通信次数 × 单次固定开销(小张量集合是延迟主导,不是带宽主导)
             + 可能多出的一次全量/池化计算
有效时间   = t0 + 字节 ÷ B(字节)     ← B 随消息变小而下降,必须实测,不得线性外推
  • 只有被量化的张量减半:同一段通信里常夹着未量化的部分(注意力输出回传、残差/门控、 只量化了一侧的 KV…),它们保持原字节 ⇒ 期望降幅要按张量逐个算。本组合量级:一次 a2a 组含 4 张量(q/k/v 前向 + o 反向),只有 3 张可量化 ⇒ 期望降到 (3×0.5+1)/4 = 62.5%, 即减少约 3/8 而非 1/2。
  • scale 自身也要传,但先算比例再决定是否计入:per-block scale 是「每 64 token × 整条 head_dim」一个 fp32 ⇒ 约占量化载荷的 4 ÷ (64 × head_dim)(head_dim=128 时约为万分之几); per-channel scale(如 V 的 per-(head,channel) amax)更小。不要凭感觉给余量, 也不要因为它"要传"就否定整个方案——量级差三个数量级。
  • 带宽不是常数(承重):有效时间 ≈ 固定开销 t0 + 字节 ÷ B,且 B 随消息变小而下降 (大消息趋近峰值,小消息被启动/同步开销主导)。消息缩小后能否仍按原速率,必须用同 communicator、同拓扑的尺寸扫描实测(方法见 dit-parallel-opt/references/parallel-plan-attribution-method.md §6),不得线性外推; 最省事的同源证据 = 同一 A/B 里两臂的消息尺寸与耗时各自算一次隐含 B,直接读出「B 掉了多少」。

判定工作流:

  1. 列出被前移张量的每个 scale 及其归约域(哪一维、是否跨 rank);
  2. 对每个 scale 套上表判据,写出对齐式(S % (world × b))并用实际 shape 验算, 不要用「应该没问题」代替;
  3. 若只需补一次小 all_reduce(MAX),先实测这次集合的固定开销(延迟主导),再决定是否前移;
  4. 若涉及 mask 等元数据,优先选侧信道传池化小张量(字节少一个数量级)而不是把派生计算前移; 该侧信道位级可达,条件是定序归约 + 尾块感知除数(§四·B.1),不满足时按 L2 数值门声明;
  5. 落地后按 §五 位级对拍:精确就报 0 字节差,不精确就报漂移与归因,二者不许混说。

与 §四 的关系:§四 说明「1 ULP 的输入差异会被组尺度放大」,本节是它在通信顺序上的推论—— 前移改变了「谁参与同一个 scale 的归约」,因此放大的是改组后的整块 payload, 看起来"只差一点点输入"也会产生成片的字节差。

四·B.1 侧信道的位级可达性(旧判决"不可达"已作废:可达,但有两项条件)

⚠️ 更正(实测推翻,先读这条):本节曾写"部分和侧信道无法位级复现,因为归约结合顺序是 全局调用形状的函数"。该判决已作废 ✗ —— 它的依据(形状依赖表、"数十种候选结构无一匹配") 是在一个并不存在的"形状依赖结合顺序"里搜索出来的。位级一致是可达的。

推翻它的实测(单卡、无模型;口径 = 逐元素差异计数 / 总数):

测内容结果
S固定一个池化块的同样数值,把调用内块数 n 从 1 变到生产形状(数百档)0 / 128 不同 ⇒ 该均值算子与 n 完全无关("形状依赖"不成立 ✗)
D1逐 rank 部分和、统一步长 ÷ 块长128 处不同、全部落在 tail cell,最大相对误差 1 − 32/128 = 0.75(该 cell 整体偏约 4 倍量级)
D2逐 rank 部分和、尾块感知除数(tail 除以真实长度)0 差异 ⇒ 位级精确 ✓
D3部分和用 fp64 合成0 差异 ✓
D4在拼齐序列上取精确 fp64 块均值0 差异 ⇒ 库的结果就是正确舍入的块均值 ✓

⇒ 更正后的三条结论:

  1. 位级可达:分布式部分和分解 + 尾块感知除数即可逐位复现(D2/D3/D4 全 0);
  2. 真正的不一致来源是"我们自己的归约不确定",不是"库的结合顺序特殊" —— 同一输入重复调用同一归约就会得到成片的元素差异(规模见会话产物归档 {run_results_dir}/archive/)⇒ 换定序分段归约 (按 cell 排序后定序求和)是个工程任务,不是研究死局 ✓。 这也解释了"约 60 种候选结构一个都匹配不上":族搜错了 —— 正确姿势(先判形状相关性、再按 相邻配对 / 对折 / 跨步 / 分块逐族穷举)见 ../../operator-dev/references/triton-ascend-lowering-pitfalls.md §三。 另:放置类算子必须用「累加」语义 —— index_copy_ 对重复索引是覆盖(后者胜), 当两个来源合法地落到同一位置时会静默丢数据 ✗(本仓形态:同一 cell 内 k 与 k + L/2 会落到同一 (row, col));但累加类归约默认不确定,所以要用定序累加(同上), 不要用"重复调用结果不同"的算子做放置;
  3. 尾块是承重的:统一步长会把 tail cell 整体做偏(D1)⇒ 除数必须取 cell 的真实长度 (counts[-1] = used_len % POOL 那种形态),不能用常量。

⇒ 判决表最后一行"放弃字节精确"相应改为:可达,条件是 ① 归约确定(定序,不得用 "重复调用结果不同"的归约)、② 除数尾块感知、③ 若还要求与全局归约一致,amax 这类 归约域的边界块要显式补一次小集合通信。任一条不满足 ⇒ 退化为 L2 数值门(层级见下)。

不要过度声称(另一半仍成立):位级可达说的是侧信道这条链路;库自身仍可能不精确 —— 实测里用精确 fp64 参照在多 seed 多族上比,仍有一族以上与库不一致,且阈值比较的平局 (probs >= threshold 形态)会把极小的数值差放大成离散的选择差异 ⇒ "可达"≠"到处都逐位": 每换形状 / seed / 阈值口径都要重新对拍(这也是 §五 SOP 要求逐形状的原因)。

三条可迁移判据(更正后):

  1. 先问"是不是我自己的归约不确定":出现"只有少数元素不同"的差异时,第一件事是同一输入 重复调用自己的归约看是否自洽(本仓实测不自洽,计数如上)。把责任先推给"库的顺序特殊", 会把一次工程修复拖成一轮研究 ✗;
  2. "与现役实现一致" ≠ "与参考实现一致":现役(eager)与融合实现偏离参考的量级相同、 且互有胜负(各自的近/远与相等样本都在同一量级;读数见会话产物归档 {run_results_dir}/archive/)⇒ 验收目标只能是 参考实现(例:拼齐序列上的 fp64 精确均值),"和现役逐位相同"会把错误一起固化 ✗;
  3. 顺序敏感性要用对抗分布才看得见:真实量级激活下 fp32 求和确实随顺序变 (三种顺序给出 23 / 11 / 26 组不同;动态范围拉到 2²³ 量级升到数千组), 但最终 bf16 结果与库 0 / 8192 全同 —— 是末级 bf16 舍入把这点关联误差吸收掉了 ✓。 更正:此前写的"8+7+7 位 < 24 位 ⇒ 求和本身精确"是错的 ✗(fp32 求和并非精确); 结论仍成立,但理由是末级舍入吸收。⇒ 判断"顺序会不会影响产物"必须在最终 dtype 上比。

层级不得混用:位级可达是有条件的 —— 条件不满足时该侧信道只是 L2 数值门 ("数量级更小"≠"无损"),违反 ../accuracy-gate/SKILL.md 的铁律。


五、位级对拍 SOP

  1. 参考必须同进程、同数据运行生产链路 —— 跨进程/跨窗口比较会引入漂移。
  2. 分开计数:payload 用 view(torch.uint8)、scale 用 view(torch.int32), 报绝对计数(0 / 67 665 920)以及 max|Δscale|(期望 0.000e+00)。
  3. 独立参考实现(不复用被测代码路径),在完整张量上要求逐字节 100% 相符。
  4. 对抗性输入清单(缺一项就可能漏掉一整个 bug 类):
    • randn / uniform[-1,1] / all-equal
    • 全部 tie 中点(165 个 e4m3 中点 × 两个指数域)
    • amax 恰为 2^k / 略高于 2^k
    • 全零 / 全负 / big+small mix
    • bf16 次正规 / 1e-38 / inf / nan(退化块)
    • 饱和边界(>448 或 >127)
    • 尾块(S % 64 != 0)
  5. 端到端无损门:md5 恒等比任何 PSNR 阈值都强 —— 但前提是"管线本身逐位确定"已被单独验证。

    ⚠️ 反向陷阱:逐字节相同的 md5 不是"门控没生效",而正是字节精确优化所预测的结果。 实践中曾把它误读为失败信号。

  6. 诚实例外要写出来:唯一不精确的输入类别(如"整张 bf16 次正规",占比为千分之几量级、全是符号零; 读数见会话产物归档 {run_results_dir}/archive/) 应显式记录为"已刻画、不追",不要藏。
  7. 先证明仪器,再做对拍:参考实现自身也要过一遍「跨流依赖是否写全 / 顺序是否正确 / 快照是否与 被测动作同时刻」的检查(口径见 ../perf-gate/references/measurement-discipline.md §8)。 本仓实测:参考侧漏了一处跨流依赖,把正确的载荷报成上千条"污染记录" ✗ —— 这类假阳性的症状与真实缺陷形态高度相似,靠看形态分不出来。

六、工具链陷阱

陷阱现象处置
Tensor.to(torch.float8_e4m3fn)NPU 上抛异常(普通 dtype cast 到 fp8 未实现)用算子 API
torch_npu.npu_dtype_cast 到 fp8越界行为不同:449/512/1000 → byte 127 (NaN)它不等于量化器的饱和转换,不能当参考
torch.arange(dtype=torch.uint8, device='npu')aclnnArange ... code 107001用 torch.empty/zeros 分配
torch.frexpNPU 上静默回落 CPU参考实现中禁用
.view(torch.uint8) 传给 triton 做 fp8 输出triton 看到 uint8 指针 → 截断而非量化(match 不足 1%)用原生 fp8 dtype
w 与 w_scale 置换只换 w 不换 w_scale → 结果静默塌到接近 0必须同序置换
积分归约(amax/amin 两次读)两次读的基线耗时torch.linalg.vector_norm(v, inf, 2) 单次读快近一倍(绝对 µs 见归档),且 0/1792 精确
手写 Triton 融合归约最优值也输给两次 torch 读"手写融合归约是错误答案;正确是一个本身只读一次的现成库算子"

scale 公式实测:scale == amax/448.0 精确相等(max|scale - amax/448| = 0.0), 不是 2 的幂(max|scale - 2^ceil(log2(amax/448))| = 7.78e-3)。全零输入 → scale = 0.0。


七、已证伪清单(不要重复)

假设证伪它的实测
MXFP8 指数字节 = ceil(log2(amax/448))仅约八成相符;在 amax=450/1000/230 失败
npu_dtype_cast(x, fp8) 与量化器行为一致449/512/1000 → NaN,不是饱和转换
dtype cast 到 int8 会饱和是回绕:inv=1e5 得 256 个均匀值
除数可以在内核内重算常除数 → 倒数乘法(~2 ulp)→ 千分之一以下的 payload 差
用 x.to(bf16).to(fp32) 做 bf16 舍入在 triton-ascend 上被静默消除,完全不相符(0%)
用 split-tree 替代归约可绕过编译问题约 4 倍更慢(绝对值见归档)
量化器核心成本在 fp8 store / castA4(payload 存 bf16)与 A7(去 store)的读数都落在噪声内 ⇒ 免费;成本在归约及 scale-byte epilogue(占该核主要部分)
非 I/O 成本随归约调用数/ tile 形状缩放随"产生的 (row, group) 最大值个数"缩放(wide 对照耗时约为窄形态的一半)
把转置 view 交给库算子会被"吸收"五个捷径全部字节精确但只省几十 µs 量级 ⇒ view 是被计价的(costed, not absorbed)
手写融合归约比两次库读更快手写融合归约慢于两次库读;对单次读的 vector_norm 更差
y * 0.0 可保留 flush 的符号反方向错误:差异扩大若干数量级(读数见归档);字面 0.0 才正确
int8 粒度猜错时可以从舍入模式看差异粒度错时三种舍入一律 ~58%,无法区分
"它编译了" / "scale 是对的" 可作为正确性证据double-tl.reshape 形式编译通过但 payload 接近但不等于 100%
用逐 rank 部分和侧信道复现"组装后单张量归约"的位级结果已作废 ✗✗:曾记"归约顺序是全局调用形状的函数 ⇒ 侧信道不可达",实测推翻 —— 该均值算子与调用内块数 n 无关(n=1…生产形状逐位相同),且尾块感知除数下部分和信道逐位精确(0 差异)。真正的差异来源是我们自己的归约不确定(重复调用同一归约会得到成片差异,规模见归档);旧结论作废见 §四·B.1
在 randn 量级输入上判"归约顺序是否影响位级结果"真实量级下 fp32 求和确实随顺序变,但最终 bf16 结果与库 0 / 8192 全同 ⇒ 末级舍入吸收了这点关联误差(更正:旧记载"8+7+7 位 < 24 位 ⇒ 求和本身精确"是错的 ✗)⇒ 判断顺序敏感性必须在最终 dtype 上比
用"与现役实现逐位相同"当侧信道验收目标现役实现自身偏离参考(实测二者偏离量级相同)⇒ 该目标会把错误一起固化;验收目标只能是参考实现
把"数量级更小"的池化侧信道写成"无损"它是 L2 数值门,不是 L1 逐字节(层级不得混用,见 ../accuracy-gate/SKILL.md)

八、参考文件

  • 📐 references/contract-reverse-engineering.md —— 契约逆向六步法(判别性探针、标记法定布局、独立参考、退化覆盖、corrigendum)+ 完整探针数据与出处。要逆向一个新量化器时读它。
  • 🔎 references/online-quant-contract.md —— 在线量化契约(算法分派、被量化的范围:哪些层/是否含 FA、图节点形态与布局互通)——自 dummy-run 下沉;判断"某框架的 online scheme 实际量化了什么、和参考实现对不上在哪"时读它。
  • 🔗 references/lora-merge-and-precision.md —— 低秩适配器(LoRA)离线合并进权重的精度判据与形态选择(合并代数与"去冗余"定位、精度存活判据与三臂对拍、三形态选择决策、判据修正纪律、loader 与摆位契约)——何时读:任何"把运行时计算折进权重"的候选(适配器合并、把缩放/偏置折进相邻线性层、把量化残差折回权重)在定形态或下"合并后不等价 ⇒ 不可用"结论之前读它。

路由判据(何时读上面第三条):① 出现"把运行时的算子链换成权重里的一份预计算结果"的候选时——先按它的 §1 判"在 ckpt 里量化还是在 load 期量化",再进 §2/§3; ② 需要判"合并后增量还在不在"时——按它的 §2 三臂对拍取数,不要用自写模拟器; ③ 要因"数值上不等价"否掉一条合并路线时——按它的 §4:纯数值研究只能推翻等价性,可用性必须由服务端产物级 A/B 收口。

九、与既有 skill 的分工

  • operator-dev —— 算子开发/优化与 DSL 选型(CV→catlass / VV→triton);本 skill 是它的量化契约补充层。
    • 其 fusion-scope-analyze/references/fusion-unit-method.md 与 fusion-benefit-method.md 讲融合范围与收益(含 §3.1 的"移除流量 vs 移除延迟"判据);本 skill 讲数值契约。
  • dit-perf-opt —— 回答**"该不该开量化、开哪一档"(特性选型与质量门禁);本 skill 回答"这个量化器到底怎么算的"**。
    • accuracy-gate/references/quality-gate.md 是有损档位的阈值门禁;本 skill 的位级对拍是无损证明,两者不可互相替代。
  • dit-parallel-opt —— 并行作用域失效(静默降级)的判定(DiT 侧)与并行陷阱清单;其 dit-parallel-opt/references/ascend-parallel-traps.md §8 只保留了量化契约的指针,契约本体在本 skill; 测量与上报口径见 perf-gate。
  • dit-parallel-opt —— 并行选型、通信掩盖与归因;本 skill §四·B 只回答「量化前移能否字节精确」的数值契约,形态选择与收益判定在那侧。
  • pattern-dev —— 量化融合 pattern 的图命中与收益核验;本 skill 提供"数值上到底对不对"的判据。

十、维护与更新

  • §二 int8 一节的证据等级必须随新证据更新:目前"RNE / 误差差近一半"仅有单一来源的一句话记录、未经独立复现; 若能复现,改为强证据并补上分母与形状。
  • 当 CANN 量化算子行为变化(派发 kernel 名、tiling 边界、退化块规则)时,重跑 §五 SOP 并更新 §一/§二。
  • §七 已证伪清单应持续追加 —— 它比正面结论更省机时。
  • §四·B.1 的"位级可达"结论必须随版本复测:可达性依赖 ① 该均值算子与调用形状无关 (换 CANN / 算子实现后可能变成形状相关 ⇒ 那时尾块感知除数不再够用), ② 该归约在库里的语义仍是"正确舍入的块均值"。 复核方法:构造一个固定池化块,分别在 n = 1 / 中间档 / 生产形状 三次调用里求均值, 比较该块取值是否仍与 n 无关(当前实测 0 / 128 不同);再用"统一步长 vs 尾块感知步长" 各合成一次部分和,看前者是否只在 tail cell 出错、后者是否 0 差异。 另:用大指数跨度分布跑一次顺序敏感性对拍(最终 dtype 上比),否则会得到"任何顺序都相等"的假阴性。
  • "自己的归约是否确定"要作为常规前置检查:凡在侧信道/中间量里做归约,先重复调用两次比自身 (当前该归约不自洽,计数见 §四·B.1 结论 2);换成定序归约后本检查应为 0 差异。

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

**精度验收标准**:凡是"改动不应改变结果"的场合(等价替换、算子/子模块融合、并行切分、 编译与图下发、拷贝消减),都按本标准判"合格 / 不合格"——等价分层(L1 逐位 / L2 数值门 / L3 有损门)+ 三级验收序(① 同配置重跑逐位 → ② 跨配置数值门 + 产物 md5 不变 → ③ 质量门)+ 判据不达标时的排障入口。当用户说"这个算子能不能换个写法/换个 kernel/等价实现/ 无损替换""替换后结果会不会变""怎么证明逐位一致""结果不对""花屏""尾部塌了" "CPU 跑对 NPU 跑不对",或发现某个 hotspot 占了大头(例如某类算子在阶段里占 90% 以上)想动手时, 都应触发;即使用户只说"这样改有没有把结果改坏""能不能判它是无损的"也应触发。 覆盖:等价分层与判据、满足本标准的实现约定(per-shape 对拍写进实现,把索引/相位/顺序类重写 错误在首次调用抓住)、per-shape 条件性等价(同一改动在不同形状下结论可能不同)、 判据不达标 → `references/silent-failure-localization.md` 排障入口、否决案例的形态学 (换写法未换 kernel / 差异极小仍非逐位 / 等价但 OOM)、以及收益口径的归属(性能数字一律交 `perf-gate`)。 **近义分流**:选量化档 / 特性选档(要不要开量化、开哪一档)→ `dit-perf-opt`; 并行选型(USP / CP / TP 怎么切)→ `dit-parallel-opt`;本技能只判"结果是否被改变", 不负责选档与选型。

日本語の概要は準備中です。原文の説明を表示しています。

Ascend/MindIE-SD152026年10月10日 更新

NPU 图批量下发能力(aclgraph / aclgraph_ex 家族)的开发与调优。覆盖 mindiesd 的 aclgraph_backend:NPUGraph 静态 capture、全局 graph pool、 lazy capture、专用 copy stream + event 管线、shape/dtype 校验、max_entries 驱逐。 当用户需要减少 host launch 开销、静态 shape 大 batch 场景加速、 或排查 NPUGraph replay 输入不匹配问题时使用此 skill。 即使用户只提"批量下发""graph capture""图捕获"而未说 aclgraph,也应触发; pattern/Inductor 融合(default 后端)见 pattern-dev,算子本体见 operator-dev, 本技能只覆盖图批量下发。由 dev-workflow 的编译开发阶段与 model-auto-optimization 的 图下发场景指引加载。

日本語の概要は準備中です。原文の説明を表示しています。

Ascend/MindIE-SD152026年10月10日 更新

MindIE-SD 核心算子(FA/BSA/GMM/MM)性能基准工具链。使用:模型优化(model-auto-optimization 的 S1/S4 选型)中用 mindie_bench 对单算子做实现级实测,按 dtype/量化档/稀疏度/形态对比 选出最优配置(产物:选型证据;稀疏度-性能曲线供 S4 稀疏度选型);开发:benchmarks/ 工具链扩展与新算子接入测试(供 operator-dev / pattern-dev 调用)。 当用户需要对比算子实现选型、新增或修改 benchmark 代码、排查 benchmark 数据异常、 给基准加算子/指标时使用;即使用户只说"benchmark 数据不对""给基准加个算子" "对比下这几个 FA 实现哪个快"也应触发;特性级方案选档请走 dit-perf-opt (本 skill 只做实现级实测)。 由 model-auto-optimization 的 S1/S4 选型场景与 operator-dev 的算子接入验证场景调用, 亦由 dev-workflow 在基准开发时指引加载。

日本語の概要は準備中です。原文の説明を表示しています。

Ascend/MindIE-SD152026年10月10日 更新

MindIE-SD Python 代码格式与 lint 规则。当编写、格式化、lint 检查或审查 MindIE-SD 项目的 Python 代码时使用此 skill。 即使用户只提到"提个MR"或"代码好像有 lint 问题"而未明确说格式化,也应触发;Markdown 格式问题见 markdown-lint,提交/PR 规范见 mindie-sd-community-governance。 通常由 dev-workflow 在编码阶段指引加载。

日本語の概要は準備中です。原文の説明を表示しています。

Ascend/MindIE-SD152026年10月10日 更新

MindIE-SD 仓库开发总入口(侧轨)。当用户进行 MindIE-SD 的任何代码开发工作时使用此 skill—— 包括但不限于写 pattern、改测试、部署到昇腾、跑 benchmark、性能分析、多卡并行、复盘归档。 模型/三方框架自动优化类任务(非本仓代码改动)由 model-auto-optimization 入口承接, 本入口只在优化流程需要新增 pattern/算子/部署代码时承接其指向的开发子任务。 即使用户未明确提到"开发流程",只要涉及 MindIE-SD 代码改动都应触发。

日本語の概要は準備中です。原文の説明を表示しています。

Ascend/MindIE-SD152026年10月10日 更新

分布式并行策略选型与实测(USP / CP 通信掩盖 / CFG / TP/RSP/PP 概览;含拓扑相关选型 (按实测拓扑分域条件化:域内 bulk vs 跨域 head-parallel 翻转)与 AlltoAllV 缺陷绕过)。在 model-auto-optimization 中承担 S3:优先 USP、结合拓扑带宽差异选 CP,少量 step + 多 rank 验证特性开启与掩盖(产物:并行方案 + 多 rank 证据)。当用户需要多卡并行 策略选择、**序列并行形态抉择**(纯 Ulysses vs 复合 AllGather-KV×Ulysses:按 GQA / 跨域带宽 / 形态 plumbing 条件化定胜负)、**并行 × 稀疏叠加**(seam 契约:先汇聚后稀疏、 窗口偏移、块对齐、per-head 掩码;含「稀疏看似生效实则未生效」判定)、通信掩盖调优 (含**掩盖率上限**:1-1/n 何时成立、c/f 决定的真实上限、没生效的排查)、**并行方案 差异归因**(阶段 Δ 分解 / 集合通信按 communicator 归属 / 4→8 卡线性度),或排查多卡 跑不动 / 通信暴露大 / 换卡组 / 端口 bind / HCCL 带宽验证问题时使用;**并收编原并行作用域诊断**: 改了 SP/CP/Ulysses/AllGather-KV 后**不报错但结果没变/性能没变**、或小规模能跑大规模崩 (如 Ascend EE1003 coreDim 超限)时,用本技能证明"改动到底有没有生效"(判别量逐层收窄 + 两侧对照 + 日志≠生效,见 `references/scope-effectiveness-check.md`); 即使用户只说 "多卡跑不动""通信暴露大""为什么没达到 6/7 的掩盖率""CP 和 USP 该选哪个""CP 叠稀疏 怎么不生效"而未说并行,也应触发。特性档位/接口事实见 `docs/zh/features/parallelism.md` /`usp.md`(仓内真源),框架侧开启见 framework-integration; 本技能承载选型决策、monkey-patch 掩盖与多卡诊断实测。 由 dev-workflow 多卡场景触发,亦由 model-auto-optimization 的 S3 阶段触发。

日本語の概要は準備中です。原文の説明を表示しています。

Ascend/MindIE-SD152026年10月10日 更新

Ascend のスキルをすべて見る

このスキルの問題を報告する