SDE / Inference · HM Phone Screen Coding

Nvidia FP32 转 INT8:Scale、Zero Point 与饱和边界

Nvidia NG SDE 面经中的 FP32 tensor 转 INT8 编程题:先按 scale 缩放,再扩展 asymmetric zero point;本文明确截断与饱和规则并验证边界。

题目重点:Nvidia NG SDE 面经中的 FP32 tensor 转 INT8 编程题:先按 scale 缩放,再扩展 asymmetric zero point;本文明确截断与饱和规则并验证边界。

题意与假设

这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。

  • 训练输入是一维有限浮点数组;多维 tensor 可逐元素映射并保留 shape。scale 为正且有限,zero point 是 [-128,127] 范围内整数。
  • 题目说“除后 cast”;本训练版先向零截断,再加 zero point,最后饱和到有符号 INT8 范围。生产量化常会另选 round-to-nearest 等规则,不能把本规则说成题面唯一要求。
  • NaN、无限值、非正 scale 和非法 zero point 明确报错;极大商值直接饱和,避免转换时溢出。

解题路线

  1. 先写对称版 q=clamp(trunc(x/scale), -128,127),逐元素处理并保留原 tensor 的结构。
  2. 加入非零 zero point 后变为 q=clamp(trunc(x/scale)+zero_point,-128,127);注意先截断再加整数 zero point,与先相加再截断在负数附近可能不同。
  3. 检查 0、正负小数、上下边界和极大值。再讨论 scale、zero point 如何由校准数据估计,per-tensor 与 per-channel 对误差和内存读取的影响。

手动走一遍

scale=0.5、zero_point=3 时,x=-1.25 的缩放值为 -2.5,向零截断得 -2,输出 1;x=1.25 得 2.5→2→5。若缩放结果加零点超过 127,输出饱和为 127。

Python 参考实现

下面的代码按上文假设实现,适合本地运行并追加自己的测试用例。

代码区可横向滚动;使用键盘时,先聚焦代码区再按方向键查看。

from math import isfinite


def quantize_int8(values, scale, zero_point=0):
    """Training convention: truncate toward zero, add zero point, saturate."""
    if not isfinite(scale) or scale <= 0:
        raise ValueError("scale must be positive and finite")
    if not isinstance(zero_point, int) or not -128 <= zero_point <= 127:
        raise ValueError("zero point must be an int8 integer")
    output = []
    for value in values:
        if not isfinite(value):
            raise ValueError("tensor contains a non-finite value")
        scaled = value / scale
        if not isfinite(scaled):
            output.append(127 if scaled > 0 else -128)
            continue
        quantized = int(scaled) + zero_point
        output.append(max(-128, min(127, quantized)))
    return output

复杂度

N 个元素逐一扫描,时间 O(N),返回数组空间 O(N);若接口允许原地写且输出 dtype 不同,需要重新分配。真正 tensor kernel 的性能还受连续内存、向量化、跨设备传输和 per-channel scale 读取影响。

易错点与追问

容易失分的边界

  • 直接把超出 INT8 范围的值 cast,语言和硬件上的溢出行为可能产生错误结果;先明确饱和口径。
  • 把 zero point 当作浮点加到原值后再除 scale,写成 (x+z)/scale,单位不一致。
  • 把训练版截断规则说成所有量化都采用的舍入规则。
  • 只测试正常值,漏掉负数截断、零点边界、非法 scale 与分布偏斜。

继续深挖

  • 若面试官要求 round-to-nearest,先确认 tie-break 规则,再修改算式和测试。
  • 若 zero point 和 scale 每个通道不同,明确轴、广播形状和连续内存访问代价。
  • 用反量化 x̂=scale·(q−zero_point) 评估饱和比例、绝对误差及模型最终指标。
✓已复制微信号!