一、量化入门:为什么需要量化?量化的数学原理与核心思想

1.1 一个真实的故事:我为什么开始研究量化

几年前,我接手了一个项目——把BERT模型部署到手机端。模型跑一次推理要2秒,内存占用1.2GB。用户反馈说:「打开App,手机烫得能煎鸡蛋。」

我当时试了各种方法:剪枝、蒸馏、知识迁移……效果都不理想。直到我尝试了量化——把32位浮点数变成8位整数。你猜怎么着?模型体积直接缩小了4倍,推理速度提升了3倍,精度只掉了0.3%。

嗯,从那以后,量化就成了我工具箱里的「常驻嘉宾」。

1.2 为什么需要量化?三个核心痛点

说白了,大模型部署面临三个「拦路虎」:

  • 内存瓶颈:一个70B参数的模型,用FP32存储需要280GB显存。就算用A100(80GB),也得4张卡才能放下。
  • 带宽限制:模型推理时,数据在内存和计算单元之间来回搬运。带宽不够,计算单元就在「等数据」——GPU利用率可能不到30%。
  • 功耗问题:移动端、边缘设备对功耗极其敏感。FP32的矩阵乘法,功耗是INT8的4-6倍。

核心结论:量化不是「锦上添花」,而是「雪中送炭」。没有量化,很多大模型根本跑不到终端设备上。

1.3 量化的数学原理:从浮点到整数

量化的本质是什么?一句话:用更少的比特数表示数值

我们来看最经典的对称量化公式:

量化:q = round(r / s)
反量化:r ≈ q × s

其中:
r —— 原始浮点值(FP32)
q —— 量化后的整数值(INT8)
s —— 缩放因子(scale),s = (r_max - r_min) / (q_max - q_min)

举个例子。假设原始数据范围是[-1.0, 1.0],要量化到INT8(范围[-128, 127]):

s = (1.0 - (-1.0)) / (127 - (-128)) = 2.0 / 255 ≈ 0.00784

原始值 0.5 → 量化值 round(0.5 / 0.00784) = round(63.78) = 64
反量化 64 × 0.00784 ≈ 0.5018  # 误差约0.0018

你看,0.5变成了0.5018,误差只有0.36%。这就是量化的代价——精度损失。

我的经验:量化误差不是均匀分布的。数值越小,相对误差越大。比如0.01量化后可能变成0.0078,误差22%。所以,小数值区域是精度损失的「重灾区」

1.4 核心思想:用「近似」换「效率」

量化的核心思想,我总结为四个字:以近似换效率

你想想看,FP32有约2^32种取值,INT8只有256种。用256个值去近似40亿个值,必然有损失。但关键是——这个损失是否在可接受范围内

我在项目中遇到过一件事:一个视觉模型量化后,在ImageNet上精度只掉了0.1%,但部署到某个特定场景(夜间低光照)时,精度掉了5%。为什么?因为量化校准集没有覆盖低光照场景,导致量化参数(scale)不匹配。

避坑指南:量化不是「一键搞定」的。我曾经因为校准集选得不好,模型上线后出了大问题。后来我养成了一个习惯——校准集必须覆盖所有实际部署场景

1.5 量化类型:对称 vs 非对称

量化有两种主流方案:

类型 公式 适用场景 优点 缺点
对称量化 q = round(r / s) 权重(通常对称分布) 计算简单,硬件友好 浪费表示范围(如果数据不对称)
非对称量化 q = round((r - z) / s) 激活值(通常非对称分布) 充分利用表示范围 多一个零点参数,计算稍复杂

非对称量化多了一个「零点偏移」z:

q = round((r - z) / s)
z = q_min - round(r_min / s)

为什么要加零点?因为ReLU后的激活值全是非负数,用对称量化会浪费一半的表示范围(负数部分全浪费了)。非对称量化通过零点偏移,把INT8的256个值「对准」到数据的实际范围上。

1.6 知识体系总览

下面这张图,是我梳理的量化入门知识体系:

量化入门知识体系 为什么需要量化? 内存瓶颈 带宽限制 功耗问题 数学原理 q = round(r / s) 缩放因子 s 零点偏移 z 核心思想 以近似换效率 精度 vs 速度 校准集选择 量化类型 对称量化(权重) 非对称量化(激活值) 量化粒度:per-tensor / per-channel 量化精度 FP32 → INT8(4倍压缩) FP32 → INT4(8倍压缩) 混合精度量化 核心目标:在可接受的精度损失下,最大化推理效率 量化 = 用更少的比特数,近似表示原始数值

1.7 量化粒度:粗粒度 vs 细粒度

量化还有一个重要维度——粒度。说白了,就是「多少个参数共享同一个scale」。

  • Per-tensor量化:整个张量(比如一个权重矩阵)用一个scale。实现简单,但精度损失大。
  • Per-channel量化:每个通道(比如卷积的每个输出通道)用一个scale。精度更好,但计算稍复杂。
  • Per-group量化:把通道分成若干组,每组一个scale。折中方案。

我的建议:对于大模型(比如LLaMA),我通常用per-channel量化权重,per-tensor量化激活值。这样在精度和效率之间取得了不错的平衡。

1.8 量化误差的来源

量化误差主要来自两个方面:

  1. 截断误差:超出量化范围的值被「截断」到边界值。比如INT8范围[-128, 127],原始值200会被截断成127。
  2. 舍入误差:量化时round操作带来的精度损失。比如0.5量化成64,反量化后是0.5018。

我曾经踩过一个坑:某个模型量化后,输出全是NaN。排查了半天,发现是某个激活值特别大(1000+),量化时被截断后,反量化回来变成了127×scale,导致后续计算爆炸。后来我加了一个clip操作,问题就解决了。

避坑指南:量化前一定要做数值分布分析。看看你的数据范围、分布形状、有没有异常值。我曾经因为没做这一步,浪费了整整两天调试时间。

1.9 小结

量化入门,说白了就三件事:

  • 为什么量化:内存、带宽、功耗——三个绕不开的瓶颈
  • 怎么量化:用scale和zero_point把浮点数映射到整数
  • 量化代价:精度损失不可避免,但可以通过粒度、校准集等手段控制

下一章,我们会深入讲解量化参数(scale和zero_point)的计算方法,以及如何选择最优的量化方案。嗯,到时候我会分享一些我在实际项目中用到的「独门技巧」。


专注资料整理