DeepSpeed 混合量化 (MoQ)
DeepSpeed 引入了新的模型压缩支持,使用量化技术,称为混合量化(Mixture-of-Quantization,MoQ)。MoQ 是在量化感知训练(Quantization-Aware Training,QAT)的基础上设计的,不同之处在于它在训练过程中安排了各种数据精度。它从使用高精度(如 FP16 或 16 位量化)量化模型开始,并通过预定义的计划逐步降低精度,直到达到目标量化位数(如 8 位)。此外,我们使用模型参数的二阶信息来动态调整网络中每一层的量化计划。我们已经看到,通过添加这样的计划并在训练过程中使用各种数据精度,我们可以以更好的质量量化模型并保持准确性。为了更好地理解 MoQ 方法,请参考 MoQ 深入解析,这里。
下面,我们以GLUE任务的微调为例,说明如何使用MoQ。
先决条件
要使用MoQ进行模型量化训练,您应满足以下两个要求:
- 使用入门指南将DeepSpeed集成到您的训练脚本中。
- 添加参数以配置您的模型,我们将在下面定义MoQ参数。
MoQ量化计划由多个参数定义,这些参数允许用户探索不同的配置。
MoQ 参数
enabled: 是否启用量化训练,默认为 False。
quantize_verbose: 是否显示详细细节,默认为 False。
quantizer_kernel: 是否启用量化内核,默认为 False。
quantize_type: 量化类型,“symmetric”或“asymmetric”,默认为“symmetric”。
quantize_groups: 量化组,显示用于量化模型的尺度数量,默认值为1。
quantize_bits,控制数据精度从起始位到最终目标位转换的位数(例如,从16位降到8位)。
`start_bits`: The start bits in quantization training. Default is set to 16.
`target_bits`: The target bits in quantization training. Default is set to 16.
quantize_schedule,这决定了如何在每个精度级别上安排训练步骤。
`quantize_period`: indicates the period by which we reduce down the precision (number of bits) for quantization. By default, we use a period of 100 training steps, that will be doubled every time the precision reduces by 1 bit.
`schedule_offset`: indicates when the quantization starts to happen (before this offset, we just use the normal training precision which can be either FP32/FP16). Default is set to 100 steps.
quantize_algo,用于量化模型的算法。
`q_type`: we currently support symmetric and asymmetric quantization that result in signed and unsigned integer values, respectively. Default is set to symmetric
`rounding`: for the rounding of the quantized values, we can either round to the nearest value or use stochastic rounding. Default is set to nearest.
特征值参数
enabled: 是否启用带有特征值计划的量化训练,默认值设置为 False。
verbose: 是否显示特征值计算的详细细节,默认值设置为 False。
max_iter: 计算特征值的最大迭代次数,默认值设置为100。
tol: 计算特征值时的容差误差,默认值设置为1e-2。
stability: 方差稳定因子,默认值设置为1e-6。
gas_boundary_resolution: 表示每N个气体边界进行一次特征值计算,默认值设置为1。
layer_name: 指向所有层以进行特征值计算的模型范围名称,默认值设置为“bert.encoder.layer”。
layer_num: 计算特征值的层数。
如何使用MoQ进行GLUE训练任务
在使用DeepSpeed MoQ微调GLUE任务之前,您需要:
- 安装DeepSpeed。
- 检出 Huggingface transformers 分支,并使用所有必需的包进行安装。
DeepSpeed 配置文件
准备一个配置文件 test.json 如下,请注意以下量化训练的重要参数:
{
"optimizer": {
"type": "AdamW",
"params": {
"lr": 2e-5,
"weight_decay": 0.0,
"bias_correction": true
}
},
"gradient_clipping": 1.0,
"fp16": {
"initial_scale_power": 16,
"enabled": true
},
"quantize_training": {
"enabled": true,
"quantize_verbose": true,
"quantizer_kernel": true,
"quantize-algo": {
"q_type": "symmetric"
},
"quantize_bits": {
"start_bits": 16,
"target_bits": 8
},
"quantize_schedule": {
"quantize_period": 400,
"schedule_offset": 0
},
"quantize_groups": 8,
}
}
测试脚本
在huggingface/examples文件夹下创建一个脚本文件,如下所示,使用上面准备的json文件启用DeepSpeed。
这里我们以MRPC任务为例。
TSK=mrpc
TEST_JSON=test.json
python text-classification/run_glue.py \
--model_name_or_path bert-base-cased \
--task_name $TSK \
--do_train \
--do_eval \
--max_seq_length 128 \
--per_device_train_batch_size 32 \
--learning_rate 2e-5 \
--num_train_epochs 3 \
--output_dir /tmp/$TSK/ \
--fp16 \
--warmup_steps 2 \
--deepspeed test.json
运行此脚本将使用MoQ量化获得MRPC的准确率和F1指标结果。
使用二阶信息(特征值)进行动态调度的量化
特征值可以作为训练期间层敏感性的代理,并可用于创建分层量化计划。当启用特征值计算时,DeepSpeed 将在 gas_boundary_resolution 处计算每个指定层的特征值,并根据层敏感性将 quantize_period 增加最多 5 倍,以便在下一个精度降低阶段之前为层提供足够的迭代次数来适应。5 倍的因子是基于启发式方法选择的。
请注意:
- 启用特征值会使训练速度大大减慢,因为需要更长的时间来计算每一层的特征值。
- 在fp16训练期间,由于范围有限,某些层的某些特征值可能变为NaN/Inf。对于这些层,我们返回所有层中所有非NaN/Inf特征值的最大值。如果所有特征值都是NaN,我们为每个特征值返回1.0。
- 特征值可以将
quantize_period增加最多5倍(基于启发式方法选择)。当与每次1位精度减少阶段中quantize_period的加倍相结合时,这可能导致非常大的quantize_period,特别是如果初始quantize_period本来就很大。因此,在使用特征值时,重要的是从一个相对较小的quantize_period开始,以便在训练结束前允许训练经历所有精度转换阶段。 - 启用特征值并不能保证更好的准确性结果,通常需要与其他设置进行调整,例如
start_bits,quantize_period和quantize_groups。
{
......
"quantize_training": {
"enabled": true,
"quantize_verbose": true,
"quantizer_kernel": true,
"quantize_type": "symmetric",
"quantize_bits": {
"start_bits": 12,
"target_bits": 8
},
"quantize_schedule": {
"quantize_period": 10,
"schedule_offset": 0
},
"quantize_groups": 8,
"fp16_mixed_quantize": {
"enabled": false,
"quantize_change_ratio": 0.001
},
"eigenvalue": {
"enabled": true,
"verbose": true,
"max_iter": 50,
"tol": 1e-2,
"stability": 0,
"gas_boundary_resolution": 1,
"layer_name": "bert.encoder.layer",
"layer_num": 12
}
}
}
微调结果
在这里,我们展示了使用量化进行GLUE任务微调的结果。下表展示了我们为每个任务使用的调度参数,以达到报告的准确率。对于所有这些实验,我们使用了8组对称分组量化。
| 任务 | STSB | MRPC | COLA | WNLI | SST2 | RTE | QNLI | QQP | MNLI |
|---|---|---|---|---|---|---|---|---|---|
| 起始位 | 12 | 12 | 12 | 12 | 12 | 12 | 12 | 12 | 14 |
| 周期 | 10 | 10 | 8 | 8 | 400 | 8 | 64 | 18 | 12 |
| 启用特征值 | False | True | True | True | False | True | False | True | True |
正如我们在下表中看到的,MoQ 在不同的下游任务中始终保持着准确性。
| 任务 | STSB | MRPC | COLA | WNLI | SST2 | RTE | QNLI | QQP | MNLI | SQuAD | ACC+ |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 无量化感知训练(FP16) | 88.71 | 88.12 | 56.78 | 56.34 | 91.74 | 65.3 | 90.96 | 90.67 | 84.04 | 90.56 | 0 |
| 基础QAT | 88.9 | 88.35 | 52.78 | 55.3 | 91.5 | 64.2 | 90.92 | 90.59 | 84.01 | 90.39 | -0.87 |
| MoQ | 88.93 | 89 | 59.33 | 56.34 | 92.09 | 67.15 | 90.63 | 90.94 | 84.55 | 90.71 | 0.75 |
提示
在使用MoQ时,需要在设置正确的量化周期或偏移之前考虑样本数量和训练迭代次数,以确保在训练完成之前量化达到所需的精度水平。
启用特征值进行量化可以动态调整网络中不同部分的量化周期。这有两个积极影响:1) 量化网络可能比使用相同quantize_period量化每一层产生更高的准确性;2) 它根据每层的敏感性自动识别出良好的量化计划。