在过去的十年中,深度学习在解决许多以前被认为无法解决的问题方面发挥了重要作用,并且在某些任务上的准确性也与人类水平相当甚至超过了人类水平。如下图所示,更深的网络具有更高的准确度,这一点也被广泛接受并且证明。
使用更深层次的网络模型追求人类级别的准确性会带来一系列挑战,例如:
- 更长的推理时间
- 更高的计算要求
- 更长的训练时间
高计算量的深度模型需要较长训练时间,对于线下训练还是可以接受的,因为训练通常进行一次或以固定的时间间隔进行,但在高吞吐量生产环境中进行线上部署变得极其困难。在这种情况下模型压缩技术变得至关重要,因为压缩能够在不影响准确性的情况下减少庞大模型的占用空间。这篇介绍性文章将讨论可用于优化重型深度神经网络模型的不同技术。
模型压缩方法
目前用于现代深度学习的模型压缩的主流方法有三个:
基于量化的方法:量化涉及使用较低精度的数据类型来存储模型权重和执行计算(例如:8 位整数而不是 32 位浮点数)。
模型剪枝:模型修剪涉及清除对模型性能的贡献较小的神经元或某些神经元之间的连接。剪枝之所以有效是因为深度神经网络本质上是稀疏的,正如 Frankle 等人在他们的论文 The Lottery Ticket Hypothesis:Finding Sparse, Trainable Neural Networks 中所描述的那样。
知识蒸馏:这种方法训练一个小模型来模拟更大、更准确的预训练模型的软标签。
软标签允许学生模型很好地泛化,因为软标签代表了更高级别的抽象和对不同类别相似性的理解,而不是峰值的独热编码表示。
在以下部分中,我们详细介绍模型量化,这是最广泛使用的模型压缩形式。
什么是量化?
根据定义,量化是将值从大集合映射到较小集合的过程,其目标是在转换中具有最少的信息损失。这个过程被广泛应用于各个领域,包括信号处理、数据压缩、信号转换等等。
量化应用于连续模拟信号,通过采样和四舍五入到最接近的可表示量化值将它们转换为离散数字信号
浮点数表示
1985 年创建的 IEEE 754 标准是现代计算机中浮点值二进制表示的技术标准。根据 IEEE 754,定义了可用于表示浮点数的级别,范围从 16 位(半精度)到 256 位(八位精度)。浮点数的表示包括三个部分:符号位、有效数(小数)和指数位。
这些二进制形式的值被连接起来以表示内存中的数字。下图描述了 32 位精度浮点数的表示:
对于离散整数表示,我们最多可以使用 n 位表示 2^n 个不同的数字。使用浮点表示法使我们能够在数轴上表示更大范围的数字,如下图所示:
还需要注意的是 不同精度的浮点数使用不同的位来表示指数位和有效位,因此所表示的范围也有所不同。下表显示了数据类型 FP32、FP16 和 INT8 表示的范围和最小值。
量化操作
可表示范围的方差对不同数据类型中固定值的表示是有影响的。以𝞹的数值为例,该值随表示它的不同数据类型而变化。
从表中可以明显看出,将数字从较高精度的数据类型直接转换为较低精度的数据类型可能会导致值的表示误差。这些误差称为量化误差。在深度神经网络中出现此类误差可能造成严重的后果的,因此将模型直接类型转换为较低的精度并非易事。我们将在本节讨论最小化此类误差的方法。
理论上我们可以使用 n 位表示最多 2^n 个不同的值。由于鸽巢原理(pigeonhole principle,狄利克雷抽屉原理),由较高精度数据类型表示的整个范围映射到较低精度数据类型必然会增加量化误差。但是如果我们知道要先验转换的分布的知识,那么它能被用来最小化误差吗?
从FP32到INT8 的代表性映射
FP32 可以表示介于 3.4 10³⁸ 和 -3.4 10³⁸ 之间的范围。但是大多数深度网络模型的权重在它们的权重和激活方面没有如此大的变化。如果我们事先知道或可以估计我们的输入范围,我们就可以确定我们输入数据的范围(而不是整个 FP32 范围)与较低精度数据类型的整个范围之间的关系,这就可以使映射变得更优化。
让我们假设输入数据的分布范围是先验已知的,并以从浮点集(FP32)到整数(INT8)的转换为例讨论转换过程。
深度学习中的量化
现在让我们介绍一下量化在深度学习中的应用。在深度神经网络中模型参数存储为浮点值,模型的前向缠脖涉及一系列浮点运算。所以对于深度学习量化是指对精度要求较低的数据类型中的权重和激活进行量化,如下图所示。
偏置层没有量化吗?在实践中,偏置层通常从浮点数量化到 INT32 精度,而不是降低到 INT8 精度,因为偏置的数量比权重/卷积层少得多。使用更大尺寸的 INT32 对深度神经网络模型的体量来说是微不足道的。
量化权重向量
在实践中这是一个简单的步骤,因为我们通常可以看到模型的权重并且在量化给定层的情况下,权重可以用作先验。我们观察到神经网络权值的分布通常在一个很小的范围内,非常接近于0。下图显示了Alexnet模型和MobileNet v1模型中一些卷积和全连接层的权重分布。这个有限的范围使得映射到较低精度的数据类型更不容易出现量化误差。
量化激活
与模型的权重不同,神经网络层的激活根据提供给模型的输入数据而变化,并且为了估计激活范围,需要一组具有代表性的输入数据样本。因此量化激活是一个依赖于数据的过程,需要额外的数据来校准神经网络层的输出。我们可以使用不同的方法来确定比例因子和模型权重和激活的零点,我们将在下一节中讨论。
量化类型
Pytorch、Tensorflow 等现代深度学习框架都支持不同类型的量化。我们可以将量化算法分类成两大类:
- 训练后量化:在模型完全训练后执行
- 量化感知训练:训练是在量化约束下完成的
1)训练后量化
在这种方法中,量化是在模型完全训练后执行的。由于权重在训练后是固定的权重的映射很容易计算,因为层的激活值根据传递的输入张量而变化, 所以在训练后计算激活范围就比较麻烦,这里有两种处理方法:
a) 动态训练后量化:
这涉及根据运行时输入到模型的数据分布,在推理过程中动态微调激活范围。这种方法最容易实现,因为量化不需要额外的步骤。由于不需要额外的数据,这种方法最适合难以生成详尽数据分布的情况——例如:序列到序列模型。但是在运行时使用指数移动平均线来估计激活范围会增加模型延迟。
b) 静态训练后量化:
这种方法会涉及额外的校准步骤,例如使用代表性数据集来估计使数据集变化的激活范围。为保证最大程度地减少误差,这种估计会以全精度数据进行,然后将激活按比例缩小到较低精度的数据类型。由于在运行期间的推理过程中没有进行额外的计算,因此这种方法生成的模型速度最快(延迟最少)
使用训练后量化的主要优点是不需要在整个数据集上进行训练,8 位或 16 位量化可以应用于任何现有的预训练模型。像 Pytorch 和 Tensorflow 这样的现代深度学习框架对这些方法都有官方实现。但是这种策略会由于量化误差而导致一些(通常是轻微的)精度损失。这些误差可以在训练过程中通过使用一个技巧来进一步减轻,我们将在下一节讨论。
2)量化感知训练
量化感知训练 (QAT) 试图解决由于模型训练过程中的量化误差而导致的精度损失的问题。在前向传递中QAT 在权重和激活计算期间复制量化行为,而损失计算和损失的反向传播保持不变(保持更高的精度)。这个想法是由 Jacob等人提出的。
使用 QAT,所有模型权重和激活在前向传递期间都被“伪量化”:也就是说浮点值被四舍五入以模拟较低精度(通常是 int8)值,但所有其他计算仍然使用浮点数完成。由于训练过程中的所有权重调整都是在“意识到”模型最终会被量化的情况下进行的,因此在量化之后这种方法通常会产生比其他方法更高的准确率,并且训练后的量化模型与全精度相比几乎无损。
自动混合精度量化
作为QAT的扩展,在某些情况下仍不可能将某些层的输入域的整个范围完全拟合到较低精度的量化范围中。这种情况下使用更高的精度值保留这些层是有益的。随着自动混合精度训练的引入这一问题在很大程度上得到了解决,自动混合精度训练涉及到在训练时间内根据层的激活范围来确定单个层的量化,并且对模型的精度没有影响。
量化类型的总结
下表从数据集需求和涉及的权衡方面总结了上面的讨论。
可概括为以下流程图:
模型的基准测试
在本节中,我们将研究这些量化方法在各种实际模型中的影响。正如预期的那样,我们看到量化感知训练(QAT)在准确性和延迟方面比训练后量化表现得更好。经过量化后大多数模型的精度都有小幅下降,但从整体上看延迟的改善可能掩盖了实际应用中性能的小幅下降。
CNN 模型对比
BERT模型对比
各种类型的量化速度对比
总结
在这篇文章中我们讨论了各种量化方法,这些方法可用于压缩深度神经网络,同时对模型的准确性影响最小。我们经常使用包括量化在内的各种技术来优化我们的模型。量化作为常用的模型压缩方式,在生产环境中得到了广泛的应用。
作者:Akash Manna,Vikram Gupta,Debdoot Mukherjee
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。