全栈开发知识库

4.模型压缩

在对模型的性能影响不大的前提下,尽可能减小模型的占用空间,减少模型参数量,让模型变得简单,提升运行速度。

分类:

  • 模型量化: Quantization
  • 模型蒸馏: Knowledge distillation
  • 模型剪枝: Pruning
  • 低秩分解: Low-rank factorization

端侧部署的三板斧: 量化、剪枝、知识蒸馏。

类比Android开发中的APK瘦身三件套: 压缩、混淆、资源优化。

模型量化(Quantization)

简单说就是把模型从高清降到标清。

在 深度神经网络模型 中,权重存储为 32 位浮点数,即fp32。量化通过减少每个权重所需的位数来压缩原始网络。例如,权重可以量化为 fp16 位、int8 位甚至 int4 位。通过减少使用的位数,可以显著减小 DNN 的大小,且加速推理速度

量化就是降低精度: - FP32 → FP16:体积减半,精度几乎无损 - FP16 → INT8:体积再减半,精度略有损失 - INT8 → INT4:再减半,需要 QAT 才能保证精度

所以量化就是用更少的信息位(比如从32位降到8位),来近似的表示原来的浮点数,从而达到减小模型体积、加快推理速度的目的。

这个过程本质上是一种信息压缩,必然会伴随着精度损失。

我们的目标就是在精度损失可控的前提下,尽可能减小模型体积。

量化方法

  • 对称量化(Symmetric Quantization)

    • 原理:将浮点数范围关于0对称地映射到整数范围。

    • 步骤:

      • 找到一批浮点数中绝对值最大的值,记为 α(alpha)。
      • 映射范围:[-α, α] → [-127, 127](以INT8为例,范围是-128到127,但对称量化通常用-127到127)。
      • 计算缩放因子(scale factor)
    • 特点:零点始终位0,FP32的0量化后还是0
    • 计算简单:不需要计算零点偏移
    • 缺点:如果数据分布不对称(比如大部分是正数),会浪费正数表达空间

非对称量化(Asymmetric Quantization)

原理:不要求关于0对称,而是将数据的实际范围 [β, α] 映射到整数范围。

步骤: - 找到数据的最小值 β 和最大值 α。 - 映射范围:[β, α] → [-128, 127](INT8完整范围)。 - 计算缩放因子

特点: - 零点不一定为0:会根据数据分布偏移。 - 能更好地利用整数表达空间:当数据分布不对称时,精度损失更小。 - 计算稍复杂:需要计算零点。

范围映射与裁剪(Clipping)

问题:数据中可能存在离群值(outliers)——个别值远大于其他值。如果按照完整范围映射,大多数值会被压缩到很小的整数区间,失去区分度。

解决方案:裁剪(Clipping)——人为设定一个较小的动态范围,超出范围的值被强制映射到边界值。

例子: - 数据:[0.1, 0.2, 0.3, 0.4, 100.0] - 如果不裁剪:范围[0.1, 100.0],缩放因子很小,前四个值都会变成0,完全无法区分。 - 如果裁剪到[0, 0.5]:100.0被映射到127,前四个值被映射到不同的整数,保留了区分度。 - 代价:离群值的量化误差变大,但非离群值的误差变小。总体效果通常更好。

校准

校准:选择裁剪范围的过程。目标是找到一个既能包含尽可能多的值,又能最小化量化误差的范围。

5.1 权重的校准

权重是模型训练好的参数,在推理前是已知的、静态的。校准方法包括: 手动选择百分位数:比如选择95%分位数作为裁剪边界。 最小化均方误差(MSE):优化原始权重与量化后权重之间的平方误差。 最小化KL散度:最小化原始分布与量化后分布之间的差异。 5.2 激活值的校准

激活值是模型推理过程中产生的中间结果,随输入变化而变化,事先未知。

挑战:必须在推理时才能知道激活值的分布,因此量化激活值更复杂。

训练后量化(Post-Training Quantization, PTQ)

PTQ:模型训练完成后,对参数进行量化。这是最常用的量化方式,因为流程简单,不需要重新训练。

动态量化(Dynamic Quantization)

