DaVinci 950 量化 (Quantization) API 与注意事项


1. 量化在 950 中的两条路径

路径 A: Cube 端量化 (FIXP 硬件管线)
  CUBE MMAD (S32/FP32 累加) → FIXP DEQ/REQ → OUT(GM) / L1 / UB 
  适用: 矩阵乘法后直接量化, 零额外计算开销

路径 B: Vector 端量化 (VEC Core 软件)
  VEC VALU 类型转换指令 → VREG → UB → GM
  适用: 非 Cube 场景, 灵活但消耗 VALU 周期

2. 路径 A: FIXP 量化 (CUBE 后处理)

2.1 支持的量化操作

FIXP 操作 转换方向 模式 用途
REQ8 S32 → S8 标量 + 向量 INT8 量化推理
REQ4 S32 → S4 标量 + 向量 INT4 量化推理
DEQF16 S32 → FP16 标量 INT 累加→FP16 输出
QS322BF16 S32 → BF16 标量 + 向量 INT 累加→BF16 输出
QF32_2_B8 FP32 → S8/U8 标量 + 向量 FP32 训练→INT8 部署
QF32_2_S4 FP32 → S4 标量 + 向量 FP32→INT4 部署
QF32_2_HiF8 FP32 → HiF8 标量 + 向量 FP32→HiFloat8
QF32_2_E4M3 FP32 → FP8 E4M3 标量 + 向量 FP32→FP8 量化
QF32_2_E5M2 FP32 → FP8 E5M2 标量 + 向量 FP32→FP8 量化
QF32_2_BF16 FP32 → BF16 标量 + 向量 FP32→BF16 精度转换
QF322F16 FP32 → FP16 标量 + 向量 FP32→FP16 精度转换

旁路模式 (不量化):

  • FP32 bypass: FP32 → FP32 (直通)
  • S32 bypass: S32 → S32 (直通)

2.2 FIXP 量化参数缓冲

缓冲 大小 用途
Bias 1024×4B = 4KB 偏置加法参数
RELU-pre 512×4B = 2KB RELU 阈值/斜率
Quantization-pre 512×8B = 4KB 量化 scale/offset 参数

2.3 FIXP 量化与 RELU 的串联

CUBE MMAD → L0C (S32/FP32)
              │
              ▼
         FIXP-PRE:
           1. BIAS 加法 (可选)
           2. DEQ 量化 (scale×data + offset)
           3. RELU/Clip-RELU (可选, 在 FP32 域)
              │
              ▼
         MEM_RIF: 数据重排
              │
              ▼
         MEM_WIF:
           NZ2ND (NC1HWC0 → NHWC) + 量化类型转换
              │
              ▼
         OUT → GM

2.4 FIXP 量化并行度

路径 并行度 (elem/cycle) 说明
L0C→OUT (S32/F32 bypass) 32 不量化, 直通
L0C→OUT (量化后 b8/b4) 64 量化后每 cycle 输出 64 元素
L0C→L1 (S32/F32 bypass) 64 直通
L0C→L1 (量化后) 128 量化后每 cycle 输出 128 元素
L0C→UB (S32 bypass) 32 直通
L0C→UB (FP32 dual source) 64 双源写入 UB0+UB1

3. 路径 B: Vector Core 量化 (VALU 类型转换)

3.1 API — FP32 → 低精度 (量化)

API 函数 目标类型 舍入模式 说明
Cast(dst, src, CAST_RINT, count) FP16 rint FP32→FP16, 就近舍入
Cast(dst, src, CAST_ROUND, count) FP16 round FP32→FP16, 四舍五入
Cast(dst, src, CAST_FLOOR, count) FP16 floor FP32→FP16, 向下取整
Cast(dst, src, CAST_CEIL, count) FP16 ceil FP32→FP16, 向上取整
Cast(dst, src, CAST_RINT, count) BF16 rint FP32→BF16, 就近舍入
Cast(dst, src, CAST_ROUND, count) BF16 round FP32→BF16, 四舍五入

3.2 API — 低精度 → FP32 (反量化)

API 函数 源类型 说明
Cast(dst, src, CAST_NONE, count) FP16→FP32 精确扩展, 无舍入
Cast(dst, src, CAST_NONE, count) BF16→FP32 扩展到 FP32

CAST_NONE 表示无舍入操作, 用于精度扩展场景。

3.3 API — 完整类型转换覆盖

