量化基础:定点数与浮点数、均匀量化与非线性量化
量化,说白了就是把连续的数值映射到有限的离散集合上。在芯片里,我们没法像数学公式那样精确表达每一个实数,只能用有限的比特位去近似。这个近似的过程,就是量化。
我刚开始做芯片设计时,总觉得量化就是简单的四舍五入。后来在一个语音处理项目中,因为量化方式选错了,导致整个系统的信噪比差了将近 6dB。嗯,从那以后我再也不敢小看这个环节了。
定点数与浮点数
先聊聊数字在硬件里的两种基本表示方式:定点数和浮点数。
定点数,顾名思义,小数点的位置是固定的。比如我们用 8 位来表示一个数,约定高 4 位是整数部分,低 4 位是小数部分。那这个数的范围就是 0 到 15.9375,精度是 1/16。
定点数的核心特点:
- 硬件实现简单,只需要整数加法器和乘法器
- 动态范围有限,容易溢出或精度不足
- 适合资源受限、计算规律的应用场景
浮点数则灵活得多。它用科学计数法的方式表示数字:一部分存指数,一部分存尾数。IEEE 754 标准里,单精度浮点数用 1 位符号、8 位指数、23 位尾数。
浮点数的好处是动态范围大。同样的 32 位,定点数可能只能表示 -32768 到 32767,浮点数却能表示 ±10³⁸ 的范围。但代价呢?硬件复杂度翻倍,功耗和面积都上去了。
| 对比项 | 定点数 | 浮点数 |
|---|---|---|
| 硬件面积 | 小(约 1x) | 大(约 3-5x) |
| 功耗 | 低 | 高 |
| 动态范围 | 有限 | 大 |
| 精度分布 | 均匀 | 不均匀(靠近零更密) |
| 适用场景 | 推理、控制、信号处理 | 训练、科学计算 |
我的经验:在部署神经网络推理时,我习惯先用浮点模型跑通精度,再逐步转定点。别一上来就拍脑袋定 Q 格式,先看看数据的实际分布范围。我曾经在一个目标检测项目里,因为没分析激活值的分布,直接选了 Q8.8 格式,结果精度掉了 3 个点,后来改成 Q6.10 才救回来。
均匀量化与非线性量化
量化方式分两大类:均匀量化和非线性量化。区别在于量化步长是否固定。
均匀量化,也叫线性量化。整个数值范围内,每个量化间隔都一样大。比如 0 到 1 的范围,用 8 位量化,步长就是 1/256。
均匀量化的好处是简单、计算快。在硬件里,均匀量化就是一个缩放加取整的操作。但问题也很明显:如果数据分布不均匀,比如大部分值集中在 0 附近,那均匀量化就会浪费很多比特位在那些很少出现的数值上。
// 均匀量化示例:将浮点值映射到 8 位整数
// 范围 [-1.0, 1.0],步长 = 2/256 ≈ 0.0078
float x = 0.345f;
int q = (int)round(x / 0.0078f); // 量化
float x_hat = q * 0.0078f; // 反量化
非线性量化则不同。它的步长不是固定的,而是根据数值大小动态调整。常见的非线性量化方式有对数量化、μ-law 量化和 A-law 量化。
为什么需要非线性量化?你想想看,在语音信号里,小信号出现的概率远大于大信号。如果均匀量化,小信号的量化误差相对值就很大,听起来就是噪声。非线性量化在小信号区域用更小的步长,大信号区域用更大的步长,这样整体信噪比就提升了。
避坑指南:我曾经在一个音频编解码器项目里,直接用了均匀量化,结果在静音段听到了明显的底噪。后来换成 μ-law 量化,同样的 8 位,信噪比提升了 12dB。非线性量化不是万能的,但在数据分布极度不均匀的场景下,它确实能省下不少比特。
量化误差分析
量化必然带来误差。这个误差通常用信噪比(SNR)来衡量。对于均匀量化,每增加 1 位,SNR 大约提升 6.02dB。
但要注意,这个公式的前提是输入信号均匀分布。如果信号分布不均匀,实际 SNR 会低于理论值。这就是为什么在神经网络量化中,我们经常需要先统计激活值的分布,再决定量化参数。
| 量化位数 | 均匀量化 SNR(理论) | 实际场景 SNR(语音) |
|---|---|---|
| 8 位 | 49.9 dB | 35-40 dB |
| 12 位 | 74.0 dB | 55-65 dB |
| 16 位 | 98.1 dB | 75-85 dB |
关键结论:量化误差不是均匀分布的。在信号幅度小的区域,相对误差更大。这就是为什么在低比特量化时,我们需要格外关注小信号的保真度。
量化方式的选择策略
在实际项目中,怎么选量化方式?我一般按这个思路来:
- 先看数据分布:收集一批代表性数据,画出直方图。如果数据近似均匀分布,均匀量化就够了。
- 再看硬件约束:如果面积和功耗是硬指标,定点数加均匀量化是最稳妥的选择。
- 最后看精度要求:如果精度要求高,但比特位有限,非线性量化可能是唯一出路。
举个例子,在神经网络量化中,权重和激活值的分布通常近似拉普拉斯分布或高斯分布。这时候用均匀量化,在均值附近精度够用,但在尾部区域就会浪费比特。所以现在很多芯片都支持非均匀量化,比如用查找表实现的对数量化。
实际项目中的量化技巧
最后分享几个我在项目中积累的小技巧:
- 先粗后细:先用低精度快速验证算法可行性,再逐步提高精度。别一开始就追求 32 位浮点。
- 混合精度:不同层、不同张量可以用不同的量化精度。比如第一层用 8 位,后面几层用 4 位。
- 校准数据集:量化参数(缩放因子、零点)一定要用有代表性的数据来校准。我见过有人随便拿几张图就做量化,结果部署后精度惨不忍睹。
- 仿真验证:在 RTL 仿真阶段就要加入量化模型,别等到流片回来才发现问题。
我的习惯:每次做量化方案时,我都会先写一个 Python 脚本,把浮点模型和量化模型的输出逐层对比。哪一层误差大了,就针对那一层调整量化参数。这样比整体调参高效得多。
量化不是简单的砍位宽,而是一个系统工程。选对了量化方式,芯片面积能省 30%,功耗能降 40%,精度损失却不到 1%。这就是我们做芯片优化的意义所在。