过程: - 模型推理时,每通过一个隐藏层,收集该层的激活值。 - 根据这些激活值,实时计算该层的缩放因子 s 和零点 z。 - 用这些 s 和 z 对该层的激活值进行量化。 特点: - 精度较高:每个层都有自己的量化参数,适应性强。 - 速度较慢:因为推理时需要额外计算 s 和 z。

静态量化(Static Quantization)

过程: - 在推理之前,用一个校准数据集(calibration dataset)输入模型,收集所有层的激活值分布。 - 根据收集到的分布,预先计算好每一层的 s 和 z。 - 实际推理时,直接使用这些预先计算好的 s 和 z 进行量化,不再重新计算。 特点: - 速度较快:推理时不需要额外计算。 - 精度较低:因为校准数据集可能无法覆盖所有情况。

4比特量化(The Realm of 4-bit Quantization)

将量化精度降到8位以下是非常困难的,因为每减少一个比特,量化误差就会显著增加。但有一些聪明的方法可以实现4位甚至更低的量化。

GPTQ

GPTQ​ 是一种著名的4位量化方法,主要在GPU上运行。

核心思想: 逐层量化:一次处理一层,独立进行。 使用逆Hessian矩阵:计算模型损失函数的二阶导数(逆Hessian),它告诉我们每个权重对模型输出的敏感程度。逆Hessian值越小,权重越重要。 量化一个权重后,将量化误差重新分配给该行中的其他权重。因为权重之间通常是相互关联的,通过这种方式可以补偿量化带来的损失。 通俗理解:就像调整一个精密仪器——拧松一个螺丝(量化一个权重)会导致误差,但可以通过微调旁边的螺丝(调整其他权重)来补偿,使整体精度保持不变。

GGUF

GGUF​ 是一种支持CPU和GPU混合部署的量化格式。当GPU显存不足时,可以将部分层卸载到CPU上运行。

量化方法: 将给定层的权重分成多个“超级块”(super blocks),每个超级块又包含多个“子块”(sub blocks)。 对每个子块,用absmax量化(类似于对称量化)进行量化,计算子块的缩放因子 s_sub。 超级块也有自己的缩放因子 s_super,用于量化子块的缩放因子。 分层量化:超级块的缩放因子用更高精度(如6位),子块的缩放因子用较低精度(如4位),权重本身用最低精度(如2位)。

量化感知训练(Quantization Aware Training, QAT)

QAT​ 与 PTQ 不同,它是在训练过程中就让模型“感知”到量化的存在。

核心思想:伪量化(Fake Quantization)

在训练的前向传播中,插入一个“伪量化”节点,模拟真实量化带来的精度损失: - 量化:将FP32权重或激活值用 round(s·x + z) 转换成INT8整数。 - 反量化:立刻将INT8整数用 (q - z)/s 转回FP32。 - 结果:得到的虽然是FP32格式,但已经“劣化”了,模拟了量化后的效果。 为什么这样做?​ 反向传播时,梯度会“看到”量化误差。优化器在更新权重时,会考虑到量化误差,引导模型学习那些对量化不敏感的权重。

比喻:寻找“宽阔最优解”

  • 狭窄最优解:像一个尖锐的峡谷,谷底损失很低,但要求权重必须非常精确(如3.14159)。稍微偏离一点,损失就急剧上升。PTQ可能找到这个点,但量化后权重变成3.1,模型性能大幅下降。
  • 宽阔最优解:像一个平坦的盆地,盆底损失可能不如峡谷低,但周围一大片区域的损失都很低。权重在3.0到3.2之间,模型性能都很好。QAT倾向于找到这样的区域,即使量化后权重变成3.1,性能依然稳定。

  • 优点:精度损失最小,量化效果最好。

  • 缺点:需要修改训练流程,计算成本更高。

PTQ(训练后量化) vs QAT(量化感知训练):
- PTQ: 训练完后直接量化,速度快但进度损失大。先全精度微调 → 再量化到 INT4 → 精度崩塌。 - QAT:训练中植入量化,速度慢但精度保持好。 在训练时插入"伪量化层",让模型提前适应 INT4 的精度截断。就像让运动员在高海拔(低氧=低精度)训练,到平原比赛(端侧部署)反而发挥更好。