C API 函数 目标类型 舍入模式 适用架构
Float2Half(dst, src, mask) FP16 rn/rd/ru/rz/rna/ro 全部
Float2Bfloat16(dst, src, mask) BF16 rn/rd/rna/ru/rz 全部
Float2Int32(dst, src, mask) S32 rn/rd/ru/rz/rna 全部
Float2E4m3(dst, src, mask) FP8 E4M3 rn 3510 ONLY
Float2E5m2(dst, src, mask) FP8 E5M2 rn 3510 ONLY
Float2Hif8(dst, src, mask) HiF8 rh/rna 3510 ONLY
Half2Int8(dst, src, mask) S8 rn/rd/ru/rz/rna 全部
Half2Int4x2(dst, src, mask) S4×2 packed rn/rd/ru/rz/rna 3510 ONLY
Half2Hif8(dst, src, mask) HiF8 rh/rna 3510 ONLY
Bfloat162E2m1x2(dst, src, mask) FP4 E2M1×2 rn/rd/rna/ru/rz 3510 ONLY
Bfloat162E1m2x2(dst, src, mask) FP4 E1M2×2 rn/rd/rna/ru/rz 3510 ONLY
Half2Float(dst, src) FP32 全部
E4m32Float(dst, src) FP32 3510 ONLY
E5m22Float(dst, src) FP32 3510 ONLY
Hif82Float(dst, src) FP32 3510 ONLY

3.4 通用舍入函数

API 函数 等价数学 适用类型
Ceil(dst, src, count) ⌈x⌉ FP16, BF16, FP32
Floor(dst, src, count) ⌊x⌋ FP16, BF16, FP32
Round(dst, src, count) 四舍五入 FP16, BF16, FP32
Rint(dst, src, count) 就近整数 FP16, BF16, FP32
Trunc(dst, src, count) 截断 FP16, BF16, FP32

3.5 舍入模式详解

模式 枚举/缩写 数学含义 典型用途
Round to nearest even rn / CAST_RINT 四舍五入到最近偶数 训练 (无偏)
Round down rd / CAST_FLOOR 向负无穷取整 量化范围下界截断
Round up ru / CAST_CEIL 向正无穷取整 量化范围上界截断
Round toward zero rz / — 向零取整 推理量化
Round to nearest away rna / CAST_ROUND 四舍五入 (远离零) 部署量化
Round to odd ro 四舍五入到奇数 特殊场景
Round hybrid rh 混合舍入 (HiF8专用) HiFloat8 量化

4. 量化 API 对应关系总览

┌──────────────────────────────────────────────────────────────────┐
│                    量化场景           API 选择                   │
├──────────────────────────────────────────────────────────────────┤
│                                                                  │
│ 场景 1: Cube 矩阵乘后直接量化                                     │
│   MMAD(S32/F32) → FIXP DEQ/REQ → GM                            │
│   配置: FixPipeParams / FIXP 指令参数                         │
│   量化参数: 从 L1 加载 Quantization-pre (4KB)                    │
│                                                                  │
│ 场景 2: 向量端 FP32→FP16 量化                                    │
│   Cast(dst, src, CAST_ROUND, count)                            │
│                                                                  │
│ 场景 3: 向量端 FP32→BF16 量化                                    │
│ 场景 4: 向量端 FP32→FP8 量化 (3510 ONLY)                         │
│ 场景 5: 向量端 FP32→HiF8 量化 (3510 ONLY)                        │
│ 场景 6: 向量端 FP16→INT8 量化                                    │
│ 场景 7: 向量端 FP16→INT4 量化 (3510 ONLY, packed)                │
│ 场景 8: BF16→FP4 MX 量化 (3510 ONLY)                             │
│ 场景 9: FP8→FP32 反量化 (3510 ONLY)                              │
│ 场景 10: FP16→FP32 反量化                                        │
│   Basic C++: Cast(dst, src, CAST_NONE, count)                   │
│ 场景 11: MX Matmul 量化 (3510 ONLY, CUBE端)                      │
│   Basic C++: Matmul(l0c, l0a, l0b, mx_params)                   │
│   输入: FP4 E2M1/E1M2 + FP8 E8M0 scale                         │
│   累加: FP32 → FIXP 可进一步量化输出                              │
│                                                                  │
└──────────────────────────────────────────────────────────────────┘

5. 量化注意事项

5.1 FIXP 量化约束

