办公用品网站建设可行性分析,新手开公司怎么找项目,网站开发原型模板,深圳网站建设哪个公司好目录 前言1. 模型压缩架构和流程介绍2. 低比特量化原理2.1 量化基础介绍2.2 量化方法2.3 量化算法原理2.4 讨论 3. 感知量化训练QAT原理3.1 QAT原理3.2 量化算子插入3.3 QAT训练流程3.4 QAT衍生研究3.5 讨论 4. 训练后量化PTQ4.1 动态PTQ4.2 静态PTQ4.3 KL散度实现静态PTQ4.4 量… 目录 前言1. 模型压缩架构和流程介绍2. 低比特量化原理2.1 量化基础介绍2.2 量化方法2.3 量化算法原理2.4 讨论 3. 感知量化训练QAT原理3.1 QAT原理3.2 量化算子插入3.3 QAT训练流程3.4 QAT衍生研究3.5 讨论 4. 训练后量化PTQ4.1 动态PTQ4.2 静态PTQ4.3 KL散度实现静态PTQ4.4 量化推理 5. 模型剪枝核心原理5.1 量化与剪枝的区别5.2 剪枝算法分类结构化、非结构化5.3 剪枝流程5.4 L1-norm剪枝算法5.5 讨论 6. 知识蒸馏原理6.1 What、Why and How6.1 知识蒸馏背景6.2 蒸馏的知识方式 7. 知识蒸馏算法解读7.1 Offline蒸馏7.2 Online蒸馏7.3 Self蒸馏7.4 Hinton经典蒸馏算法解读 总结参考 前言 这篇文章主要分享下博主最近在 B 站上偶然间看到的一个视频该视频对模型压缩相关知识进行了简单的介绍包括量化、剪枝、蒸馏、二值化。比较适合博主这种对各种概念模糊的初学者因此记录下方便下次查看博主也就把原作者的话复述了一遍大家可以自行查看原视频。 视频链接【推理引擎】模型压缩 文档链接https://github.com/chenzomi12/DeepLearningSystem/tree/main/043INF_Slim 1. 模型压缩架构和流程介绍 这个系列主要是和大家分享推理引擎或者推理系统里面的模型压缩也可以叫模型小型化或者模型轻量化。 我们主要是和大家分享模型压缩的 4 件套
低比特量化二值化网络模型剪枝模型蒸馏
下面来看下在整个推理引擎架构图里面模型压缩所处位置 首先最上面有个 API 的层接着有个模型转换它会把从不同的 AI 框架训练出来的网络模型转换成为推理引擎的自己的 IR或者自己的 Schema那转换成为自己的 IR 之后呢就会经过模型压缩这个功能那可能会做一些量化、蒸馏、剪枝、二值化可能会把模型压缩的四件套同时用起来那这个时候就叫做多维混合压缩算法。实现完模型的压缩之后就真正的去把网络模型给到 Runtime 还有 Kenrel 去执行在不同的硬件上面这就是整体的流程。
那我们最主要的关注点就是对模型进行压缩把模型变得越小越好减少网络模型的大小第二个就是加快整个推理的速度使得在推理引擎里面跑得越快越好最后就是要求保持相同的精度即在精度损失较小的前提下去减少网络模型的大小和推理速度。
下面我们来看看整体的推理流程如下图所示 我们会把很多不同 AI 框架训练出来的网络模型转换成为推理的模型接着经过一个模型压缩模块后输出执行通过模型压缩如果能使得模型又小速度又快精度还能无损那这是最好的。
OK以上就是关于模型压缩架构和流程的简单介绍下面我们会来介绍下具体的压缩方法。
2. 低比特量化原理 这小节内容主要分享量化基础、量化三种方法以及量化算法的原理 2.1 量化基础介绍
模型量化是一种将浮点计算转成低比特定点计算的技术可以有效的降低模型计算强度、参数大小和内存消耗但往往带来巨大的精度损失。尤其是在极低比特4bit、二值网络1bit、甚至将梯度进行量化时带来的精度挑战更大。 如上图所示数值在计算机里面有多种表示方法如 FP32、FP16、INT32、INT16 以及 INT8 等其中 FP32 是我们一般用来去做模型训练的一个精度我们随便打开一个 ONNX 模型可以看到里面存储的数据的类型是 float32 即 FP32 很多时候在模型训练时我们会开启混合精度即 –amp 参数的指定。那所谓的混合精度一般是把 FP32 和 FP16 混合到一起去训练FP16 占用的内存位置或地址空间相比于 FP32 确实少了很多。一般我们所说的模型量化除了把 FP32 的精度降成 FP16更多的是降到 INT16、INT8 甚至 INT4 更低比特的一种表示把 FP32 的 32 位比特转换成为更低比特的方式或者技术就叫做模型量化
接下来我们看下神经网络有什么特点 上图展示了不同的深度学习模型在计算复杂性和分类精度的关系可以看到基本上模型的效果越好其计算复杂度也越高相对较大的神经网络模型一般有以下几个特点
1. 数据参数量大2. 计算量大3. 内存占用大4. 模型精度高
但是当我们要把模型部署起来特别是在一些资源有限的移动端和边缘嵌入式设备我们就不得不考虑模型的计算复杂度和参数量了我们当然希望我们的模型又小精度又高。
特别是目前的大语言模型动不动就几百亿的参数量它们更加需要量化压缩这些技术来减少模型的参数量提高模型的推理速度。因此我们还是有必要去了解模型压缩相关技术的。
那我们先不去谈模型量化到底做了什么我们先来看看模型量化的一些优点主要有以下几点
1. 保持精度量化会损失精度因为这相当于给网络引入了噪声但是神经网络一般对噪声是不太敏感的只要控制好量化的程度对高级任务精度影响可以做到更小。博主之前的文章有测试过 YOLOv5 模型的量化FP32 到 FP16 基本无损FP32 到 INT8 会掉 3~4 个点左右这取决于你的量化方式QAT 量化相比于 PTQ 量化掉点要好些2. 加速计算传统的卷积操作都是使用 FP32 浮点数进行的计算低比特的位数减少计算性能也更高INT8 相对比 FP32 的加速比可达到 3 倍甚至更高。博主之前的文章有测试过 YOLOv5 模型的量化FP16 比 FP32 快 2.4 倍INT8 比 FP32 快 3 倍3. 节省内存与 FP32 类型相比FP16、INT8、INT4 低精度类型所占用空间更小对应存储空间和传输时间都可以大幅下降4. 节能和减少芯片面积每个数值如果使用了更少的位数表示则做运算时需要搬运的数据量就少了减少了访存开销节能同时所需的乘法器数目也减少了减少芯片面积
下面我们来看下模型量化的五个特点
1. 参数压缩2. 提升速度3. 降低内存4. 功耗降低5. 提升芯片面积
也就是对上面的优点进行了一个简单的总结。
接着我们来看下量化技术落地的三大挑战
1. 精度挑战
量化方式现在的量化方法大部分是线性量化但线性量化对数据分布的描述不精确低比特从 16bits → 4bits 比特数越低精度损失越大任务分类、检测、分割中任务越复杂精度损失越大大小模型越小精度损失越大
2. 硬件支持程度
不同硬件支持的低比特指令不相同比如 Jetson nano 就不支持 INT8不同硬件提供不同的低比特指令计算方式不同PF16、HF32不同硬件体系结构 Kernel 优化方式不同
3. 软件算法是否能加速
混合比特量化需要进行量化和反量化如果硬件指令不支持低比特但我还是想要做量化这时需要插入 Cast 算子但 Cast 算子将影响 kernel 执行性能降低运行时内存占用与降低模型参数量的差异模型参数量小压缩比高不代表执行内存占用少
OK以上就是关于量化基础知识的介绍下面我们来看量化方法
2.2 量化方法
量化方法现在来看一般分为三大种
量化训练Quant Aware Training,QAT 量化训练让模型感知量化运算对模型精度带来的影响通过 finetune 训练降低量化误差具体实现可以参考YOLOv5-QAT量化部署 动态离线量化Post Training Quantization Dynamic,PTQ Dynamic 动态离线量化仅将模型中特定算子的权重从 FP32 类型映射成 INT8/16 类型 静态离线量化Post Training Quantization Static,PTQ Static 静态离线量化使用少量无标签校准数据采用 KL 散度等方法计算量化比例因子具体实现可以参考YOLOv5-PTQ量化部署
下面我们来看一个图更好的去理解这三种具体的算法 首先就是感知量化 QAT我们会先准备一个训练好的网络模型然后对它进行一个转换具体是插入一些伪量化的算子也就是我们常说的 Q/DQ 节点从而得到一个新的网络模型接着对新的网络模型进行 Finetuning 微调得到真正量化后的模型最后交给部署端。
静态离线量化 PTQ-static首先准备一个训练好的网络模型和一堆训练的数据然后通过训练数据对模型进行校准校准的方法可能会用 KL 散度或者其它的方式
动态离线量化 PTQ-dynamic准备一个网络模型然后对其进行转换最后得到转换后或者量化后的网络模型使用较少
现在我们来看一下这三种方法有什么区别对它们做一个简单的比较如下表所示
量化方式功能经典适用场景使用条件易用性精度损失预期收益量化训练(QAT)通过 Finetune 训练将模型量化误差降到最小对量化敏感的场景、模型例如目标检测、分割、OCR 等有大量带标签的数据好极小减少存续空间4x降低计算内存静态离线量化(PTQ Static)通过少量校准数据得到量化模型对量化不敏感的场景例如图像分类任务有少量无标签数据较好较少减少存续空间4x降低计算内存动态离线量化(PTQ Dynamic)仅量化模型的可学习权重模型体积大、访存开销大的模型例如 BERT 模型无一般一般减少存续空间2/4x降低计算内存
QAT 量化训练的精度损失确实比较少但它的缺点是需要大量带标签的数据进行 FinetunePTQ Static 静态离线量化方式的好处是精度损失也是比较小的但不能说没有因为它缺少了 Finetune 训练的步骤它只需要有一些少量无标签的数据进行校准PTQ Dynamic 动态离线量化方法的精度损失一般来说不可控但它没有任何使用的约束你想咋用就咋用。
OK以上就是关于量化方法的介绍下面我们正式进入到量化原理的分析
2.3 量化算法原理
模型量化桥接了定点和浮点建立了一种有效的数据映射关系主要是线性映射使得以较小的精度损失代价获得了较好的收益。 上面这个图表示了从定点到浮点的映射先看左图上面是指浮点数权重参数的数值它有最小值和最大值当然也有 0 值现在我们希望把这一堆数据映射到一个具体的范围 -127-127 之间其实就是 INT8 所表示的范围。
当然还有另外一种映射方式就是截断的方式看右图我们会去设置一个最小值和最大值把最小值和最大值范围内的参数去映射到 -127-127 之间而不在这个范围内的数据直接把它丢弃掉这个就是简单的量化方法。
量化的类型其实可以分为对称量化和非对称量化所谓的对称很简单就是以 0 作为中心轴量化范围从 -127-127就是两边的对称可以用 INT 来表示。另一种非对称量化可能就没有中心轴了以 0 作为开始以 255 作为结束这种表示方式直接可以使用 UINT 去进行一个表示 下面我们真正的来到了量化的原理。
要弄懂模型量化的原理就是要弄懂定点和浮点之间的数据映射关系浮点和定点数据的转换公式如下 Q R S Z R ( Q − Z ) ∗ S \begin{aligned} Q \frac{R}{S}Z \\ R (Q-Z)*S \end{aligned} QRSRZ(Q−Z)∗S R R R 表示输入的浮点数据FP32、FP16 都行 Q Q Q 表示量化之后的定点数据INT 类型的数据 Z Z Z 表示零点Zero Point的数值偏移值用于决定做对称量化还是非对称量化 S S S 表示缩放因子Scale的数值
第一条公式叫做量化第二条公式叫做反量化。
这里面最重要的就是找到缩放因子 S S S 和零点 Z Z Z有了它们就能够求得 Q Q Q。那如何求取 S S S 和 Z Z Z 呢其实有很多种方法这里列举其中比较简单一种方式MinMax如下 S R max − R min Q max − Q min Z Q max − R max S \begin{aligned} S \frac{R_{\text{max}}-R_{\text{min}}}{Q_{\text{max}}-Q_{\text{min}}} \\ Z Q_{\text{max}} - \frac{R_{\text{max}}}{S} \end{aligned} SZQmax−QminRmax−RminQmax−SRmax
Rmax 表示输入浮点数据中的最大值Rmin 表示输入浮点数据中的最小值Qmax 表示最大的定点值127/255Qmin 表示最小的定点值-128/0
下面我们来看下 MinMax 方式的实际使用公式推导
1. 量化算法原始浮点精度数据与量化后 INT8 数据的转换如下 f l o a t s c a l e × ( u i n t o f f s e t ) float scale\times(uintoffset) floatscale×(uintoffset) f l o a t float float 表示原始模型中的 float32 精度的数据 s c a l e scale scale 表示缩放尺度 u i n t uint uint 表示量化后模型中的 int8 精度的数据 o f f s e t offset offset 表示偏移量 Z Z Z这是反量化公式
2. 确定后通过原始 float32 高精度数据计算得到 uint8 数据的转换即如下公式所示 u i n t 8 r o u n d ( f l o a t / s c a l e ) − o f f s e t uint8 round(float/scale)-offset uint8round(float/scale)−offset r o u n d round round 表示四舍五入操作这是量化公式
3. 若待量化数据的取值范围伪 [ X m i n , X m a x ] [X_{min},X_{max}] [Xmin,Xmax]则 s c a l e scale scale 的计算公式如下 s c a l e ( x max − x min / Q max − Q min ) scale (x_{\text{max}}-x_{\text{min}} / Q_{\text{max}}-Q_{\text{min}}) scale(xmax−xmin/Qmax−Qmin) 4. o f f s e t offset offset 的计算方式如下 o f f s e t Q min − r o u n d ( x min / s c a l e ) offset Q_\text{min} - round(x_{\text{min}}/scale) offsetQmin−round(xmin/scale) 其它求取的 S S S 和 Z Z Z 方式可以参考TensorRT量化第三课动态范围的常用计算方法
OK以上就是关于量化算法原理的知识在下节中我们将会讨论感知量化训练 QAT 的相关知识。
2.4 讨论 讨论1在量化基础介绍小节中我们有介绍模型量化的最终目的是得到更小性能更好的小模型那我们为什么不直接训练一个小模型呢在小模型上面调参让它性能更好呢 以下是一些理由和讨论(from ChatGPT)
1. 大模型的训练容量大型模型在训练时具有更多的容量可以捕捉到更多的特征和模式。而小模型由于参数限制可能无法捕捉到这些模式。通过先训练一个大模型然后进行量化或压缩可以尝试保留这些重要的模式。
2. 技术挑战直接训练小模型确实存在一些技术挑战例如训练不稳定、容易过拟合等。而大模型则更容易训练并且可以利用现有的预训练技术。
3. 通用性 vs. 特定性大模型通常被设计为通用模型可以在多种任务上工作。一旦这些模型被训练好可以通过量化和压缩来适应特定的任务或应用而不需要为每个新任务从头开始训练。 讨论2为什么我们不直接训练低精度例如 INT8、INT4的模型呢 直接在低精度例如 INT8、INT4下训练模型是一个有趣的想法并且确实有研究者在这方面进行了探索。但是直接在低精度下训练模型面临着一些挑战和问题(from ChatGPT)
1. 梯度消失和爆炸使用低精度表示时数值范围和精度都会受到限制。这可能导致在训练过程中遇到梯度消失或爆炸的问题这些问题在高精度下可能不会出现。
2. 数值稳定性低精度可能导致数值不稳定性特别是在某些需要精确计算的操作例如 Batch Normalization中。
3. 收敛速度和最终性能由于表示的限制直接在低精度下训练的模型可能需要更多的时间才能收敛且最终的模型性能可能不如在高精度下训练的模型。
4. 硬件和软件支持直接在低精度下训练可能需要特定的硬件和软件支持这可能并不是所有平台都具备的。
5. 训练技巧许多现代的深度学习训练技巧和方法例如优化器、正则化方法等都是在高精度下开发和优化的。在低精度下这些方法可能需要调整或重新设计。
总的来说虽然直接在低精度下训练模型面临一些挑战但它仍然是一个有前景的研究方向。与此同时高精度训练后再进行量化仍然是一种更为常见和实用的方法。
3. 感知量化训练QAT原理 这个小节内容主要分享感知量化训练 QAT 原理、伪量化算子插入、QAT 训练流程以及 QAT 训练最新研究 3.1 QAT原理
感知量化训练Aware Quantization Training模型中插入伪量化节点 fake quant 来模拟量化引入的误差。端测推理的时候折叠 fake quant 节点中的属性到 tensor 中在端测推理的时候折叠 fake quant 节点中的属性到 tensor 中在端测推理的过程中直接使用 tensor 中带有的量化属性参数。
简单来说就是在一个正常的网络模型中去插入一些伪量化的算子或者节点这个节点叫做 Fake Quant之所以称为 Fake 是因为它不是真正的量化而是用来模拟量化的时候引入的一些误差。而在真正端侧推理的时候需要把这些 Fake Quant 去进行一个折叠最后做推理。
那折叠是什么呢
在感知量化训练 QAT 中折叠是指在推理过程中将伪量化节点中的量化属性参数scale 和 zero-point直接应用到输入的张量上而不再使用伪量化节点来模拟量化引入的误差。这个过程实际上是将量化操作与反量化操作进行逆操作将原始的浮点数张量恢复为量化后的整数张量以便在推理中高效地进行计算。 在上面的计算图中输入中插入了一个伪量化的算子接着还需要对权重也插入一个伪量化的算子完成卷积计算之后会给 BN 层进行一个学习学习完之后进入了 ReLU在 BN 层后面也会插入一个伪量化的节点在里面像这种在一个正常的计算图里面去插入各种伪量化节点的量化方式就叫做 QAT 量化。
刚刚大量的去提到一些伪量化的节点 Fake Quant那 Fake Quant 的节点有什么用呢以下是它的两个比较大的作用
1. 找到输入数据的分布即找到 min 和 max 值2. 模拟量化到低比特操作的时候的精度损失把该损失作用到网络模型中传递给损失函数让优化器去在训练过程中对该损失值进行优化
我们来看下伪量化节点的正向传播具体是如何计算的。
为了求得网络模型 tensor 数据精确的 Min 和 Max 值因此在模型训练的时候插入伪量化节点来模拟引入的误差得到数据的分布。对于每一个算子量化参数通过下面的方式得到 clamp ( x , x min , x max ) : min ( max ( x , x min ) , x max ) \text{clamp}(x,x_\text{min},x_\text{max}): \text{min}(\text{max}(x,x_\text{min}),x_\text{max}) clamp(x,xmin,xmax):min(max(x,xmin),xmax) 有了最小值和最大值之后就可以去求量化的 scale通过 scale 就可以把输入数据直接量化成 INT8。正向传播就会做这个工作除了记录最大值和最小值它还要做一个量化模拟的操作如下所示 假设之前的数据是一条平滑的数据类似于一条线性的直线经过伪量化算子进行模拟的时候就变成了阶梯型状它把大部分的数据都直接消掉了从 FP32 的数据变成了 INT8 的数据那这个就是伪量化算子的正向传播。
有正向是不是应该有反向那现在来看看反向传播时伪量化算子具体怎么实现。
按照前面正向传播的公式如果对其求导数会导致权重为 0权重为 0 就没有办法去学习了因此反向传播的时候相当于一个直接估算器 δ o u t δ i n , I ( x ∈ S ) ∈ S : x : x min ≤ x ≤ x max \delta_{out}\delta_{in},I_{(x\in S)}\in S:x:x_{\min}\leq x\leq x_{\max} δoutδin,I(x∈S)∈S:x:xmin≤x≤xmax 值得注意的是输入数据 x x x 必须要在量化范围之内如果不在的话则需要把它进行截断如下图所示 了解完伪量化算子前向和反向传播之后还有一个很重要的工作就是更新 Min 和 Max因为每一个 epoch 都会有不同的数据输入有不同的 Min 和 Max更新的方式有点类似于 BN 算子去更新 beta 和 gamma 的这种方式它主要是通过 running 和 moving 去完成更新的。
3.2 量化算子插入
前面我们讲了 Fake Quant 伪量化算子怎么去实现正向传播怎么进行伪量化学习反向传播怎么进行截断那我们应该在哪些地方插入 Fake Quant 伪量化节点呢
一般我们会在密集计算算子、激活算子、网络输入输出等地方插入伪量化节点下面我们来看一个实际操作的图 左边是包含 Conv、BN 和 ReLU 三个简单算子的计算图右边是插入伪量化算子的计算图一般来说我们会对输入、Conv 的 weights 还有激活后面插入伪量化算子这个是一般的插入方式。
值得注意的是如果你研究感知量化算法你可以提出很多不同的插入方式也可以自己造一个伪量化算子上面这个是最原始的一种方式。
OK我们简单的讲了感知量化训练的一般通用性的算法还讲了伪量化算子是怎么实现的包括正向反向还讲了伪量化算子是怎么插入到计算图里面的接下来我们来讲下 QAT 训练的流程
3.3 QAT训练流程
QAT 的工作流程图如下所示 步骤如下
1. 预训练模型开始时你需要一个预训练的模型。这个模型通常是通过常规方法在大量数据上训练得到的。
2. Fuse 模块在这一步相关的层或模块被合并以便于后续的量化过程。
3. 插入 stubs 和 observers为了量化模型需要在关键位置插入 stubs 和 observers即伪量化算子。这些工具可以帮助在训练过程中捕捉和模拟量化的效果。
4. 训练/微调在此阶段使用标准的训练数据对模型进行训练或微调。但与常规训练不同的是此时模型已经被修改可以模拟量化操作的效果。
5. 量化在训练完成后模型将经过量化处理将 32 位的浮点数转化为较低位宽的整数例如 8 位。
6. QAT 模型最后您将得到一个量化感知训练后的模型通常这个模型在大小和推理速度上都有所优化同时尽量保持与原始模型相近的准确度。
值得注意的是最后得到的 QAT 网络模型没有办法去执行推理它要经过推理系统的一个转换模块然后去掉一些冗余的伪量化的算子才能够正常的推理。
3.4 QAT衍生研究
最后我们来简单聊一聊 QAT 的衍生研究
在 Straight Through Estimation Derivative Approximation 这篇文章博主未找到该篇文章中作者提出了一种新的伪量化算子如下所示 其中的正向传播和我们之前讲解的一样但反向传播就不再是一个简单的分段了
另外还有一些科研类的创新文章会对计算图或者对量化的流程进行改进比如 Quantization and Deployment of Deep Neural Networks on Microcontrollers 这篇文章 最后量化的方式和种类还有不同的层次感兴趣的可以看看 Per-channel Quantization Level Allocation for Quantizing Convolutional Neural Networks 这篇文章 3.5 讨论 讨论1伪量化节点有参数吗如果有其参数有哪些属性呢 伪量化节点的参数通常包括以下属性(from chatGPT)
1. 量化比特数bitwidth表示量化操作的比特数例如 8 位整数量化表示。通常8 位整数量化用于表示权重和激活值。这个属性决定了量化的精度。
2. 量化范围quantization range表示量化操作的范围通常是一个最小值和一个最大值用于确定如何将浮点数映射到整数表示。这个范围是根据训练数据和模型的统计信息动态确定的。
3. 缩放因子scale factor通常是量化范围的倒数用于将浮点数映射到整数表示。缩放因子等于量化范围的宽度除以量化比特数的最大整数值。
4. 零点zero point表示整数表示中的零值对应的浮点数值。它通常等于量化范围的最小值。
这些属性使得伪量化节点能够模拟量化操作的效果从而允许模型在训练期间适应量化的影响。在推理期间你可以选择将伪量化节点的属性折叠到张量中这意味着不再使用伪量化节点来模拟量化而是直接使用张量中包含的量化属性参数来执行量化操作。 上图中的模型已经插入了 Q/DQ 节点我们可以看到节点中包含着缩放因子属性 scale其类型为 float32 以及零点属性 zero-point其类型为 int8。 讨论2为什么说伪量化操作在反向传播时求导数的权重为 0 呢 考虑公式 δ o u t δ i n , I ( x ∈ S ) ∈ S : x : x min ≤ x ≤ x max \delta_{out}\delta_{in},I_{(x\in S)}\in S:x:x_{\min}\leq x\leq x_{\max} δoutδin,I(x∈S)∈S:x:xmin≤x≤xmax 这是一个分段函数。对于在范围 [ x min , x max ] [x_\text{min},x_\text{max}] [xmin,xmax] 内的 x x x其导数为 1因为这部分是线性的。但是对于不在这个范围内的 x x x函数是常数其导数为 0。这意味着当 x x x 不在量化范围内时梯度就是 0因此权重更新也就是 0。
但是在实际的伪量化的反向传播中为了确保模型能够正常训练我们不直接使用这个 0 梯度。相反对于在范围内的输入我们传递原始的梯度即 1而对于超出范围的输入我们则截断它使其保持在量化范围内。
所以当说伪量化节点的反向传播对其求导数的权重为 0 时指的是在量化范围外的那部分输入。 讨论3如何平滑计算伪量化阶段的 Min 和 Max像 BN 层计算一般会有一个平滑的计算过程在具体算子或kernel 实现的时候就会有一个 moving mean moving variance 去进行一个平滑它和 BN 层平滑类似吗 在 BN 层中移动均值和移动方差的计算使用了指数移动平均Exponential Moving Average, EMA。具体地给定一个新的均值 μ \mu μ 和方差 σ 2 \sigma^2 σ2它们可以按以下方式更新 m o v i n g _ m e a n β × m o v i n g _ m e a n ( 1 − β ) × μ m o v i n g _ v a r β × m o v i n g _ v a r ( 1 − β ) × σ 2 moving\_mean \beta\times moving\_mean ( 1- \beta) \times \mu \\ moving\_var \beta\times moving\_var ( 1- \beta) \times \sigma^2 moving_meanβ×moving_mean(1−β)×μmoving_varβ×moving_var(1−β)×σ2 其中 β \beta β 是一个介于 0 和 1 之间的系数通常接近 1例如 0.9 或 0.99
对于伪量化我们可以采用类似的方法来平滑地计算 Min 和 Max 值。假设 x m i n _ n e w x_{min\_new} xmin_new 是新的最小值 x m a x _ n e w x_{max\_new} xmax_new 是新的最大值那么移动最小值和移动最大值可以按照如下方式更新 m o v i n g _ m i n β × m o v i n g _ m i n ( 1 − β ) × x m i n _ n e w m o v i n g _ m a x β × m o v i n g _ m a x ( 1 − β ) × x m a x _ n e w moving\_min \beta\times moving\_min ( 1- \beta) \times x_{min\_new} \\ moving\_max \beta\times moving\_max ( 1- \beta) \times x_{max\_new} moving_minβ×moving_min(1−β)×xmin_newmoving_maxβ×moving_max(1−β)×xmax_new 这种方法可以确保在整个训练过程中 Min 和 Max 值的计算是稳定的从而避免因小批次内的数据变化而产生的过大波动。这与 BN 层中移动均值和移动方差的平滑方法是类似的。 讨论4如果要对 Batch Normal 进行折叠那么计算公式或者 kernel 会变成什么样会不会有新的变化呢 QAT 感知量化训练的过程中 BN 层的计算确实需要对它进行一个特殊插入如下图所示 左边是没有融合之前的右边是融合之后的算子具体计算公式的变化如下 4. 训练后量化PTQ 之前我们讲解了感知量化训练 QAT这节我们来看下另外一种量化方式-训练后量化 PTQ 4.1 动态PTQ
PTQ 量化有静态和动态之分我们先看一个比较简单的就是动态离线量化PTQ Dynamic
它主要有以下特性
仅将模型中特定算子的权重从 FP32 类型映射成 INT8/16 类型主要可以减小模型大小对特定加载权重费时的模型可以起到一定加速效果但是对于不同输入值其缩放因子是动态计算因此动态量化是几种量化方法中性能最差的权重量化成 INT16 类型模型精度不受影响模型大小为原始的 1/2权重量化成 INT8 类型模型精度会受到影响模型大小为原始的 1/4
算法流程如下 首先是拿到一个已经训练好的网络模型接着将这个网络模型的 FP32 的权重直接转换成 INT8 这种量化模型最后将转换成 INT8 权重的量化模型对外输出即可
值得注意的是动态离线量化这种方式性能比较差大家做简单了解即可。
4.2 静态PTQ
接着我们来看静态离线量化PTQ Static像华为昇腾里面的推理引擎 ACL 和英伟达的 TensorRT 里面的量化模块都是采用的静态离线量化方式。
现在大部分的推理引擎或推理框架都会采用离线量化的这种方式作为里面集成的一个模块因此大家需要对它了解。
它具有以下特性
静态离线量化也称为校正量化或者数据集量化。使用少量无标签校准数据核心是计算量化比例因子。使用静态量化后的模型进行预测在此过程中量化模型的缩放因子会根据输入数据的分布进行调整 u i n t 8 r o u n d ( f l o a t / s c a l e ) − o f f s e t uint8 round(float/scale)-offset uint8round(float/scale)−offset
静态离线量化的目标是求取量化比例因子主要通过对称量化、非对称量化方式来求而找最大值或者阈值的方法又有 MinMax、KLD、ADMM、EQ 等方法
下面看一下 PTQ Static 算法的主要流程 步骤如下
预训练模型开始时你需要一个预训练的模型。这个模型通常是通过常规方法在大量数据上训练得到的。Fuse 模块在这一步相关的层或模块被合并以便于后续的量化过程。插入 stubs 和 observers为了量化模型需要在关键位置插入 stubs 和 observers即伪量化算子。这些工具可以帮助在训练过程中捕捉和模拟量化的效果。校准数据准备用于校准的数据。这个数据不需要带标签只要从真实的数据场景里面获取即可通常是从训练数据中选取一个子集校准使用校准数据进行模型校准。校准的目的是确定量化的范围和参数这通常是通过分析模型在校准数据上的行为来完成的。量化利用校准算法获得的量化参数将模型的权重和激活从浮点数转换为定点数或整数PTQ模型最后我们得到了一个量化后的模型这个模型通常有较小的体积并可以更快地进行推理
在静态离线量化里里面为了更好的去得到 scale 或者去计算数据分布通常会使用到校准算法而常见的校准算法校准 KL 散度校准法用 KL 散度去校准数据集下面我们一起来了解下。
4.3 KL散度实现静态PTQ
KL 散度校准法的原理如下
KL 散度校准法也叫做相对熵其中 P P P 表示真实分布 Q Q Q 表示非真实分布或 P P P 的近似分布其计算公式如下 D K L ( P f ∥ Q q ) ∑ i 1 N P ( i ) ∗ l o g 2 P f ( i ) Q q ( i ) D_{KL}(P_f\parallel Q_q)\sum_{i1}^NP(i)*log_2\frac{P_f(i)}{Q_q(i)} DKL(Pf∥Qq)i1∑NP(i)∗log2Qq(i)Pf(i)
相对熵用来衡量真实分布与非真实分布的差异大小。目的是改变量化域实则就是改变真实的分布并使得修改后的真实分布在量化后与量化前相对熵越小越好。主要是去对比两个分布之间的差异其中 P P P 是真实的分布 Q Q Q 是预测的分布KL 散度就去对比真实的分布跟预测的分布之间的一个近似值或者它们的差异的大小我们希望它们的差异越小越好也就是量化后的分布和量化前的分布越接近越好
KL 散度校准法的流程如下:
选取 validation 数据集中一部分具有代表的数据作为校准数据集 Calibration对于校准数据进行 FP32 的推理对于每一层 收集 activation 的分布直方图使用不同的 threshold 来生成一定数量的量化好的分布计算量化好的分布与 FP32 分布的 KL divergence并选取使 KL 最小的 threshold 作为 saturation 的阈值
通俗的理解算法收集激活 Act 直方图并生成一组具有不同阈值的 8 位表示法选择具有最小 KL 散度的表示此时的 KL 散度在参考分布FP32 激活和量化分布INT8 激活之间。
这里有几个点需要注意以下首先就是需要准备一些小批量的数据也就是刚才所说的 Calibration Dataset 校准数据集这里面一般选取 500 到 1000 张图片左右就够了不用太大当然也不能太少。博主之前有做过相关的校准图片数量对模型性能影响的实现具体可参考YOLOv5-PTQ量化部署
所以大家不用浪费太多的时间去调多少张不同的数据集更多的可以去调一调通过什么阈值什么参数去产生不同的数据的分布。
具体的算法流程如下 Run FP32 inference on Calibration Dataset.For each Layer: collect histograms of activations.generate many quantized distributions with different saturation thresholds.pick threshold which minimizes KL divergence(ref_divergence, quant_divergence). 需要准备小批量数据500~1000 张图片校准用的数据集使用校准数据集在 FP32 精度的网络下推理并收集激活值的直方图不断调整阈值并计算相对熵得到最优解
下面这段是 NVIDIA TensorRT 的一个关于 KL 散度或者静态量化后训练的伪代码这里就不一一介绍了感兴趣的看官可以看下TensorRT量化第三课动态范围的常用计算方法 4.4 量化推理
我们在之前讲了很多种的不同的量化方式但是实际上真正的端侧量化推理部署应该是怎样的呢
端侧量化推理的结构方式主要有三种分别是下图aFP32 输入 FP32 输出、图bFP32 输入 INT8 输出、图cINT8 输入 INT32 输出 第一种就是输入是 FP32接着通过量化成 INT8 的权重然后通过一个 Conv2d这个卷据算子对应的参数也是 INT8通过卷积计算出来后的数据是 INT32因为如果输出还是 INT8 的话会造成一个溢出最后经过反量化回 FP32 再给到下一层的输入。
第二种方式的输入是 FP32 输出是 INT8FP32 的数据进去通过量化成 INT8然后经过卷积变成 INT32最后会做一个重量化把 INT32 的数据量化成 INT8如果下一个算子也是卷积的话就可以直接串起来了所以引申处第三种方式。
第三种方式的输入是 INT8卷积之后输出是 INT32然后再做一个重量化变成 INT8 再输出。
所以在整个计算图整个网络模型的量化过程当中会遇到三种不同的方式。INT8 卷积里面涉及到上面三种不同的模式因为不同的卷积通过不同的方式进行拼接。使用 INT8 量化进行 inference 时由于数据是实时的因此数据需要在线量化量化的流程如下图所示。数据量化涉及 Quantize、Dequantize 和 Requantize 等 3 种操作。 值得注意的是量化 Quant 和反量化 DeQuant 这两个算子一定会有而重量化 ReQuant 会不会存在取决于网络模型的具体的形态。在端侧量化推理部署的时候会多 Quantize、Dequantize 和 Requantize 这几个不同的算子这是跟没有量化之前最大的区别。
我们先来看看 Quantize 量化 这个算子该算子会将 float32 数据量化为 int8。在离线转换工具转换的时候就要根据之前提到的不论是 QAT 还是 PTQ 找到 x max x_{\text{max}} xmax x min x_{\text{min}} xmin Q max Q_{\text{max}} Qmax Q min Q_{\text{min}} Qmin 也就是数据的分布接着离线转换工具就会根据它们计算出 scale 和 offset在真正端侧推理部署也就是 runtime 去运行的时候就会根据 scale 和 offset 把 FP32 的数据转成 INT8具体的量化公式如下 s c a l e ( x max − x min ) / ( Q max − Q min ) o f f s e t Q min − r o u n d ( x min / s c a l e ) u i n t 8 r o u n d ( f l o a t / s c a l e ) − o f f s e t f l o a t s c a l e × ( u i n t o f f s e t ) \begin{aligned} scale (x_{\text{max}}-x_{\text{min}})/(Q_{\text{max}}-Q_{\text{min}}) \\ offset Q_{\text{min}} - round(x_{\text{min}}/scale) \\ uint8 round(float/scale)-offset \\ float scale \times(uintoffset) \end{aligned} scaleoffsetuint8float(xmax−xmin)/(Qmax−Qmin)Qmin−round(xmin/scale)round(float/scale)−offsetscale×(uintoffset) 接着我们来看看第二个算子 Dequantize 反量化INT8 相乘、加之后的结果用 INT32 格式存储如果下一个 Operation 需要 float32 格式数据作为输入则可以通过 Dequantize 反量化操作将 INT32 数据反量化为 float32。Dequantize 反量化推导过程如下 y x ⋅ w x s c a l e ⋅ ( x i n t x o f f s e t ) ⋅ w s c a l e ⋅ ( w i n t w o f f s e t ) ( x s c a l e ∗ w s c a l e ) ⋅ ( x i n t x o f f s e t ) ⋅ ( w i n t w o f f s e t ) ( x s c a l e ⋅ w s c a l e ) ⋅ ( x i n t ⋅ w i n t x i n t x o f f s e t w i n t x o f f s e t w o f f s e t x o f f s e t ) ( x s c a l e ⋅ w s c a l e ) ⋅ ( I N T 3 2 r e s u l t x i n t x o f f s e t w i n t x o f f s e t w o f f s e t x o f f s e t ) ≈ ( x s c a l e ⋅ w s c a l e ) ⋅ I N T 3 2 r e s u l t \begin{aligned} yx\cdot w \\ x_{scale}\cdot(x_{int}x_{offset})\cdot w_{scale}\cdot(w_{int}w_{offset}) \\ (x_{scale}*w_{scale})\cdot(x_{int}x_{offset})\cdot(w_{int}w_{offset}) \\ (x_{scale}\cdot w_{scale})\cdot(x_{int}\cdot w_{int}x_{int}x_{offset}w_{int}x_{offset}w_{offset}x_{offset}) \\ (x_{scale}\cdot w_{scale})\cdot(INT32_{result}x_{int}x_{offset}w_{int}x_{offset}w_{offset}x_{offset}) \\ \approx(x_{scale}\cdot w_{scale})\cdot INT32_{result} \end{aligned} yx⋅wxscale⋅(xintxoffset)⋅wscale⋅(wintwoffset)(xscale∗wscale)⋅(xintxoffset)⋅(wintwoffset)(xscale⋅wscale)⋅(xint⋅wintxintxoffsetwintxoffsetwoffsetxoffset)(xscale⋅wscale)⋅(INT32resultxintxoffsetwintxoffsetwoffsetxoffset)≈(xscale⋅wscale)⋅INT32result 最后一个就是 Requantize 重量化 算子INT8 相乘、加之后的结果用 INT32 格式存储如果下一层需要 INT8 格式数据作为输入则通过 Requantize 重量化操作将 INT32 数据重量化为 INT8。重量化推导过程如下 y x ⋅ w x s c a l e ⋅ ( x i n t x o f f s e t ) ⋅ w s c a l e ⋅ ( w i n t w o f f s e t ) ( x s c a l e ⋅ w s c a l e ) ⋅ ( x i n t x o f f s e t ) ⋅ ( w i n t w o f f s e t ) ( x s c a l e ⋅ w s c a l e ) ∗ I N T 3 2 r e s u l t \begin{aligned} yx\cdot w \\ x_{scale}\cdot(x_{int}x_{offset})\cdot w_{scale}\cdot(w_{int}w_{offset}) \\ (x_{scale}\cdot w_{scale})\cdot(x_{int}x_{offset})\cdot(w_{int}w_{offset}) \\ (x_{scale}\cdot w_{scale})*INT32_{result} \end{aligned} yx⋅wxscale⋅(xintxoffset)⋅wscale⋅(wintwoffset)(xscale⋅wscale)⋅(xintxoffset)⋅(wintwoffset)(xscale⋅wscale)∗INT32result 其中 y y y 为下一个节点的输入即 y x n e x t y x_{next} yxnext y i n t y s c a l e ∗ ( y i n t y o f f s e t ) y_{int} y_{scale} * (y_{int}y_{offset}) yintyscale∗(yintyoffset) 则有 x n e x t i n t ( x s c a l e ⋅ w s c a l e / x n e x t s c a l e ) ⋅ I N T 3 2 r e s u l t − x n e x t o f f s e t x_{next\ int} (x_{scale} \cdot w_{scale} / x_{next \ scale})\cdot INT32_{result}-x_{next\ offset} xnext int(xscale⋅wscale/xnext scale)⋅INT32result−xnext offset 因此重量化不仅需要本层输入 input 和权重的 scale更加需要下一个 op 算子的输入的 scale 和 offset所以在运行量化推理的过程当中确实需要到全图的信息也就是整个计算图的信息。
5. 模型剪枝核心原理 这小节内容主要分享剪枝原理、剪枝流程以及 L1-norm 剪枝算法的具体实现 模型压缩提出了三部分的优化
1. 减少内存密集的访问量2. 提高获取模型参数的时间3. 加速模型推理时间
不管是剪枝还是量化都属于模型压缩的一部分而它们所做的工作都是围绕上面三个点进行优化的。那量化和剪枝到底有什么区别呢我们下面来看下。
5.1 量化与剪枝的区别
模型量化是值通过减少权重表示或激活所需的比特数来压缩模型
模型剪枝研究模型权重中的冗余并尝试删除/修剪冗余和非关键的权重 To prune, or not to prune: exploring the efficacy of pruning for model compression 这篇论文大家可以作为剪枝的白皮书去看这篇论文有以下几个观点
1. 在内存占用相同情况下大稀疏模型比小密集模型实现了更高的精度2. 经过剪枝之后稀疏模型要优于同体积非稀疏模型说明网络模型中很多参数是不一定需要的3. 资源有限的情况下剪枝是比较有效的模型压缩策略4. 优化点还可以往硬件稀疏矩阵储存方向发展
5.2 剪枝算法分类结构化、非结构化
剪枝算法主要有两大类别
Unstructured Pruning非结构化剪枝随机对独立的权重或者神经元连接进行剪枝 优点剪枝算法简单模型压缩比高缺点精度不可控剪枝后权重矩阵稀疏没有专用硬件难以实现压缩和加速的效果很少使用 Structured Pruning结构化剪枝对 filter / channel / layer 进行剪枝 优点大部分算法在 channel 或者 layer 上进行剪枝保留原始卷积结构不需要专用硬件来实现缺点剪枝算法相对复杂
具体可参考剪枝与重参第一课修剪结构和标准 5.3 剪枝流程
对模型进行剪枝有三种常见的做法
1. 训练一个模型 → 对模型进行剪枝 → 对剪枝后模型进行微调2. 在模型训练过程中进行剪枝 → 对剪枝后模型进行微调3. 进行剪枝 → 从头训练剪枝后模型使用较少
模型剪枝主要单元有以下三个
训练 Training训练过参数化模型得到最佳网络性能以此为基准剪枝 Pruning根据算法对模型进行剪枝调整网络结构中通道或层数得到剪枝后的网络结构微调 Finetune在原数据集上进行微调用于重新弥补因为剪枝后的稀疏模型丢失的精度性能 模型剪枝的流程如下图所示 第一种就是最原始的模型剪枝的流程第二种就是会有多个子网络模型进行采样然后对这些子模型进行评估看哪个模型的精度性能比较好最后选择其中一个对它微调即可最后一种就是基于 NAS 自动搜索的方式第三种更多的是学术的前沿在工业界使用较少因为基于 NAS 的搜索太消耗资源了
5.4 L1-norm剪枝算法
下面我们来了解一个具体的剪枝算法—L1-norm based Channel Pruning
该剪枝算法是结构化剪枝专门针对 channel 进行剪枝剪枝的标准使用 L1-norm 进行约束。
通过 L1-norm 标准来衡量卷积核的重要性L1-norm 是一个很好的选择卷积核的方法认为如果一个 filter 的绝对值和比较小说明该 filter 并不重要。[论文]指出对剪枝后的网络结构从头训练要比对重新训练剪枝后的网络好
基于这个算法原理我们来看下具体的算法步骤 1. 对每个卷积核 F i j F_{ij} Fij 计算它的权重绝对值L1-norm之和 S j ∑ l 1 j i Σ ∣ K l ∣ S_{j}\sum_{l1}^{ji}\Sigma|Kl| Sj∑l1jiΣ∣Kl∣
2. 根据卷积核的 L1-norm 值 S j S_j Sj 进行排序
3. 将 m 个权重绝对值之和最小的卷积核以及对应 feature maps 进行剪枝
4. 下一个卷积层中与剪掉 feature maps 相关的卷积核 F i 1 , j F_{i1,j} Fi1,j 进行剪枝
5. 对于第 i 层和第 i1 层的新权重矩阵被创建剩下权重参数被复制到新模型中。 L1-norm 是一个非常经典的剪枝算法非常欢迎大家去学习一下
5.5 讨论 讨论1博主之前在学习剪枝量化课程的时候有提到要对预训练模型进行约束训练主要是为模型的 BN 层增加 L1 约束然后再进行剪枝我们为什么要进行约束训练最后微调阶段又为什么去除约束训练不去除又会发生什么 约束训练的目的是为了鼓励模型中的某些权重趋向于 0具体地说L1 正则化会使得某些权重的值变得非常接近与 0这为后续的剪枝步骤提供了便利因为那些接近于 0 的权重或通道可以被视为不重要并被剪掉。加入 L1 约束的方法其实就是我们上面提到的 L1-norm 剪枝算法的一部分该算法使用 L1 范数来评估网络中每个通道的重要性。那些具有较小 L1 范数的通道被认为是不重要的并可能在剪枝步骤中被删除。
在剪枝后进行微调的主要目的是为了恢复因剪枝导致的模型性能下降。微调过程中我们希望模型在较小的学习率下逐渐适应其新的结构并优化其残留的权重以获得更好的性能。
在微调阶段去除 L1 约束的原因是因为我们不再需要鼓励更多的权重接近于 0因为剪枝已经完成了。继续应用 L1 约束可能会干扰权重的优化因为它可能会继续促使一些权重接近于 0而这并不是微调阶段的目的。
如果在微调时仍然保留 L1 约束那么这种约束可能会与微调的目的发生冲突。模型可能会在尝试优化其性能的同时仍然受到使权重接近于 0 的约束。这可能导致微调过程不够有效甚至可能导致模型的性能下降。 讨论2为什么我们约束训练后就知道如何去剪枝呢我们从约束训练中得到了什么 约束训练的结果 通过 L1 约束训练我们得到的是一个模型其中某些权重或参数的值非常小接近于 0。这些接近于 0 的权重或参数代表了对模型输出影响最小的部分。在神经网络中权重的绝对值可以被视为该权重的重要性的一个指示。更大的权重值意味着更强烈的影响而接近于 0 的权重值意味着很小或没有影响。因此L1 约束训练为我们提供了一个直观的、基于权重值的方法来评估每个权重或参数的重要性。
如何进行剪枝在约束训练后我们可以为模型中的权重或参数设定一个阈值。权重值低于这个阈值的权重或参数可以被认为是不重要的并被剪掉。例如对于 BN 层我们可以根据其对应的 γ \gamma γ缩放系数的 L1 范数来决定是否剪掉整个通道。一个常见的方法是选择一个阈值如最小的 10% 或 20% 的 γ \gamma γ 值然后将这些通道剪掉。
为什么这样做有效这种基于 L1 范数的剪枝方法的背后思想是那些重要性低的权重或参数在整体模型性能中的贡献很小因此去掉它们不太可能对模型性能产生大的影响。同时剪枝可以显著减少模型的大小和计算量。 讨论3为什么对 BN 层增加 L1 约束后能够指导 Conv 的剪枝呢 我们可以用下面一张图说明 我们都知道 BN 层主要执行两个操作标准化normalize和缩放移位scale and shift。标准化是为了使特征的分布接近于均值为 0、方差为 1 的正态分布。缩放移位则是通过两个参数 γ \gamma γ缩放因子和 β \beta β偏移因子来进行的。
上图中展示了大的缩放移位和小的缩放移位对特征分布的影响。可以看到大的缩放移位会引起特征分布的显著变化而小的缩放移位则较为微妙。如果 BN 层后某个通道的特征分布没有发生显著变化即 γ \gamma γ 和 β \beta β 的影响较小这暗示这个通道可能对模型输出的贡献不大。因此可以考虑对这些通道进行剪枝。
因此 BN 层能够指导 conv 通道的剪枝的原因主要是
BN 层可以揭示卷积通道的有效性通过观察 BN 参数特别是缩放因子 γ \gamma γ的大小和特征分布的变化可以评估通道的重要性。如果 BN 层的参数或特征分布显示某个通道的贡献很小那么这个通道可以被认为是不重要的并可以考虑剪枝。
6. 知识蒸馏原理 这小节内容主要分享知识蒸馏的背景、原理以及蒸馏的知识方式 6.1 What、Why and How 问题什么是知识蒸馏为什么需要知识蒸馏如何使用知识蒸馏 **知识蒸馏Knowledge Distillation**是深度学习中的一个技术用于将一个大型、复杂的模型称为“教师模型”的”知识“传递给一个小型、简化的模型称为”学生模型“。这个过程涉及到使用教师模型的预测结果来指导学生模型的训练。(from chatGPT)
为什么需要知识蒸馏呢主要涉及以下几点
部署限制大模型往往有巨大的参数量和计算需求这使得它们难以部署在资源有限的环境中如移动设备和嵌入式系统。通过知识蒸馏我们可以得到一个性能相近但参数量远小的模型。计算效率小模型通常更快需要更少的计算资源。泛化能力在某些情况下经过知识蒸馏训练的学生模型可能具有比直接训练的小模型更好的泛化能力
如何使用知识蒸馏呢主要涉及以下几点
训练教师模型首先你需要有一个已经训练好的大型模型。这个模型可以是任何复杂的深度网络如 ResNet、BERT等。生成软标签使用教师模型对训练数据集进行预测得到软标签。软标签是指模型输出的概率分布而不是硬的类标签。训练学生模型使用这些软标签来训练学生模型。损失函数通常是学生模型预测的概率分布与教师模型的概率分布之间的距离例如 KL 散度。可选的技巧有许多技巧和变种可以增强知识蒸馏的效果例如使用温度来调整软标签的“软度”或者结合硬标签和软标签的损失。
6.1 知识蒸馏背景
Knowledge DistillationKD最初是 Hinton 在 Distilling the Knowledge in a Neural Network 提出与 Label smoothing 动机类似但是 KD 生成 soft label 的方式是通过教师网络得到的KD 可以视为将教师网络学到的知识压缩到学生网络中另外一些工作 Circumventing outlier of auto augment with knowledge distillation 则将 KD 视为数据增强方法的一种
知识蒸馏主要思想Student Model 学习模型模仿 Teacher Model 教师模型二者相互竞争直到学生模型可以与教师模型持平甚至卓越的表现有点 GAN 网络的味道如下图所示 知识蒸馏的算法主要由1知识 Knowledge、2蒸馏算法 Distillate、3师生架构三个关键部分组成
6.2 蒸馏的知识方式
Knowledge 知识的方式可以分为以下几种
1. response-based knowledge2. feature-based knowledge3. relation-based knowledge4. Architecture-based knowledge使用较少
下面我们逐一介绍
Response-Based Knowledge
主要指 Teacher Model 教师模型输出层的特征。主要思想是让 Student Model 学生模型直接学习教师模式的预测结果Knowledge。通俗的来讲就是一个知识点老师充分学习完了然后把结论告诉学生就好了假设张量 z t z_t zt 为教师模型输出张量 z s z_s zs 为学生模型输出Response-based knowledge 蒸馏形式可以被描述为 L R e s D ( z t , z s ) L R ( z t , z s ) L_{ResD}(z_{t},z_{s}){\mathcal L}_{R}(z_{t},z_{s}) LResD(zt,zs)LR(zt,zs)
学习流程如下图所示 红色的代表老师绿色的代表学生我们会把 Teacher Model 输出的最后一层的特征给到学生网络模型中去学习然后通过 Distillation Loss 让学生模型最后一层的特征学习老师模型输出的特征。老师的输出特征是比较固定的而学生是不太固定需要去学习的于是通过一个损失函数去模拟去学习使得两个的 Logits 越小越好。
Feature-Based Knowledge
深度神经网络善于学习到不同层级的表征因此中间层和输出层的都可以被用作知识来训练学生模型中间层学习知识的 Feature-Based Knowledge 对于 Respone-Based Knowledge 是一个很好的补充其主要思想是将教师和学习的特征激活进行关联起来。Feature-Based Knowledge 知识转移的蒸馏损失可表示为 L F e a D ( f t ( x ) , f s ( x ) ) L F ( ϕ t ( f t ( x ) ) , ϕ t ( f s ( x ) ) ) L_{Fea\ D}(f_{t}(x),f_{s}(x)){\mathcal L}_{F}(\phi_{t}(f_{t}(x)),\phi_{t}(f_{s}(x))) LFea D(ft(x),fs(x))LF(ϕt(ft(x)),ϕt(fs(x))) Feature-Based Knowledge 整体工作流程图如下所示 这里面的 Distillation Loss 更多是创建在 Teacher Model 和 Student Model 的中间层通过中间层去创建一个连接关系这种算法的好处就是教师网络可以给学生网络提供非常大量的有用的参考信息但如何有效地从教师模型中选择提示层从学生模型中选择引导层仍有待进一步研究。另外由于提示层和引导层的大小存在显著差异如何正确匹配教师和学生的特征表示也需要探讨。
Relation-Based Knowledge
前面基于 Feature-Based Knowledge 和 Response-Based Knowledge 知识都使用了教师模型中特定层中特征的输出。基于关系的知识即 Relation-Based Knowledge 进一步探索了不同层或数据样本之间的关系。一般情况下基于特征图关系的关系知识的蒸馏损失可以表示为 L R e l D ( f t ( x ) , f s ( x ) ) L R ( ψ t ( f ˊ t , f ˋ t ) , ψ t ( f ˊ s , f ˋ s ) ) L_{Rel\ D}(f_{t}(x),f_{s}(x)){\mathcal L}_{R}(\psi_{t}({\acute{f}}_{t},{\grave{f}}_{t}),\psi_{t}({\acute{f}}_{s},{\grave{f}}_{s})) LRel D(ft(x),fs(x))LR(ψt(fˊt,fˋt),ψt(fˊs,fˋs)) Relation-Based Knowledge 整体工作流程图如下所示 这里面的 Distillation Loss 就不仅仅去学习刚才讲到的网络模型中间的特征还有最后一层的特征而且它会学习数据样本还有网络模型层之间的一个关系。
OK本节就和大家分享两个知识一个是知识蒸馏的背景为什么要去蒸馏蒸馏有什么好处。另一个就是蒸馏的知识形式更多的关注于 Knowledge 怎么提取从哪里来。
7. 知识蒸馏算法解读 在上节内容中我们已经充分地了解了知识蒸馏算法提出的背景还有知识蒸馏的知识形态。这节我们主要是去学习三个具体的知识蒸馏的方法还有 Hinton 经典的知识蒸馏论文解读 知识蒸馏可以划分为
1.离线蒸馏offline distillation2.在线蒸馏online distillation3.自蒸馏self-distillation 7.1 Offline蒸馏
大多数蒸馏采用 Offline Distillation蒸馏过程被分为两个阶段1蒸馏前教师模型预训练2蒸馏算法迁移知识。因此 Offline Distillation 主要侧重于知识迁移部分。
通常采用单向知识转移和两阶段训练过程。在步骤1中需要教师模型参数量比较大训练时间比较长这种方式对学生模型的蒸馏比较高效。 注这种训练模式下的学生模型往往过度依赖于教师模型。
7.2 Online蒸馏
Online Distillation 主要针对参数量大、精度性能好的教师模型不可获得的情况。教师模型和学生模型同时更新整个知识蒸馏算法是一种有效的端到端可训练方案。 注现有的 Online Distillation 往往难以获得在线环境下参数量大、精度性能好的教师模型。
7.3 Self蒸馏
Self-Distillation 的教师模型和学生模型使用相同的网络结构同样采用端到端可训练方案属于 Online Distillation 的一种特例。 现在总结下上面提到的三种知识蒸馏方法offline distillation、online distillation 和 self-distillation 三种蒸馏方法可以看做是学习过程
Offline Distillation指知识渊博教师向学生传授知识Online Distillation指教师和学生共同学习Self-Distillation指学生自己学习知识
7.4 Hinton经典蒸馏算法解读
在 16 年到 17 年的时候Hinton 在 Distilling the knowledge in a neural network 这篇文章中第一次提出知识蒸馏的概念在正式了解这篇文章之前我们先要去看看两个概念Hard-target 和 Soft-target
传统的神经网络训练方法是定义一个损失函数目标是使预测值尽可能接近真实值Hard-target损失函数就是使神经网络的损失值和尽可能小。这种训练过程是对 ground truth 求极大似然。在知识蒸馏中是使用大模型的类别概率作为 Soft-target 的训练过程。 假设现在是识别 MNIST 数据集中的 10 个数字我现在输入一张写着 2 数字的图片到神经网络中去当然希望网络预测是 2 的概率越高越好如左图所示。那这种方式在数学或者统计方面就是对 ground truth 真实的数据求极大的似然值。
在知识蒸馏中就像右边的图所示希望网络能够学习到更多的其它额外像的知识。假设现在还是输入一张写着 2 数字的图片到神经网络中我们希望网络能学到更多冗余的信息比如 2 手写数字的字体长得像 3网络把这个冗余的信息也学习出来是最好的。
因此上面左边的图就叫做 Hard Target右边的图就叫做 Soft Target。
下面再了解另外一个概念叫做 SoftMax with Temperature在 SoftMax 函数里面增加一个温度系数。
传统的 softmax 函数定义如下 q i e x p ( z i ) ∑ j e x p ( z j ) q_{i}\frac{exp(z_{i})}{\sum_{j}exp(z_{j})} qi∑jexp(zj)exp(zi) 使用软标签就是修改了 softmax 函数增加温度系数 T q i e x p ( z i / T ) ∑ j e x p ( z j / T ) q_{i}\frac{exp(z_{i}/T)}{\sum_{j}exp(z_{j}/T)} qi∑jexp(zj/T)exp(zi/T) 其中 q i q_i qi 是每个类别输出的概率 z i z_i zi 是每个类别输出的 logitsT 是温度。温度 T1 时为标准 Softmax。T 越高softmax 的输出概率分布越趋平滑其分布的熵越大负标签携带的信息会被相对地放大模型训练将更加关注负标签。
这个时候网络模型训练时就会更关注于一些负标签的冗余的信息就是上面提到的 Soft Target它会将一些冗余的信息额外的信息记录下来通过简单的设置一个温度系数来控制。
下面看一下比较明确的图 从图中可以看出随着 T 的增加可以看到 softmax 输出的分布就会越平滑信息熵也就会越大信息的差异也会越少。如何找打一个合适的 T 让网络学习到一些冗余的信息但又不至于影响模型最终的性能呢
下面我们就来探讨下如何选择这个 T
负标签中包含一定的信息尤其是那些负标签概率值显著高于平均值的标签。但由于 Teacher 模型的训练过程决定了负标签部分概率值都比较小并且负标签的值越低其信息就越不可靠。因此温度的选取需要进行实际实验的比较本质上就是在下面两种情况之中取舍
当想从负标签中学到一些信息量的时候温度 T 应该调高一些当想减少负标签的干扰的时候温度 T 应该调低一些
接下来我们就正式的回到知识蒸馏这个算法里面首先需要了解下知识蒸馏算法的训练流程的差异
传统训练过程 Hard Targets对 ground truth 求取极大似然 softmax 值KD 训练过程 Soft Targets用 Teacher 模型的 calss probabilities 作为 soft targets
在论文中知识蒸馏使用 offline distillation 的方式采用经典的 Teacher-Student 结构其中 Teacher 是“知识”的输出者Student 是“知识”的接受者。知识蒸馏的过程分为 2 个阶段
1. 教师模型训练训练 Teacher 模型简称为 Net-T特点是模型相对复杂精度较高。对 Teacher 模型不作任何关于模型架构、参数量等方面限制像 transformer 这类的大模型更加适合。唯一的要求就是对于输入 X其都能输出 Y其中 Y 经过 softmax 映射输出值对应相应类比的概率值。
2. 学生模型蒸馏训练 Student 模型简称为 Net-S它是参数量较小、模型结构相对简单的模型。同样对于输入 X其都能输出 YY 经过 softmax 映射后能输出与 Net-T 对应类别的概率值。
论文中Hinton 将问题限定在分类问题下或者属于分类的问题共同点是模型最后有 softmax 层其输出值对应类别的概率值。知识蒸馏时由于已经有一个泛化能力较强的 Net-T在利用 Net-T 来蒸馏 Net-S 时可以直接让 Net-S 去学习 Net-T 的泛化能力。
下面来看下算法流程
1. 训练 Teacher Model2. 利用高温 T h i g h T_{high} Thigh 产生 soft target3. 使用 {soft target, T h i g h T_{high} Thigh} 与 {hard target, T h i g h T_{high} Thigh} 同时训练 Student Model4. 设置温度 T 1Student Model 用于线上推理 Student Model 的训练或者蒸馏过程相对来说会复杂一点它有两个损失在训练 Net-T 的过程中高温蒸馏过程的目标函数由 distill loss对应 soft target和 student loss对应 hard target加权得到计算公式如下 L α L s o f t β L h a r d L s o f t − ∑ j N p j T log ( q j T ) L h a r d − ∑ j N c j l o g ( q j ) \begin{aligned} L\alpha L_{soft}\beta L_{hard} \\ L_{soft} -\sum_j^Np_j^T\log(q_j^T) \\ L_{hard} -\sum_j^Nc_j\mathrm{log}(q_j) \end{aligned} LLsoftLhardαLsoftβLhard−j∑NpjTlog(qjT)−j∑Ncjlog(qj) soft label 的损失函数来自于 Teacher Modelhard label 的损失函数来自于真实的数据标签通过结合两个损失函数去学习。
OK以上就是关于知识蒸馏的内容
总结 本系列视频主要讲解了模型压缩的几种常见方法包括量化、剪枝和蒸馏其中量化和剪枝博主之前有简单了解过这次再理清一些基础概念并加深印象蒸馏方面也初步了解了其原理感谢 ZOMI 老师。 总的来说该系列视频作为导读了解一些基本概念还是不错的真正要深入研究还行需要大家多看看论文和相关代码动手实践才行 参考
【推理引擎】模型压缩YOLOv5-QAT量化部署YOLOv5-PTQ量化部署剪枝与重参第一课修剪结构和标准TensorRT量化第三课动态范围的常用计算方法https://github.com/chenzomi12/DeepLearningSystem/tree/main/043INF_SlimTo prune, or not to prune: exploring the efficacy of pruning for model compressionDistilling the Knowledge in a Neural Network