2. 定点数量化与数据格式转换

任务目标

设计一个INT8定点数量化模块,将浮点权重和激活值转换为定点数,并验证量化前后的精度损失。本案例聚焦于对称均匀量化方案,覆盖量化参数计算、浮点转定点、定点转浮点(反量化)的完整链路。

量化方案与数据格式

采用对称INT8量化:scale = max_abs / 127,浮点值 f 映射为 q = round(f / scale),反量化为 f_hat = q * scale。该方案无需零点偏移,适合权重和ReLU后的激活值。

核心代码(Python实现)

import numpy as np

def compute_scale(tensor):
    """计算对称量化scale"""
    max_abs = np.max(np.abs(tensor))
    if max_abs == 0:
        return 1.0
    return max_abs / 127.0

def quantize_to_int8(tensor, scale):
    """浮点张量 → INT8定点数(返回int8数组)"""
    q = np.round(tensor / scale)
    q = np.clip(q, -128, 127)
    return q.astype(np.int8)

def dequantize_to_float(q_tensor, scale):
    """INT8定点数 → 浮点张量(反量化)"""
    return q_tensor.astype(np.float32) * scale

def quantization_error(orig, dequantized):
    """计算量化前后均方误差(MSE)与相对误差"""
    mse = np.mean((orig - dequantized) ** 2)
    norm_orig = np.linalg.norm(orig)
    rel_err = np.linalg.norm(orig - dequantized) / norm_orig if norm_orig > 0 else 0
    return mse, rel_err

# ===== 验证流程 =====
if __name__ == "__main__":
    # 模拟一组浮点权重(正态分布,含正负值)
    np.random.seed(42)
    weights = np.random.randn(64, 64).astype(np.float32) * 0.5

    # 模拟ReLU后的激活值(非负)
    activations = np.abs(np.random.randn(128, 32).astype(np.float32)) * 0.3

    for name, tensor in [("weights", weights), ("activations", activations)]:
        scale = compute_scale(tensor)
        q = quantize_to_int8(tensor, scale)
        deq = dequantize_to_float(q, scale)
        mse, rel_err = quantization_error(tensor, deq)
        print(f"{name}: scale={scale:.6f}, "
              f"INT8 range=[{q.min()}, {q.max()}], "
              f"MSE={mse:.6e}, relative_err={rel_err:.4f}")

运行方式

python int8_quantization.py

验证方法与判定标准

运行脚本后观察输出:

  • INT8范围检查:量化后数值必须在[-128, 127]内,输出中q.min()与q.max()应落在此区间。
  • 精度损失度量:记录MSE与相对误差。相对误差通常应小于5%(本例随机数据预期在1%~3%量级),若误差过大说明scale计算或舍入方式有误。
  • 反量化正确性:反量化结果应与原始浮点值趋势一致,可通过打印若干对应值人工抽查。

若输出中INT8范围越界或相对误差异常(如>10%),检查np.clip边界与np.round是否按预期工作。

关键说明

  • 本实现为对称量化,适用于权重和正激活值;若激活值含负值(如Leaky ReLU输出),需改用非对称量化或调整方案。
  • 实际FPGA部署时,scale通常以浮点常量传入硬件,INT8乘累加结果用INT32累加后再反量化,本案例覆盖了数据格式转换的核心数学链路。
  • 随机种子固定为42,保证可复现;替换为真实模型权重时,只需将weights/activations替换为实际张量即可。