# 约束 原因 违反后果
1 L0C 数据 不能是 denormal FIXP 内部用 FP32 域处理 量化结果错误
2 量化参数 不能是 denormal/INF/NaN 参数在硬件中直接使用 量化结果错误
3 量化后数据写入 OUT: 字节对齐 OUT 接口特性 数据错位
4 量化后数据写入 L1/UB: 32B 对齐 L1/UB 写对齐要求 硬件异常
5 L0C 读对齐: FP32/S32 64B, FP16 32B L0C bank 粒度 性能损失/数据错误
6 L1/UB/OUT 不能同时写 FIXP 资源互斥 指令丢弃
7 Quantization post type 不支持 硬件限制 不可用
8 N 方向 dummy data 不删除 FIXP 只删 M 方向 输出含垃圾数据
9 量化参数 只从 L1 加载 FIXP 硬件设计 无法加载
10 参数源 32B 对齐, 目的 64B 对齐 MEM_RIF 接口要求 硬件异常

5.2 Vector Core 量化约束

# 约束 原因 解决方案
1 DataCopy count 必须 32B 对齐 硬件搬运约束 FP16≥16, FP32≥8, INT8≥32, 尾部 padding
2 FP8/FP4 类型只在 3510 可用 2201 无这些类型 #if (__NPU_ARCH__ == 3510) 条件编译
3 FP4 是 packed ×2 (8bit 存 2 个 FP4) 紧凑存储格式 一次转换得到 2 个值, 需拆包
4 FP8 E8M0 只用作 MX scale 无尾数, 只有指数 仅配合 MX Matmul 使用
5 反量化 (→FP32) 无舍入模式 精度扩展无损失 Cast(dst, src, CAST_NONE, count)
6 INT8 量化依赖 mask 控制有效元素 INT8 与 FP16 位宽不同 构造对应宽度的 predicate mask
7 量化指令消耗 VALU 周期 走 VALU 流水线 尽量用 FIXP 路径替代
8 舍入模式选择影响 量化精度 不同舍入偏差不同 训练用 rn, 推理用 rz

5.3 舍入模式选择指南

┌──────────────────────────────────────────────────────────────┐
│                    舍入模式决策树                              │
│                                                              │
│  是否是训练场景?                                              │
│    ├── 是 → rn / CAST_RINT (round to nearest even, 无偏)    │
│    └── 否 (推理/部署)                                        │
│          ├── 是否要求无偏量化?                                │
│          │    ├── 是 → rn / CAST_RINT                        │
│          │    └── 否 → 性能优先?                              │
│          │          ├── 是 → rz (trunc, 最快)                │
│          │          └── 否 → rna / CAST_ROUND (精度好)       │
│          └── HiF8 场景 → rh (hybrid, HiF8专用)              │
│                                                              │
│  特殊场景:                                                    │
│    量化范围上界截断 → ru / CAST_CEIL                         │
│    量化范围下界截断 → rd / CAST_FLOOR                        │
│    混合精度累加 → ro (round to odd, 保持精度)                 │
└──────────────────────────────────────────────────────────────┘

5.4 量化精度陷阱

陷阱 现象 原因 修复
溢出截断 INT8 量化后最大值全是 127 scale 太小, FP32 值远超 127/scale 调大 scale 或用 saturation
全零输出 量化后输出全为 0 scale 太大, 所有值量化后 < 0.5 被截断 调小 scale
非对称量化偏移 有符号量化不对称 未正确处理 zero-point 用 U8 + offset 做对称化预处理
BF16 精度低 梯度更新不收敛 BF16 只有 7-bit 尾数 用 FP32 累加 + 最后一步转 BF16
FP4 精度不足 量化误差 > 50% FP4 E2M1 只有 1-bit 尾数 配合 MX scale (E8M0) 分组补偿
denormal 输入 量化结果不可预测 denormal 在 FP32 域处理异常 输入数据先 flush-to-zero
混合精度链 串联量化精度衰减 每次量化引入舍入误差 减少量化次数, 合并为一步
NZ2ND 尾部垃圾 N 不对齐时输出含无效数据 FIXP 不删 N 方向 dummy N 按 C0 向上对齐, 或用 NZ2DN

Logo

鲲鹏昇腾开发者社区是面向全社会开放的“联接全球计算开发者,聚合华为+生态”的社区,内容涵盖鲲鹏、昇腾资源,帮助开发者快速获取所需的知识、经验、软件、工具、算力,支撑开发者易学、好用、成功,成为核心开发者。

更多推荐