
1. 为什么大模型推理绕不开量化这件事1.1 从显存墙说起模型权重到底吃掉多少资源先把账算清楚。一个千亿参数级别的 MoE 模型如果权重全部用 FP16 存储光权重就要占 200GB 左右的显存。这还没算上 KV Cache、激活值、临时缓冲区。单卡放不下多卡就得考虑通信开销而通信带宽往往比算力更早成为瓶颈。这就是所谓的“显存墙”——不是算不动是根本装不下。量化的本质是用更少的比特位来表示原本需要高精度存储的数值。FP16 用 16 位表示一个数INT8 只用 8 位4 bit 更是只用 4 位。理论上从 FP16 降到 INT8存储占用直接砍半降到 4 bit占用只剩四分之一。对于 Kimi 2.7 这类 MoE 架构的模型来说专家数量多、总参数量大但每次推理只激活其中一部分专家这种稀疏激活特性让量化收益更加明显——你不需要把所有专家都塞进最高精度里。但量化不是免费的午餐。位宽越低数值表示的动态范围越窄精度损失越大。4 bit 能表示的无符号整数只有 0 到 15 这 16 个档位要覆盖神经网络权重那种近似正态分布、跨度可能从 -0.5 到 0.5 甚至更大的范围就必须引入缩放因子和零点偏移。这就是量化的核心机制用一组量化参数把浮点区间线性映射到整数区间。1.2 W4A8 到底是什么意思W4A8 是权重 4 bit、激活 8 bit 的缩写。W 代表 WeightA 代表 Activation。这个组合不是随便定的背后有很实际的工程考量。权重是静态的模型训练完之后就固定了可以离线做精细的量化校准甚至可以用分组量化、混合精度等手段把 4 bit 的精度损失压到可接受范围。激活值是动态的每次推理输入不同激活值的分布就会变化离线校准很难覆盖所有情况。如果激活也压到 4 bit精度崩坏的风险会显著上升。所以激活保留 8 bit是一个精度和效率之间的折中。从硬件角度看INT8 的矩阵乘加MMAC在主流推理芯片上都有原生支持吞吐量通常是 FP16 的两倍甚至更高。而 4 bit 权重的加载带宽需求只有 FP16 的四分之一对于显存带宽受限的场景这个收益非常直接。W4A8 的组合等于在权重侧吃满带宽红利在激活侧保住计算精度。1.3 Kimi 2.7 MoE 为什么适合这套方案MoE 架构的特点是专家网络数量多但每次 token 只路由到少数几个专家。这意味着大部分专家权重在单次推理中是不参与计算的但它们仍然占着显存。如果每个专家都用 FP16 存显存浪费非常严重。把专家权重压到 4 bit等于用同样的显存能放下四倍的专家数量或者用四分之一的显存放下同样的专家。另外MoE 的路由机制本身有一定的容错性。即使某个专家的量化误差稍大只要路由没有把关键 token 集中送到这个专家整体输出的退化就不明显。这一点和稠密模型不同——稠密模型每一层都参与计算任何一层的量化误差都会累积传播。MoE 的稀疏性反而给量化留出了更大的误差预算。Kimi 2.7 作为新一代 MoE 模型在训练阶段可能已经考虑了量化友好性比如权重分布更集中、激活函数选择更利于量化等。这些先验条件让 W4A8 方案在这类模型上的落地难度比通用模型低不少。2. 4 bit 存储的核心机制与量化参数计算2.1 对称量化与非对称量化的选择逻辑4 bit 量化最常用的两种方案对称量化和非对称量化。对称量化把浮点范围映射到以零为中心的整数区间比如 4 bit 有符号整数范围是 -8 到 7。量化公式很简单q round(x / scale)反量化就是x q * scale。scale 通常取max(abs(x)) / 7保证最大绝对值映射到 7 或 -8。这种方案的好处是计算简单零点固定为 0矩阵乘法时不需要额外处理偏移。非对称量化则引入零点偏移把浮点范围映射到无符号整数区间比如 0 到 15。公式变成q round(x / scale) zero_point反量化是x (q - zero_point) * scale。scale 取(max(x) - min(x)) / 15zero_point 取round(-min(x) / scale)。这种方案能更好地利用整数区间尤其适合权重分布不对称的情况。对于 Kimi 2.7 这类模型的权重实际分布往往近似零均值对称量化已经够用而且计算开销更低。但在某些层比如 gate 网络的输出或者某些归一化层之后的权重分布可能明显偏移这时候非对称量化的优势就体现出来了。实际工程中通常是逐层判断甚至逐通道判断用哪种方案。2.2 分组量化4 bit 精度不够时的救命稻草4 bit 的表示能力有限如果整个权重矩阵共用一个 scale那些数值较小的权重就会被量化到零信息直接丢失。分组量化Group-wise Quantization就是解决这个问题的。具体做法是把权重矩阵按通道或者按块分组每组独立计算 scale 和 zero_point。比如每 128 个权重一组每组有自己的量化参数。这样数值小的组可以用更小的 scale保留更多细节数值大的组用更大的 scale避免溢出。分组越细精度越高但量化参数占用的存储也越多反量化时的计算开销也越大。常见的分组大小有 32、64、128、256。选哪个取决于模型对精度的敏感度和硬件的反量化效率。实测下来128 是一个比较平衡的点——精度损失可控额外存储开销大约在 3% 左右每组两个 FP16 参数128 个 4 bit 权重共 64 字节参数占 4 字节。2.3 量化参数的离线校准流程权重的量化参数可以离线算流程大致如下加载 FP16 或 BF16 的原始权重。按分组策略切分权重矩阵。对每组计算max(abs(x))或max(x)和min(x)。根据对称或非对称方案算出 scale 和 zero_point。用round(x / scale)得到整数权重裁剪到 4 bit 范围。保存整数权重和对应的量化参数。这里有个细节校准用的权重应该是推理时实际加载的权重而不是训练时的权重。有些模型在导出推理格式时会做权重融合比如把 BatchNorm 融合进卷积层融合后的权重分布会变化量化参数必须基于融合后的权重重新计算。另外对于 MoE 模型每个专家的权重是独立校准的。不同专家的权重分布可能差异很大共用量化参数会导致某些专家精度严重下降。逐专家校准是必须的。2.4 从 4 bit 存储到 INT8 计算的转换路径权重存成 4 bit但计算时通常要还原到 INT8 或更高精度。这个转换路径的设计直接影响推理效率。一种做法是在加载权重时就把 4 bit 反量化成 INT8然后 INT8 权重和 INT8 激活做矩阵乘法。这样计算核心只需要支持 INT8 MMAC硬件兼容性好。但反量化本身有开销如果每次推理都要重新反量化这部分开销会累积。另一种做法是保持权重为 4 bit在计算单元内部做 4 bit 权重和 8 bit 激活的混合精度乘加。这需要硬件支持混合精度指令比如某些推理芯片提供的 4 bit 权重加载加 INT8 计算通路。这种方案省去了显式的反量化步骤但硬件门槛更高。实际部署中第一种方案更常见因为 INT8 MMAC 的生态成熟工具链完善。反量化的开销可以通过预计算或者流水线隐藏来降低。3. INT8 激活量化的实操要点3.1 激活量化的动态范围问题激活量化的难点在于动态范围。权重是固定的激活是随输入变化的。同一个模型输入一段代码和输入一段自然语言中间层的激活分布可能完全不同。如果量化参数用固定值遇到分布偏移的输入就会出问题。常见的解决方案是动态量化每次推理时先统计当前 batch 激活的最大绝对值算出 scale再量化。这样做精度有保障但引入了一个统计步骤增加了延迟。对于延迟敏感的场景可以用滑动窗口统计历史激活的分布用历史统计值来估计当前 scale牺牲一点精度换速度。还有一种方案是混合量化对激活分布稳定的层用静态量化对分布波动大的层用动态量化。哪些层稳定、哪些层波动大需要在校准集上跑一遍统计。3.2 激活量化的校准集选择校准集的质量直接决定激活量化的精度。校准集应该覆盖模型实际部署时可能遇到的各种输入类型。如果模型用于对话校准集里就应该有各种长度、各种话题的对话数据如果模型用于代码生成校准集里就应该有不同编程语言、不同复杂度的代码片段。校准集的数量不需要很大通常几百到几千条就够。关键是多样性而不是数量。我见过有人用几万条同质数据做校准结果量化后模型在少数场景下崩得很厉害就是因为校准集没有覆盖到那些场景。对于 MoE 模型校准集还要考虑路由的多样性。如果校准集里所有输入都路由到同一组专家其他专家的激活分布就没被统计到量化参数会偏。所以校准集要尽量让路由分散开。3.3 激活量化的对称与非对称选择和权重一样激活也可以选对称或非对称量化。激活分布通常比权重更不对称因为 ReLU 之类的激活函数会把负值截断到零导致分布偏向正值。这种情况下非对称量化能更好地利用整数区间。但非对称量化在计算时多一个零点偏移的处理步骤。对于 INT8 MMAC如果激活和权重都用了非对称量化矩阵乘法的累加结果需要做零点修正公式会复杂一些。实际工程中常见做法是权重用对称量化激活用非对称量化这样权重侧的零点为零修正项简化。3.4 INT8 激活量化的精度补偿技巧如果激活量化后精度损失明显有几个补偿技巧可以试逐通道量化对激活的每个通道独立计算 scale而不是整个张量共用一个 scale。这能显著提升精度但增加了量化参数存储和计算开销。量化感知训练微调在量化后的模型上做少量微调让权重适应量化误差。这需要训练资源但效果通常最好。混合精度回退对量化敏感的层保留 FP16 或 BF16其他层用 INT8。哪些层敏感可以通过逐层量化实验来确定。激活裁剪在校准时统计激活的百分位数比如 99.9% 分位数用这个值作为量化范围的上界而不是用最大值。这样能避免个别极端值拉大量化范围导致大部分激活被量化到很小的整数区间。4. 完整实操流程从模型导出到 W4A8 推理4.1 环境准备与工具链选型做 W4A8 量化工具链的选择很关键。目前主流的有几条路线ONNX Runtime 量化工具支持 INT8 量化对 4 bit 权重的支持在逐步完善。优点是生态成熟部署方便缺点是 4 bit 支持可能不如专用工具灵活。TensorRTNVIDIA 平台上的首选支持 INT8 和部分 4 bit 量化。需要模型先转成 ONNX再转 TensorRT engine。专用量化框架一些针对大模型的量化工具比如 GPTQ、AWQ 等算法的实现支持 4 bit 权重和 INT8 激活的组合。选哪条路线取决于目标硬件和部署环境。如果是 NVIDIA GPU 部署TensorRT 通常是首选如果是多平台部署ONNX Runtime 更通用。环境准备方面Python 3.8 以上、PyTorch 2.0 以上、CUDA 11.8 以上是比较稳妥的基线。量化工具通常对版本有要求装之前先看文档。4.2 权重 4 bit 量化的具体操作以 ONNX Runtime 为例权重 4 bit 量化的流程大致如下from onnxruntime.quantization import quantize_dynamic, QuantType # 先做 INT8 动态量化作为基线 quantize_dynamic( model_inputkimi_moe_fp16.onnx, model_outputkimi_moe_int8.onnx, weight_typeQuantType.QInt8 )如果要上 4 bit需要用到支持 4 bit 的量化配置。ONNX Runtime 的 4 bit 支持通过MatMul4BitsQuantizer等类实现from onnxruntime.quantization.matmul_4bits_quantizer import MatMul4BitsQuantizer quantizer MatMul4BitsQuantizer( modelkimi_moe_fp16.onnx, block_size128, # 分组大小 is_symmetricTrue, # 对称量化 accuracy_level4 # 精度等级 ) quantizer.process() quantizer.model.save_model_to_file(kimi_moe_w4.onnx)这里block_size128就是前面说的分组大小。is_symmetricTrue表示权重用对称量化。accuracy_level控制量化算法的精度值越高量化越慢但精度越好。对于 MoE 模型需要确认量化工具是否支持逐专家量化。如果不支持可能需要手动拆分模型对每个专家单独量化再合并。4.3 激活 INT8 量化的配置方法激活量化通常需要校准数据。ONNX Runtime 的静态量化流程from onnxruntime.quantization import quantize_static, CalibrationDataReader class KimiCalibrationReader(CalibrationDataReader): def __init__(self, calibration_data): self.data calibration_data self.index 0 def get_next(self): if self.index len(self.data): return None item self.data[self.index] self.index 1 return item reader KimiCalibrationReader(calibration_data) quantize_static( model_inputkimi_moe_w4.onnx, model_outputkimi_moe_w4a8.onnx, calibration_data_readerreader, quant_formatQuantFormat.QDQ, # 量化-反量化格式 activation_typeQuantType.QUInt8, # 激活用无符号 INT8 weight_typeQuantType.QInt8 )注意activation_typeQuantType.QUInt8这里激活用了无符号 INT8配合非对称量化。权重用有符号 INT8配合对称量化。这是比较常见的组合。校准数据的准备从实际业务数据里采样几百条覆盖不同输入长度和类型。每条数据要预处理成模型需要的格式比如 tokenize 后的 input_ids、attention_mask 等。4.4 量化后模型的精度验证量化完不能直接上线必须做精度验证。验证分两个层面数值层面用同一批输入分别跑 FP16 模型和 W4A8 模型比较输出的差异。常用的指标有指标含义可接受范围最大绝对误差输出中单个元素的最大偏差通常 0.1平均绝对误差所有元素偏差的平均值通常 0.01余弦相似度输出向量的方向一致性通常 0.99Top-1 一致率分类任务中最高分类别一致的比例通常 95%任务层面在具体任务上评测比如对话任务看回复质量代码任务看生成代码的正确率。数值指标好不代表任务表现好有些量化误差会被后续层放大。我一般会准备一个包含 100 到 200 条样本的评测集覆盖主要业务场景。量化前后各跑一遍人工对比或者用自动指标打分。如果任务指标下降超过 2%就要考虑调整量化策略。4.5 推理性能实测与调优精度达标后看性能。主要关注两个指标首 token 延迟和吞吐量。首 token 延迟受权重加载和首次计算影响大。4 bit 权重加载带宽需求低理论上首 token 延迟应该比 FP16 低不少。实测中如果延迟没有明显下降可能是反量化开销吃掉了收益或者权重加载没有走 4 bit 通路。吞吐量看的是单位时间能处理多少 token。INT8 MMAC 的吞吐量通常是 FP16 的两倍左右但实际提升取决于计算和访存的平衡。如果模型是访存瓶颈4 bit 权重的带宽优势会更明显如果是计算瓶颈INT8 的计算优势更关键。调优方向调整分组大小分组越小精度越高但反量化开销越大需要找平衡点。调整 batch sizebatch 增大能提高计算利用率但激活量化的动态范围统计可能变难。算子融合把反量化和矩阵乘法融合成一个算子减少中间结果的读写。KV Cache 量化如果 KV Cache 也压到 INT8显存占用和带宽需求都能进一步降低。5. 常见问题与排查技巧实录5.1 量化后模型输出乱码或重复这是最典型的问题通常有几个原因激活量化范围估计错误。如果校准集不能代表实际输入激活的 scale 算小了推理时激活值超出量化范围被裁剪信息丢失。排查方法是打印量化前后各层的激活分布看哪些层的裁剪比例高。解决方法是扩充校准集或者对敏感层改用动态量化。权重分组大小不合适。分组太大小权重被量化到零分组太小量化参数存储和计算开销大。排查方法是逐层对比量化前后的权重分布看哪些层的权重损失严重。解决方法是调小分组或者对敏感层单独用更小的分组。MoE 路由被量化影响。路由网络的输出如果量化误差大可能导致 token 被路由到错误的专家。排查方法是统计量化前后路由结果的一致率。如果一致率低路由网络可能需要保留更高精度。5.2 推理速度没有提升甚至变慢量化后速度没提升常见原因反量化开销过大。4 bit 权重每次计算前都要反量化如果反量化是逐元素做的开销可能超过计算本身。解决方法是把反量化融合进矩阵乘法算子或者预先把权重反量化成 INT8 缓存起来。硬件不支持 INT8 加速。有些老 GPU 的 INT8 吞吐量和 FP16 一样甚至更差。确认目标硬件是否支持 INT8 的 DP4A 或类似指令。如果不支持量化只能省显存不能提速。内存带宽不是瓶颈。如果模型本身计算量很大访存不是瓶颈4 bit 权重的带宽优势就体现不出来。这种情况下INT8 计算的优势更关键需要确认计算核心是否真的走了 INT8 通路。5.3 不同输入长度下精度波动大长输入和短输入的激活分布差异很大。短输入时激活值可能集中在某个范围长输入时累积效应导致激活值范围扩大。如果量化参数用短输入校准长输入就会溢出。解决方法校准集里包含各种长度的输入让量化参数覆盖长输入的分布。对长输入场景考虑用动态量化每次推理重新统计激活范围。如果长输入是主要场景校准集以长输入为主。5.4 常见问题速查表问题现象可能原因排查方法解决方向输出乱码激活量化范围错误打印各层激活裁剪比例扩充校准集或改动态量化输出重复权重分组过大对比量化前后权重分布调小分组大小速度无提升反量化开销大profile 反量化耗时融合反量化算子速度无提升硬件不支持 INT8查硬件指令集换硬件或接受仅省显存长输入精度差校准集长度单一分长度统计精度校准集覆盖多长度MoE 路由错误路由网络量化误差统计路由一致率路由网络保留高精度显存没降KV Cache 未量化查显存占用分布量化 KV Cache首 token 慢权重加载未走 4 bit查权重加载带宽确认 4 bit 加载通路5.5 几个踩过的坑坑一校准集用了训练数据。训练数据分布和推理数据分布往往不同用训练数据校准会导致量化参数偏向训练分布。一定要用推理场景的数据做校准。坑二忽略了 LayerNorm 和 Softmax 的量化。这两个操作的输入范围通常比较固定但输出范围可能波动大。如果把它们也量化了精度损失可能比矩阵乘法还严重。实际中这两类操作经常保留 FP16。坑三MoE 专家量化参数共用。不同专家的权重分布差异大共用量化参数会导致部分专家精度崩坏。必须逐专家校准。坑四量化后没做 warmup。有些推理引擎在首次推理时会做 JIT 编译或者缓存预热首次延迟不能代表稳定延迟。测性能前先跑几十次 warmup。坑五只看平均精度不看最差情况。平均精度达标不代表所有样本都达标。要关注精度最差的那部分样本看是否在可接受范围内。6. 量化方案的扩展与组合思路6.1 W4A8 与其他量化方案的对比方案权重精度激活精度显存节省计算加速精度损失适用场景FP1616 bit16 bit基准基准无精度优先W8A88 bit8 bit50%约 2x小通用推理W4A84 bit8 bit75%约 2x中显存受限W4A44 bit4 bit75%约 4x大极端受限W4A164 bit16 bit75%约 1x小显存受限但算力充足W4A8 的定位很清晰显存节省和计算加速兼顾精度损失可控。如果显存不是瓶颈W8A8 更稳妥如果显存极度受限且能接受精度损失W4A4 可以考虑。6.2 KV Cache 量化的配合使用KV Cache 在长上下文场景下占用显存很大。把 KV Cache 也量化到 INT8能进一步降低显存占用。KV Cache 量化的难点在于它是动态生成的每生成一个 token 就追加一个 KV 对量化参数需要动态更新。常见做法是对 KV Cache 用逐 token 或者逐块的动态量化每个新生成的 KV 对独立计算 scale。这样精度有保障但增加了量化计算开销。另一种做法是用滑动窗口统计历史 KV 的分布用历史统计值估计当前 scale减少计算开销。KV Cache 量化后注意 attention 计算的精度。attention score 是 query 和 key 的点积如果 key 被量化了score 的误差会影响 attention 权重分布。实测中KV Cache 量化到 INT8 通常精度损失很小但量化到 4 bit 就需要谨慎。6.3 混合精度量化的分层策略不是所有层都适合 W4A8。有些层对量化敏感需要保留更高精度。分层策略的思路是嵌入层通常保留 FP16因为嵌入层的量化误差会传播到所有后续层。路由网络保留 FP16 或 INT8避免路由错误。专家权重W4A8这是量化的主要收益来源。输出层保留 FP16 或 INT8避免最终输出精度损失。LayerNorm 和 Softmax保留 FP16。哪些层敏感可以通过逐层量化实验来确定。方法是每次只量化一层其他层保留 FP16看精度下降多少。下降多的层就是敏感层。6.4 量化感知训练的必要性与取舍如果离线量化后精度不达标量化感知训练QAT是最后的补救手段。QAT 在训练过程中模拟量化误差让权重适应量化后的表示。具体做法是在前向传播时插入伪量化节点反向传播时用直通估计器STE传递梯度。QAT 的代价是需要训练资源和时间。对于大模型全量 QAT 成本很高。常见的折中方案是只对部分层做 QAT或者用 LoRA 等参数高效微调方法做 QAT。我的经验是如果离线量化后任务指标下降在 2% 以内优先调量化参数和分组策略如果下降超过 5%再考虑 QAT。QAT 不是万能的如果量化位宽太低QAT 也救不回来。6.5 面向不同硬件的量化策略调整不同硬件对量化的支持差异很大。NVIDIA GPU 对 INT8 支持好4 bit 支持在逐步完善。某些专用推理芯片对 4 bit 有原生支持但工具链可能不成熟。CPU 上 INT8 推理有成熟库支持但 4 bit 支持有限。策略调整的思路GPU 部署优先 W4A8利用 INT8 MMAC 和 4 bit 权重加载。CPU 部署优先 W8A8INT8 在 CPU 上支持最成熟。专用芯片看芯片文档确认支持的量化位宽和算子。多平台部署用 ONNX 作为中间格式针对不同平台做不同的量化配置。量化不是一次性的工作而是一个需要根据硬件、模型、场景不断调整的过程。W4A8 在 Kimi 2.7 MoE 上的落地核心是把 4 bit 权重的存储优势和 INT8 激活的计算精度结合起来同时通过分组量化、逐专家校准、混合精度分层等手段把精度损失控制在可接受范围。实际做的时候先跑通 INT8 基线再逐步上 4 bit 权重每步都做精度验证比一步到位更稳妥。