端侧部署的实际案例:Qwen3-0.6B 经过 QAT + INT4 量化后,导出为 .pte 文件约 472MB,在 Android 旗舰机上推理速度可达 40 tokens/s——完全离线运行。

QAT、DQ、PTQ三个都是量化的具体实现,也就是他们的核心目的一样:

在对模型效果影响不大的情况下,通过降低参数的精度也就是数据类型,来达到减小模型体积和提高运行速度。

量化是一种技术,通过使用低精度数据类型(如 8 位整数 (int8))而不是通常的 32 位浮点 (float32))来表示权重和激活,从而降低运行推理的计算和内存成本。减少位数意味着生成的模型需要更少的内存存储,并且使用整数运算可以更快地执行矩阵乘法等运算。它还允许在嵌入式设备或者边缘设备上运行模型,这些设备有时仅支持整数数据类型。将float32量化为int8会实现性能提升:

  • 模型尺寸缩小 4 倍;
  • 内存带宽减少 2-4 倍;
  • 推理速度提高了 2-4 倍(确切的加速取决于硬件、网络和模型等)。 量化背后的基本思想非常简单:从权重和激活的高精度表示(通常是常规的 32 位浮点)到较低精度的数据类型。

模型蒸馏

用一个大的"教师模型"指导小的"学生模型"学习。比如用 Qwen-72B 教 Qwen-0.6B,让小模型在远小于大模型的体量下尽量逼近其能力。

在知识蒸馏中,在大型数据集上训练大型复杂模型。当这个大模型可以泛化并进行推理时,使其知识转移到较小的网络。较大的模型称为教师模型,较小的网络称为学生网络。

  • 教师模型:是一个大模型,参数量大,预测精确,但是运行速度慢,模型体积大
  • 学生模型:是一个小模型,参数量少,预测相对精确,但是运行速度快,模型体积小

  • 硬标签:模型预测结果的概率值,非0即1。学生模型只能学到有限的内容,只能学到一个最终的答案

  • 软标签:模型预测结果的概率值,取值区间在[0,1]之间。学生模型能够学到预测结果的概率分布
  • 中间层:模型的思考过程

KL散度介绍: 1- 作用:衡量两个预测概率分布之间的差异性 2- 规律:该值越小越好。最小为0,那么说明学生模型和教师模型的结果完全一样,蒸馏效果最好 3- 扩展:硬标签中 KL散度值=交叉熵,因为信息熵带入预测分布概率进去H(P)结果是0

记住: KL离散度就是我们用一个分布去模仿另一个分布,结果差多少的一个衡量方式。

模型剪枝(Pruning): 删掉不重要的神经元

对模型的卷积层/注意力头做灵敏度分析,剪去冗余通道(比如剪去 30% 的通道),再用小学习率微调补回精度。类比:删掉 App 里没人用的功能模块。

剪枝是一种减少深度神经网络参数数量的强大技术。在 深度神经网络中,许多参数是冗余的,因为它们在训练期间贡献不大。因此,在训练之后,可以从网络中删除这些参数,而对准确性的影响很小。

作用:主要是为了去除神经网络中不重要或者冗余的神经元、连接,甚至整个网络层 特点:对模型体积的减小和模型运行速度的提升,微乎其微 使用:剪枝后,一般会和其他的模型压缩手段配合使用

剪枝概念¶ 模型剪枝(Pruning)是一种模型压缩技术,旨在通过移除神经网络中冗余或不重要的部分(如权重、神经元或整个层)来减小模型大小,同时尽量保持模型的性能。剪枝的核心思想是:神经网络通常存在大量冗余参数,许多参数对最终输出的贡献微乎其微,可以安全移除而不显著影响模型性能。 剪枝与其他优化技术的融合 剪枝+量化:先剪枝再量化可获得更好的压缩效果

剪枝+知识蒸馏:先使用教师模型指导剪枝后学生模型的训练

低秩分解

低秩因式分解通过采用矩阵分解来识别深度神经网络的冗余参数。当需要减小模型大小时,低秩因式分解技术通过将大型矩阵分解为较小的矩阵来提供帮助。

Image

本页由 Markdown 自动渲染 · 共 628 篇笔记