一旦拥有训练好的模型和具有代表性的校准数据集,训练后量化(PTQ)的核心工作就是确定量化参数:比例因子($s$)和零点($z$)。这些参数定义了从校准期间观察到的浮点范围到目标整数范围(例如 INT8,通常为 [-128, 127])的映射。存在多种算法来计算这些参数,每种算法在简易性、对异常值的稳定性以及潜在的精度影响之间都有其自身的权衡。最常见的几种算法将被描述。MinMax 量化这是最简单直接的方法。它使用给定张量(或量化组)在校准数据中观察到的绝对最小值和最大值来确定范围。工作原理:在校准期间,跟踪被量化张量遇到的最小值($x_{min}$)和最大值($x_{max}$)。直接使用这些值来计算比例因子和零点。对于非对称量化,零点可以是目标范围内的任意整数,其公式为:$$ s = \frac{x_{max} - x_{min}}{Q_{max} - Q_{min}} $$$$ z = \text{round}(Q_{max} - \frac{x_{max}}{s}) $$这里,$Q_{min}$ 和 $Q_{max}$ 表示目标整数范围的最小值和最大值(例如,有符号 INT8 的 -128 和 127)。零点 $z$ 本质上是对应于浮点值 0.0 的整数值。对于对称量化,范围以零为中心,强制零点 $z$ 为 0(对于有符号整数)。比例因子由观察到的最大绝对值确定:$$ s = \frac{\max(|x_{min}|, |x_{max}|)}{Q_{max}} $$$$ z = 0 $$(这里,$Q_{max}$ 对于有符号 INT8 将是 127,将范围 $[-\max(|\dots|), +\max(|\dots|)]$ 映射到 $[-127, 127]$。)优点:实现和理解起来非常简单。保证所有观察到的校准值在量化后都落在可表示的范围内(没有基于校准数据的裁剪)。缺点:对异常值高度敏感。单个极端值,即使不常见,也会显著扩大所需范围($x_{max} - x_{min}$ 或 $\max(|x_{min}|, |x_{max}|)$)。这会使得比例因子 $s$ 变大,意味着可用于表示大部分数据分布的整数值更少,可能导致明显的量化误差和精度下降。{"layout":{"title":"异常值对量化范围的影响","xaxis":{"title":"值"},"yaxis":{"title":"频率"},"barmode":"overlay", "legend":{"yanchor":"top", "y":0.99, "xanchor":"right", "x":0.99}},"data":[{"type":"histogram","x":[0.1,0.2,0.15,0.3,0.25,0.1,0.2,0.18,0.22,0.13,0.28,0.21, 1.5],"name":"含异常值数据","opacity":0.75,"marker":{"color":"#4dabf7"}},{"type":"histogram","x":[0.1,0.2,0.15,0.3,0.25,0.1,0.2,0.18,0.22,0.13,0.28,0.21],"name":"无异常值数据","opacity":0.75,"marker":{"color":"#69db7c"}}]}直方图显示了包含和不包含异常值的数据分布。MinMax 量化使用包含异常值的整个范围(例如,高达 1.5),这可能会降低 0.1 到 0.3 之间更常见值的精度。百分位数量化为减轻 MinMax 对异常值的敏感性,百分位数量化使用分布尾部的值,但不是绝对的极端值。工作原理:在校准期间收集值的分布(通常以直方图形式)。选择下限和上限百分位数阈值(例如,0.1% 和 99.9%,或 1% 和 99%)。确定对应于这些百分位数的浮点值,我们称之为 $p_{low}$ 和 $p_{high}$。在比例因子和零点计算公式中(无论是对称还是非对称),使用 $p_{low}$ 和 $p_{high}$ 代替 $x_{min}$ 和 $x_{max}$。任何落在 $[p_{low}, p_{high}]$ 范围之外的原始浮点值在量化期间都将被截断(或饱和)到最小或最大可表示整数值。优点:比 MinMax 对异常值更具抵抗力。通过忽略最极端的值,它通常会得到更小的比例因子 $s$ 和更好的数据分布精度。实现相对简单,只需收集直方图和计算百分位数。缺点:对被截断的异常值引入饱和误差。如果这些异常值带有重要信息,截断它们可能会对精度产生负面影响。需要选择合适的百分位数,这成为一个需要调整的超参数。最佳百分位数可能因不同层或模型而异。熵(KL 散度)量化该方法采用了一种更偏向信息论的方式。它旨在找到一个量化范围(由裁剪阈值定义),以最大程度地减少原始浮点分布与量化分布之间的信息损失。用于衡量这种信息损失最常用的度量是 Kullback-Leibler (KL) 散度。工作原理:从校准数据集中收集激活值的直方图。这表示原始概率分布 $P$。遍历不同的可能裁剪阈值。对于每个阈值: a. 根据阈值定义一个量化范围(通常是对称的,即 $[-threshold, +threshold]$)。 b. 使用此范围量化阈值内的值。超出阈值的值将被饱和到最小/最大量化值。 c. 创建一个新直方图,表示量化后再反量化(将其映射回浮点近似值)后的分布 $Q$。由于量化误差和饱和,此分布 $Q$ 将与 $P$ 不同。 d. 计算原始分布 $P$ 和量化分布 $Q$ 之间的 KL 散度。$D_{KL}(P || Q)$。选择导致最小 KL 散度的阈值。该阈值根据此标准定义了量化的最佳范围。根据所选阈值计算最终的比例因子($s$)和零点($z$),类似于对称 MinMax,但使用最佳阈值而不是绝对最大值。优点:在常见 PTQ 算法中通常能达到最佳精度,特别是对于非均匀或偏斜分布,因为它直接尝试保持整体分布形状。提供了一种更具原则性的方式来处理饱和(裁剪异常值)和量化误差(内部值精度)之间的权衡。缺点:在校准期间计算成本较高,因为需要进行直方图统计并迭代测试多个阈值以及计算 KL 散度。结果可能对用于分布直方图表示的 bin 数量敏感。算法选择最佳 PTQ 算法通常取决于具体情况:权重: 权重分布通常相对稳定且大致围绕零对称。MinMax 或百分位数方法(通常是对称的)常被使用且表现良好。激活: 激活分布可能因输入数据和层类型而明显不同。它们通常是非对称的,并且可能存在明显的异常值。熵(KL 散度)或百分位数方法常用于激活,以更好地处理这些特点。非对称量化方案对于激活也更常见。性能与精度: MinMax 在校准期间最快,但最容易因异常值导致精度损失。熵在校准期间最慢,但通常能提供最高精度。百分位数在这两者之间提供了一种平衡。在实践中,Hugging Face Optimum 或 PyTorch 的量化模块等库通常提供这些算法的实现,让您能够尝试并选择最符合特定模型和任务精度及性能要求的方法。您甚至可以在同一模型中混合使用权重和激活的不同策略。