训练后量化(PTQ)提供了两种主要处理模型激活的方法:静态量化和动态量化。它们的主要区别在于激活的量化参数(缩放因子和零点)是何时确定和应用的。在这两种方案中,权重通常都在离线(推理前)进行量化。
静态量化
静态量化是在执行推理之前对模型权重和激活进行量化。由于激活的取值范围可能因输入数据而异,静态量化需要一个校准步骤。
- 校准: 将一个有代表性的数据集(校准数据集)以其原始精度(例如,FP32)通过模型。模型中各个点(例如,特定层的输出)的激活值的典型取值范围(最小值和最大值)会被观察并记录下来。
- 参数计算: 基于校准期间观察到的范围,为模型内不同量化点的激活计算固定的量化参数(缩放因子和零点)。这些参数的选择旨在合理地表示观察到的激活分布。
- 离线量化: 权重和激活(使用计算出的静态参数)都被量化并存储为INT8等低精度格式。
- 推理: 在推理过程中,模型主要使用整数运算执行计算,因为权重和激活量化参数都已预先确定。输入数据使用校准期间为第一层输入确定的参数进行量化,并且中间激活在层与层之间尽可能保持量化格式。
静态量化工作流程:校准在离线阶段确定激活参数,从而在推理期间实现高效的纯整数计算。
优点:
- 更高的潜在性能: 由于所有量化参数都预先固定,推理可以在支持的硬件(CPU、GPU、加速器)上完全使用高度优化的整数算术指令运行,从而实现最大程度的加速和能效。
- 更低的推理开销: 计算激活范围或量化参数无需运行时成本。
缺点:
- 需要校准数据: 需要一个数据集,该数据集能够准确反映模型在生产中将遇到的输入分布。差的校准数据可能导致精度显著下降。
- 对离群值敏感: 如果运行时输入产生的激活范围与校准期间观察到的范围显著不同,精度可能会受到影响。未在校准期间捕获的离群值会被截断,可能会丢失重要信息。
动态量化
动态量化,在某些情况下也常被称为“仅权重量化”,采取了不同的方法。权重在离线阶段量化,这一点与静态量化类似。然而,激活是在推理过程中动态或即时量化的。
- 离线权重量化: 模型权重被转换为低精度整数格式(例如,INT8)并存储。
- 推理:
- 当输入数据到来时,激活会逐层处理。
- 对于涉及量化权重的操作(如矩阵乘法),传入的浮点激活会在操作前立即量化。它们的范围(最小值/最大值)是根据当前批次数据动态计算的。
- 计算(例如,
INT8权重 * INT8激活)得以执行。
- 结果通常在传递给需要浮点输入的下一个操作或层(如某些激活函数或归一化层)之前,反量化回浮点数(FP32)。
动态量化工作流程:权重在离线阶段量化,但激活在推理期间即时量化,这会增加开销,但消除了对校准数据的需求。
优点:
- 无需校准数据: 简化了量化过程,因为它不需要为激活提供单独的校准步骤或数据集。
- 更具适应性: 适应每个输入的特定激活范围,如果校准不理想,可能比静态量化更好地处理意料之外的分布。
- 简便性: 最初实现起来更简单。
缺点:
- 更高的推理开销: 在推理期间动态计算激活范围并执行量化/反量化会增加计算成本,从而降低与静态量化相比的潜在加速效果。
- 内存带宽: 持续读取FP32激活、对其进行量化、执行计算并经常反量化回FP32,这会增加内存带宽使用,与完全静态的INT8流水线相比。
- 并非总是纯整数: 整数权重与动态量化/反量化激活的混合意味着计算可能无法在所有硬件上完全利用纯整数算术路径,从而可能限制性能提升。
选择静态量化与动态量化
选择取决于您应用程序的具体要求:
- 选择静态量化的情形:
- 最大推理速度和能效是首要目标。
- 您拥有有代表性的校准数据。
- 目标硬件对完整整数算术流水线有高效支持。
- 您愿意投入时间进行校准过程并可能对其进行微调。
- 选择动态量化的情形:
- 优先考虑简便性和易于实现。
- 获取好的校准数据很困难或不切实际。
- 可以接受一定的推理开销。
- 主要目标是减少权重内存占用,且激活计算开销不那么重要。
对于大型语言模型(LLM),由于其计算密集性,静态量化通常更受青睐,以最大化吞吐量并降低延迟。然而,LLM中大的激活范围和离群值的存在,使得有效的校准对于静态量化尤为重要。动态量化可以是一个更简单的起点,主要减少权重的内存占用,但动态激活量化的计算开销对于LLM来说可能相当大。更高级的PTQ技术,稍后会讨论,通常会基于静态量化框架来解决其局限性。