尽管量化的基本目的不变,即降低模型参数和激活值的数值精度以提升计算效率,但要将这些技术有效应用于大型语言模型(LLMs),需要根据其独特的规模和结构来调整核心原则。量化的基本思想在此处呈现,并侧重于拥有数十亿参数的Transformer模型。量化的核心是将高精度浮点值(如FP32或FP16)映射到低精度表示形式,通常是整数(如INT8或INT4)或专用低位浮点格式。这种精度降低是效率提升的原因:模型尺寸减小可降低内存带宽需求,并在针对低精度算术优化的硬件上实现更快的计算。映射方案:对称与非对称将浮点值 $x$ 映射到其量化对应值 $q$ 的过程需要定义一个映射函数。两种主要方案常见:对称量化: 该方案将浮点值对称地映射到零点附近。量化公式通常为: $$ q = \text{clip}(\text{round}(x / s), Q_{\text{最小值}}, Q_{\text{最大值}}) $$ 其中,$s$ 是缩放因子,根据张量中观测到的绝对值范围计算得出(例如,$s = \max(|x|) / Q_{\text{最大值}}$,其中 $Q_{\text{最大值}}$ 是可表示的最大整数值)。clip 函数确保结果保持在目标整数类型的有效范围内(例如,INT8为[-128, 127])。对称量化一个重要特点是浮点值0.0精确映射到整数0。这对于涉及填充或稀疏性的操作有利。非对称量化: 该方案通过引入零点(或偏移量) $z$ 来处理不以零为中心的数值范围: $$ q = \text{clip}(\text{round}(x / s) + z, Q_{\text{最小值}}, Q_{\text{最大值}}) $$ 缩放因子 $s$ 基于数值的完整范围计算($s = (\max(x) - \min(x)) / (Q_{\text{最大值}} - Q_{\text{最小值}})$),零点 $z$ 表示与浮点0.0对应的整数值($z = -\text{round}(\min(x) / s) + Q_{\text{最小值}}$)。当数据分布倾斜或偏移时,这使得非对称量化能够更有效地利用完整的整数范围。digraph G { rankdir=LR; node [shape=record, style=filled, fillcolor="#e9ecef"]; subgraph cluster_0 { label = "对称量化 (INT8)"; fillcolor="#f8f9fa"; style=filled; node [fillcolor="#a5d8ff"]; fp_sym [label="{<min>-R | 0.0 | <max>+R}", shape=none, margin=0]; int_sym [label="{<min>-128 | 0 | <max>+127}", shape=none, margin=0]; fp_sym:max -> int_sym:max [label=" / s", color="#1c7ed6"]; fp_sym:min -> int_sym:min [label=" / s", color="#1c7ed6"]; fp_sym:c -> int_sym:c [label=" 映射到", style=dotted, color="#495057"]; } subgraph cluster_1 { label = "非对称量化 (UINT8)"; fillcolor="#f8f9fa"; style=filled; node [fillcolor="#b2f2bb"]; fp_asym [label="{<min>最小值 | 0.0 | <max>最大值}", shape=none, margin=0]; int_asym [label="{<min>0 | z | <max>255}", shape=none, margin=0]; fp_asym:max -> int_asym:max [label=" / s + z", color="#37b24d"]; fp_asym:min -> int_asym:min [label=" / s + z", color="#37b24d"]; fp_asym:c -> int_asym:c [label=" 映射到", style=dotted, color="#495057"]; } invisible [style=invis, width=0]; fp_sym -> invisible [style=invis]; invisible -> fp_asym [style=invis]; }对称与非对称量化映射之间的区别。对称量化将0.0映射到整数0,而非对称量化则使用零点 $z$ 处理偏移范围。对于LLMs,权重分布通常合理地以零为中心,使对称量化成为常见选择。然而,激活值,尤其是在ReLU或GeLU函数之后,可以是严格非负的或具有高度非对称分布。在这种情况下,非对称量化通过更有效地使用可用整数范围,可能提供更好的表示保真度,尽管它引入了零点参数 $z$,这会增加计算的微小复杂性。粒度:逐张量与逐通道(或逐轴)另一个基本选择是应用缩放因子 $s$(如果非对称,还有零点 $z$)的粒度:逐张量量化: 对整个张量(例如,特定线性层中的所有权重)使用单个 $s$ 和 $z$。这是最简单的方法,最大限度地减少了存储量化参数的开销。然而,如果张量的不同部分具有明显不同的值范围,单一缩放因子可能导致低范围值的精度不佳或高范围值的截断。逐通道(或逐轴/逐组)量化: 为张量的特定维度计算独立的 $s$ 和 $z$ 值。对于线性层的权重矩阵(形状为[output_features, input_features]),逐通道量化通常意味着为每个输出通道(即每一行)计算唯一的 $s$(和 $z$)。这使得量化范围能更贴近每个通道或参数组内部的分布。{ "data": [ { "y": [0.1, 0.15, -0.05, 0.08, 0.12], "name": "通道1权重", "type": "bar", "marker": { "color": "#74c0fc" } }, { "y": [2.5, -1.8, 3.0, 2.1, -2.8], "name": "通道2权重", "type": "bar", "marker": { "color": "#f783ac" } } ], "layout": { "title": { "text": "通道间权重分布差异" }, "xaxis": { "title": "权重索引" }, "yaxis": { "title": "数值" }, "barmode": "group", "height": 350, "margin": { "l": 50, "r": 20, "t": 50, "b": 40 }, "legend": { "yanchor": "top", "y": 0.99, "xanchor": "left", "x": 0.01 } } }线性层中两个通道权重值范围明显不同的例子。逐张量量化难以同时精确表示这两个范围。在LLMs中,线性层占据了绝大多数参数。这些层中的权重通常在不同的输出通道(神经元)间表现出突出的差异。因此,逐通道量化常常是量化LLM权重的优选方法,因为相较于相同位宽下的逐张量量化,它通常能更好地保持精度。逐张量量化仍可考虑用于激活值,因为在那里,逐通道参数的开销相对于计算可能更大,或者分布更均匀。逐组量化(将缩放应用到通道内权重块)等变体也作为一种折衷方案存在。校准的作用无论是使用对称还是非对称方案,逐张量还是逐通道粒度,确定最优的量化参数($s$ 和 $z$)都非常重要。这个过程被称为校准,它涉及分析你打算量化的浮点值的统计分布。对于训练后量化(PTQ),这通常需要在一个小型、有代表性的数据集(校准数据集)上运行推理,以观测权重以及更重要的激活值的典型范围。校准数据的选择以及从观测范围(例如,最小值/最大值、百分位数范围)推导 $s$ 和 $z$ 的方法会明显影响最终量化模型的精度。对大型模型的适用性为何重温这些基础知识对LLMs如此重要?规模与敏感性: 拥有数十亿参数,量化选择的影响被放大。每个参数的微小精度提升都可能导致整体性能的明显差异。相反,糟糕的选择可能导致无法接受的质量下降。LLMs对量化误差可能出乎意料地敏感,特别是在注意力机制等特定模块中。内存带宽: 通过量化减小模型尺寸直接转化为推理期间更低的内存带宽使用,这通常是LLMs的主要瓶颈。相较于权重数据本身,逐张量和逐通道元数据存储的差异变得可以忽略不计。硬件计算核: 效率的提升很大程度上取决于目标硬件(CPU、GPU、专用加速器)上优化过的低精度计算核的可用性。不同的量化方案(对称与非对称)和粒度可能与可用的硬件指令有不同的映射方式。理解对称/非对称映射与逐张量/逐通道粒度之间的这些基本权衡,为评估和实施专门针对LLMs的更高级PTQ和QAT技术提供了必要的背景,这些技术将在后续章节中介绍。这些高级方法通常会改进缩放因子的计算方式,或选择性地应用不同的粒度,以优化精度与性能的平衡。