优化大型语言模型以使其在生产环境中高效运行是一项主要目标,尤其是在它们经过特定用途的微调之后。微调后量化是实现此目标的一种有效方法,显著减少模型的内存占用,并经常加速推理速度,尤其是在兼容硬件上。它的做法是将模型的权重(有时也包括激活值)从高精度浮点格式(例如32位浮点数,$fp32$,或16位脑浮点数,$bf16$)转换为低精度整数格式,最常见的是8位整数($int8$)甚至4位整数($int4$)。核心思想很简单:即使用一组小得多的离散整数值来表示连续浮点值的范围。这种精度降低直接带来:内存占用减少: 低精度类型需要较少的存储空间。从$fp16$到$int8$可将模型大小减半,到$int4$则可将模型大小缩小至四分之一。这不仅有利于存储,还能减少推理期间所需的内存带宽,而内存带宽通常是瓶颈。计算加速: 许多现代处理器(CPU和GPU)都有专门的硬件指令,可比浮点运算更快地执行整数运算。进行$int8$或$int4$计算能够带来显著的延迟降低。能耗降低: 整数运算通常比浮点运算消耗更少的电量。量化要点量化是指将浮点值$X$映射到其整数表示$X_q$。此映射通常需要缩放因子$S$和零点$Z$这两个参数。范围确定: 首先,需要确定待量化的浮点数(权重或激活值)的范围(最小值$min$和最大值$max$)。缩放因子 ($S$): 此因子将浮点数范围缩放到目标整数范围。对于无符号$b$位整数(范围$[0, 2^b-1]$),它通常计算为: $$ S = \frac{max - min}{2^b - 1} $$零点 ($Z$): 此整数值对应于浮点域中的实数零。它确保零能够被精确表示,这对于填充等操作很重要。一种常见的计算方式是: $$ Z = \text{取整}\left(-\frac{min}{S}\right) $$ 注意,$Z$必须在目标整数范围内(例如,$uint8$的范围是$[0, 255]$)。如果量化方案是对称的(例如$int8$将$[-a, a]$映射到$[-127, 127]$),则零点通常根据具体情况固定为0或128。量化: 浮点值$X$使用以下公式进行量化: $$ X_q = \text{截断}(\text{取整}(X / S) + Z) $$ 截断函数确保结果保持在目标整数类型的有效范围内(例如,$uint8$的范围是$[0, 255]$)。反量化: 为了执行计算或返回接近原始值,量化后的整数$X_q$进行反量化: $$ X_{dq} = S \times (X_q - Z) $$ $X_{dq}$是原始值$X$的近似。量化可应用于模型的不同部分:权重量化: 仅模型的参数(权重)以低精度存储。在推理过程中,它们通常在计算前反量化回更高精度(如$fp16$)。这主要节省存储和内存带宽。激活值量化: 层之间流动的中间输出(激活值)也进行量化。这需要仔细处理值范围,因为它们可能根据输入的不同而有很大差异。动态量化: 激活值范围在推理期间即时确定。方法更简单但会增加开销。静态量化: 激活值范围使用校准数据集预先计算。需要额外的校准步骤,但推理通常更快。权重和激活值量化: 权重和激活值都进行量化,使得可以使用低精度整数运算(例如$int8$矩阵乘法)直接进行计算。这在兼容硬件上带来了最大的加速潜力。大型语言模型常用量化技术虽然基本原则适用,但已出现几种专门技术,可有效量化大型Transformer模型,同时保持最小的精度损失。训练后量化 (PTQ)PTQ是在模型完全训练和微调之后应用的。它通常更易于实施,因为它不需要改变训练过程。过程: PTQ通常包括直接量化权重,并使用少量具有代表性的校准数据集来确定激活值的量化参数($S$和$Z$)。模型在此数据集上运行以观察激活值的分布。优点: 易于应用,无需重新训练。缺点: 有时会导致明显的精度下降,尤其是在量化到极低位宽(例如$int4$或更低)时,因为模型没有经过训练来处理这种精度损失。量化感知训练 (QAT)QAT将量化效果融入到微调过程中。过程: 它包括在训练期间将“假量化”节点插入到模型图中。这些节点在正向传播期间模拟量化效果(量化并立即反量化),同时允许梯度在反向传播期间流动。模型学习调整其权重,以尽量减少这种模拟量化引入的误差。优点: 通常比PTQ产生更好的精度,特别是对于激进量化(例如$int4$权重和$int8$激活值),因为模型学会补偿精度损失。缺点: 实施更复杂,需要修改训练流程,并需要额外的微调计算时间。大型语言模型的先进PTQ方法考虑到大型语言模型的规模及其敏感性,已开发出几种先进的PTQ方法:GPTQ (生成式预训练Transformer量化): 一种逐层权重量化方法,旨在比简单舍入更智能地最小化量化误差。它分析层重建误差相对于权重的Hessian(二阶导数)信息。通过迭代量化权重并根据此信息更新剩余权重,GPTQ试图补偿早期权重量化引入的误差。它通常在$int4$甚至$int3$权重量化方面取得良好效果,且校准数据需求极少。AWQ (激活感知权重量化): 此方法观察到,对于连接到具有较大幅值的激活值的权重,量化误差更具破坏性。AWQ根据激活值尺度识别显著权重并在量化期间保护它们。它通过在量化之前缩小与这些显著权重相关的激活通道,并按比例放大相应的权重来实现。这有效地将量化难度从激活值转移到权重,从而保持重要计算的精度。AWQ在$int4$方面通常与GPTQ性能匹敌或胜过,并且通常只需要很少的校准数据。SmoothQuant: 解决了同时量化权重和激活值的难题,特别是在激活值存在显著异常点时。异常点使得静态激活值量化变得困难。SmoothQuant引入了一种数学上等价的变换:该变换按通道缩小激活值(使其更容易量化)并放大权重。这种“平滑”使得$int8$权重和激活值量化能够有效进行,并有良好表现。LLM.int8(): 一种主要侧重于$int8$量化的技术,专门处理激活值中的异常特征。它以混合精度执行矩阵乘法:大部分计算在$int8$中进行,但检测到的异常激活值会以$fp16$处理,以保持这些重要特征的精度。{"layout": {"title": "相对模型大小与精度", "xaxis": {"title": "精度类型"}, "yaxis": {"title": "相对大小 (fp32=1.0)"}, "template": "plotly_white", "width": 600, "height": 400}, "data": [{"type": "bar", "x": ["fp32", "fp16 / bf16", "int8", "int4"], "y": [1.0, 0.5, 0.25, 0.125], "marker": {"color": ["#4263eb", "#74c0fc", "#fd7e14", "#ffc078"]}}]}当从32位浮点数转换为更低精度时,模型大小的缩减。权衡与实际考量应用量化涉及平衡多个因素:精度: 这通常是首要考虑的问题。为了提高效率,可接受多大的性能下降?$int8$量化对于许多模型通常是相当安全的,而$int4$则需要更仔细的应用和评估,通常依赖于GPTQ或AWQ等方法。QAT有助于保持精度,但需要更多投入。硬件兼容性: 量化带来的实际加速效果很大程度上取决于目标推理硬件。NVIDIA最新架构的GPU具有专门的Tensor Cores,可为$int8$(有时是$fp8$)矩阵乘法提供显著加速。$int4$支持较不常见,可能主要提供内存节省,除非有特定的硬件/内核(例如bitsandbytes或TensorRT-LLM使用的那些)可用。量化为非原生加速的格式可能只带来内存优势而无速度提升。量化粒度: 量化参数($S$,$Z$)可以按张量、按通道/组,甚至按令牌(对于激活值)计算。更细的粒度(例如按通道)通常可以带来更好的精度,但会增加复杂性和元数据开销。校准数据: 对于静态PTQ方法,校准数据的选择很重要。它应能代表模型在推理期间将遇到的数据,以确保激活值的范围估计准确。工具: 从头开始实施这些技术很复杂。Hugging Face的optimum(与ONNX Runtime、TensorRT接口)、bitsandbytes、AutoGPTQ、AutoAWQ等库,以及TensorRT-LLM或vLLM等专门推理服务器,提供了用于应用各种量化方法的工具和预优化内核。量化模型的评估应用量化后,严格的评估是必不可少的。标准基准: 衡量相关学术基准(例如GLUE、SuperGLUE、HELM)上的性能。特定任务指标: 使用为其定义的具体指标(例如,准确率、F1分数、ROUGE、BLEU、指令遵循分数)直接评估微调任务上的性能。定性分析: 对模型输出进行人工检查,以查看可能未被自动化指标捕捉到的细微退化、偏差增加或无意义输出。注意在早期评估阶段发现的边缘情况。量化是一种有效的优化工具,使得大型微调模型能够在资源受限的环境中部署。通过仔细选择合适的方法(PTQ、QAT、GPTQ、AWQ)并评估权衡,您可以显著提升已部署大型语言模型的效率。