大语言模型通常包含数十亿参数,并以32位浮点(FP32)格式表示,在推理过程中对内存和计算资源提出较大要求。量化提供一套有效方法来应对这些挑战,通过使用较低精度的数值格式(通常是8位整数(INT8)或甚至4位整数(INT4))来表示模型权重,有时也表示激活值。这种精度降低能带来更小的模型占用空间、降低内存带宽需求、更快的推理速度(尤其是在支持低精度运算的专用硬件上)以及更低的能耗。然而,量化并非没有代价。降低数值精度可能影响模型精度。主要任务是有效地应用量化方法,最大限度减少精度下降,同时最大限度提升性能。量化原理本质上,量化将浮点值从一个连续范围映射到一组离散的较低精度整数值。例如,将FP32值(范围大约从$-3.4 \times 10^{38}$到$+3.4 \times 10^{38}$)映射到INT8值(范围从-128到127)。这种映射需要两个重要参数:比例因子 ($s$): 一个正浮点数,它决定量化级别之间的步长。零点 ($z$): 一个整数值,对应于浮点值0.0。它确保实数零可以精确无误差地表示。真实值 $r$ 及其量化整数表示 $q$ 之间的关系可以表示为: $$r \approx s \times (q - z)$$量化过程(将浮点数映射到整数)是: $$q = \text{round}(r / s) + z$$难点在于为模型的不同部分(例如,每个张量、每个通道)确定最佳的比例因子和零点值,以最小化此映射引入的信息损失。主要量化方法在LLMOps工作流中实现量化主要有两种策略:训练后量化(PTQ)和量化感知训练(QAT)。训练后量化(PTQ)PTQ是一种更简单的方法,在模型已训练完成后应用。它涉及获取一个预训练的FP32模型,并将其权重(以及可能的激活值)转换为较低精度格式。工作流程:校准: 这是PTQ中非常重要的一步。一个小的、有代表性的数据集(校准数据集)会通过已训练的FP32模型进行处理。记录在不同层观察到的激活值范围。此信息用于计算适当的比例因子 ($s$) 和零点 ($z$) 参数,用于在推理期间动态量化激活值,或有时静态量化权重。权重转换: FP32权重被转换为目标低精度格式(例如INT8),使用计算出的或预定义的量化参数。部署: 量化模型以及量化参数(比例因子、零点)被部署。推理引擎使用这些参数进行整数运算或模拟量化。优点:简单: 无需更改原始训练流程。速度: 实施相对快速,因为它不涉及再训练。易用性: 可以应用于现有的预训练模型。缺点:潜在精度损失: 可能导致明显的精度下降,尤其是在激进量化(例如INT4)时,或对于对精度变化敏感的模型。校准质量非常重要。恢复能力有限: 与QAT相比,精度损失更难恢复。示例(使用Hugging Face Optimum):from optimum.onnxruntime import ORTQuantizer from optimum.onnxruntime.configuration import AutoQuantizationConfig # 假设'model_checkpoint'指向一个标准的Transformer模型 # 假设'onnx_model_path'是导出ONNX模型的路径 # 1. 为ONNX模型创建一个量化器 quantizer = ORTQuantizer.from_pretrained(model_checkpoint, feature='sequence-classification') # 2. 定义量化配置(例如,权重和激活的INT8静态量化) qconfig = AutoQuantizationConfig.avx512_vnni(is_static=True, per_channel=False) # 示例配置 # 3. 定义校准数据集(需要一个真实的数集加载器) def preprocess_fn(examples): # 根据模型的tokenizer对输入进行分词 return quantizer.tokenizer(examples['text'], padding='max_length', truncation=True) calibration_dataset = load_dataset("glue", "sst2", split="validation[:100]") # 小样本 calibration_dataset = calibration_dataset.map(preprocess_fn, batched=True) # 4. 运行量化 quantizer.quantize( save_dir='./quantized_model', quantization_config=qconfig, dataset=calibration_dataset, batch_size=8 )量化感知训练(QAT)QAT在微调或训练过程中引入了量化效果的模拟。它允许模型使其权重适应降低的精度,通常能恢复PTQ中损失的大部分精度。工作流程:模型修改: “假”量化操作(模拟量化和反量化效果的节点)被插入到模型图中,通常在具有权重(如线性层)和激活函数之后。微调/训练: 模型在这些假量化节点激活的情况下进行训练或微调。前向传播模拟量化噪声,后向传播允许梯度流动,使模型权重能够调整以最大程度减少这种噪声的影响。权重转换: 训练后,学习到的FP32权重被转换为目标低精度格式,使用QAT期间隐式学习或确定的参数。部署: 真正量化后的模型被部署。优点:更高精度: 通常比PTQ获得更好的精度,尤其对于较低位深(INT4,INT8)。更强的适应性: 模型能更好地适应量化噪声。缺点:复杂性: 需要修改训练流程并访问训练过程。训练时间: 增加训练/微调时间和计算成本。超参数调整: 可能需要针对QAT过程本身进行额外调整。QAT集成(PyTorch):import torch import torch.quantization as quant # 假设'model'是你的FP32 PyTorch模型 model.eval() # 设置为评估模式以准备QAT # 指定QAT配置 model.qconfig = quant.get_default_qat_qconfig('fbgemm') # 示例后端 # 准备模型进行QAT:插入观察器和fake_quant模块 model_prepared = quant.prepare_qat(model) # --- 训练循环 --- # model_prepared.train() # 设置为训练模式 # for epoch in range(num_epochs): # for batch in dataloader: # inputs, labels = batch # optimizer.zero_grad() # outputs = model_prepared(inputs) # 前向传播模拟量化 # loss = criterion(outputs, labels) # loss.backward() # 后向传播调整权重 # optimizer.step() # --- 训练循环结束 --- # 将QAT训练后的模型转换为真正量化后的模型 model_prepared.eval() model_quantized = quant.convert(model_prepared) # 现在'model_quantized'包含INT8权重,可用于推理量化格式与权衡INT8: 最常见的格式。在性能提升(在支持硬件上通常有2-4倍的加速)和精度保持之间取得良好平衡。得到硬件(NVIDIA Tensor Cores,Intel DL Boost)和软件框架的广泛支持。INT4: 更激进的量化。带来更大的模型尺寸缩小(比INT8小约2倍)和进一步加速的可能,但通常伴随更明显的精度损失。需要细致的实施(例如,使用GPTQ或AWQ等方法)和评估。硬件支持正在兴起。FP8: 一种正在获得关注的新格式,特别适用于大型Transformer模型的训练和推理。提供比INT8更宽的动态范围,同时保持低精度。需要特定的硬件支持(例如NVIDIA Hopper/Blackwell GPU)。包含两种主要变体:E4M3(4位指数,3位尾数)和E5M2(5位指数,2位尾数)。其他格式: FP16/BF16是半精度浮点格式,通常用作基准或中间步骤,相比FP32有一些优点,但压缩/加速效果不如整数格式。二进制/三进制量化代表位使用最少但通常精度损失较大的极端情况,在大型生成模型中较不常见。{"layout": {"title": "通过量化实现模型尺寸缩减", "xaxis": {"title": "格式"}, "yaxis": {"title": "相对尺寸 (FP32=1.0)"}, "template": "plotly_white", "shapes": [], "annotations": []}, "data": [{"type": "bar", "x": ["FP32", "FP16/BF16", "INT8", "INT4"], "y": [1.0, 0.5, 0.25, 0.125], "marker": {"color": ["#495057", "#748ffc", "#20c997", "#ff922b"]}, "name": "模型尺寸"}]}各种量化格式相对于原始FP32表示所实现的模型尺寸缩减。工具和库有几个库和框架有助于实现LLM的量化:Hugging Face Optimum: 提供与各种硬件加速和优化后端(ONNX Runtime, TensorRT, OpenVINO)的接口,包括量化能力(PTQ)。PyTorch: 提供PTQ (torch.quantization.quantize_dynamic, torch.quantization.prepare, torch.quantization.convert) 和QAT (torch.quantization.prepare_qat) 的内置模块。TensorFlow Lite: 主要面向移动/边缘设备,但提供可调整的量化工具(PTQ,QAT)。NVIDIA TensorRT: 一款高性能推理优化器和运行时。包含强大的PTQ和有时QAT能力,通常在NVIDIA GPU上实现优秀的性能。TensorRT-LLM专门用于LLM。bitsandbytes: 一款流行的库,用于在运行时直接在PyTorch模型中启用4位和8位量化,常用于在消费级硬件上微调大型模型。AutoGPTQ / GPTQ-for-LLaMA: 实现GPTQ算法的库,这是一种特定的PTQ方法,能有效地将类GPT模型量化到INT4或INT3,且精度损失相对较低。AWQ(激活感知权重校准): 另一种先进的PTQ方法,侧重于根据激活分布保护重要权重,通常能实现良好的INT4性能。将量化集成到LLMOps工作流程中评估策略: 在应用量化之前,明确定义精度指标并设定可接受的精度下降阈值。在有代表性的测试数据集上严格评估量化后的模型。选择PTQ或QAT: 首先尝试PTQ(例如INT8),因为它更快。如果精度下降不能接受,考虑更复杂的PTQ校准、每通道量化,或投入QAT(如果微调可行)。自动化: 将量化步骤集成到你的MLOps流程中。对于PTQ,在训练/微调后自动化校准和转换过程。对于QAT,将QAT微调阶段纳入你的训练流程。版本控制: 将量化模型与其FP32对应模型一同存储,并追踪量化方法、校准数据集(针对PTQ)和评估结果。硬件适配: 选择与目标推理硬件的加速能力兼容的量化方案(例如,INT8 Tensor Cores,特定的FP8支持)。推理引擎兼容性: 确保你选择的推理服务器(Triton, vLLM, TGI等)支持所使用的量化格式和库。量化是一种核心技术,用于使大语言模型实现实用部署。通过审慎选择正确的方法(PTQ或QAT)和格式(INT8, INT4, FP8),并通过严格评估将其系统地整合到你的LLMOps流程中,你可以显著降低资源消耗并提升推理延迟,同时平衡模型精度之间的权衡。