文章目录
- 一、什么是模型量化?
- 二、常见的模型量化方法
- 1.权重量化(Weight Quantization)
- 2.激活量化(Activation Quantization)
- 3.混合精度量化(Mixed Precision Quantization)
- 4. 剪枝和量化(Pruning and Quantization)
- 三、什么是int8量化
- 1. int8量化步骤
- 2. int8量化计算公式
- 2.1 确定缩放因子(Scale)和零点(Zero Point)
- 2.2 应用量化
- 2.3 整数裁剪
- 2.4 一个线性、非对称、int8后量化的例子
- 3.代码
一、什么是模型量化?
在深度学习领域,模型通常采用float32这种数据格式进行训练和存储,每个参数占据32比特(即4字节)的空间。例如,一个大小为7b的模型会需求28b的显存或内存资源。但如果能够将参数所需的存储空间压缩至16比特、8比特甚至4比特,那么就能显著减少所需的存储容量,并可能加快模型的推理速度。量化可以应用在模型的参数(即权重)、激活值,甚至是在训练过程中更新的梯度上。参数的量化通常相对容易实施,因为模型的参数分布通常比较稳定。
模型量化的主要目标是在尽可能保持模型性能的前提下,减少模型的存储空间、内存带宽和计算资源消耗。较小的模型可以更轻松地部署在资源受限的设备上,例如移动设备、嵌入式系统和边缘设备等。
二、常见的模型量化方法
1.权重量化(Weight Quantization)
将模型中的权重参数转换为较低比特的整数或浮点数表示。例如,将32位浮点数权重量化为8位整数或4位浮点数。
2.激活量化(Activation Quantization)
将模型中的激活值转换为较低比特的整数或浮点数表示。类似于权重量化,激活量化可以将32位浮点数激活值量化为8位整数或4位浮点数。
3.混合精度量化(Mixed Precision Quantization)
结合使用不同精度的数据表示,例如使用低精度整数表示权重和激活值,同时保持某些操作的高精度表示(如矩阵乘法)。
4. 剪枝和量化(Pruning and Quantization)
将模型中的冗余连接或不重要的权重剪枝(删除),然后将剩余的权重进行量化。这种方法结合了剪枝和量化两种技术,可以进一步减少模型的存储需求和计算复杂性。
模型量化的实现通常需要进行训练和校准过程。在训练阶段,模型使用原始的高精度表示进行训练。在校准阶段,使用预定义的数据集或一部分训练数据集来收集模型在推理过程中的激活值统计信息,以便确定合适的量化范围。然后,通过量化算法将权重和激活值转换为较低比特的表示。最后,量化后的模型可以用于推理阶段,其中计算和存储都使用量化后的数据格式。
三、什么是int8量化
在深度学习模型中,通常使用32位浮点数(FP32)来表示权重和激活值。然而,FP32的存储需求和计算复杂性较高,特别是在边缘设备和嵌入式系统等资源有限的环境中运行时,会造成显著的性能瓶颈。INT8量化通过将这些浮点数值量化为8位整数,可以大幅度地减少模型的存储空间和内存带宽,并加速模型的推理过程。
1. int8量化步骤
- 训练模型:首先,使用常规的训练方法和数据集对深度学习模型进行训练,得到FP32精度的模型。
- 收集统计信息:使用预先定义的校准数据集或一部分训练数据集来收集模型在推理过程中的激活值统计信息。这些统计信息可以用于确定合适的量化范围,以便将浮点数值映射到8位整数。
- 量化权重和激活值:根据收集的统计信息,将模型的权重和激活值量化为8位整数。通常使用量化算法(如最大/最小值量化、均匀量化等)来将浮点数映射到8位整数。
- 构建量化模型:使用量化后的权重和激活值,重新构建量化模型。这个模型在推理过程中只使用8位整数进行计算。
- 推理过程:使用量化模型进行推理。输入数据经过量化模型,推理过程中的计算都使用8位整数进行,从而提高推理效率和性能。
2. int8量化计算公式
2.1 确定缩放因子(Scale)和零点(Zero Point)
缩放因子(scale):用于将浮点数映射到整数范围。
零点(Zero Point):确保浮点数0可以被准确地表示为整数。
计算scale和zero_point通常需要最大值(max_val)和最小值(min_val):
scale = (max_val - min_val) / (2^7 - 1) # 127是int8的最大值
zero_point = round(-min_val / scale) #zero_point需要在-128到127的范围内,因为这是8位有符号整数的范围
2.2 应用量化
使用scale和zero_point,量化一个浮点数(float_val)成一个8位整(int_val)。
int_val = round(float_val / scale) + zero_point #round"指的是将一个浮点数四舍五入到最接近的整数
2.3 整数裁剪
如果量化后的整数超出了-128到127的范围,它需要被裁剪以保持在有效范围内。
int_val = min(127, max(-128, int_val))
这样,量化过程就可以将32位浮点数数组转换为能够在8位整数范围内表示的数组,这减少了内存占用,同时可能提高了执行速度。
2.4 一个线性、非对称、int8后量化的例子
假设我们有下面这个列表的模型权重作为浮点数:
weights = [0.15, -0.8, 0.2, -0.5]
量化到8位整数涉及以下步骤:
(1)确定量化范围:
在Int8量化中,值的范围通常是[-128, 127](对于有符号整数)。找到浮点列表中的最小和最大值:
min_val = min(weights) # -0.8
max_val = max(weights) # 0.2
(2)计算缩放系数(scale)和零点(zero point):
计算缩放系数,将浮点数范围映射到整数范围。举例来说,可以简单选择max(abs(min_val), abs(max_val))作为分母,然后以[-128, 127]为分子进行缩放计算。因为0可能不在浮点数的范围内,我们需要一个零点来表示量化值0对应的浮点数。通常,零点是通过缩放原始的浮点数零值来确定的。
scale = (max_val - min_val) / (127 - (-128))
#缩放系数 (0.2 - (-0.8)) / (127 - (-128))
#scale = 1.0 / 255
zero_point = 127-max_val / scale
#zero_point = 76
(3)应用量化转换:
将每个浮点数权重转换为整数表示。
quantized_weights = [round((w / scale) + zero_point) for w in weights]
应用上面的公式,具体计算:
quantized_weights = [round(0.15 / scale) + zero_point,round(-0.8 / scale) + zero_point,round(0.2 / scale) + zero_point,round(-0.5 / scale) + zero_point
]
#根据scale,四舍五入并加上zero_point
quantized_weights = [round(38.4) + 76,round(-204.8) + 76,round(51.2) + 76,round(-128.0) + 76
]
得到的quantized_weights是: [114, -129, 127, -52]
(4)做截断,使得数据落在[-128,127]范围
量化后的权重如下所示:
quantized_weights = [114, -128, 127, -52]
3.代码
model = AutoModelForCausalLM.from_pretrained("Llama-2-7b-ms",
low_cpu_mem_usage=True,
load_in_8bit=True,
device_map="auto")