量化应该在微调之前还是之后进行?

作者

Jambay Kinley, Sam Kemp

2024 年 11 月 19 日

👋 简介

机器学习中的量化是一种用于降低计算中数字精度的技术,这有助于提高模型的效率。量化不是使用高精度浮点数(如 32 位或 16 位),而是将这些数字转换为较低精度的格式,例如 8 位整数。量化的主要优点是模型尺寸更小、计算速度更快,这对于在资源有限的设备(如手机或嵌入式系统)上部署模型尤其有用。但是,这种精度降低有时会导致模型准确性略有下降。

使用 LoRA(低秩适配)方法微调 AI 模型是将大型语言模型适应特定任务或领域的有效方法。LoRA 没有重新训练所有模型参数,而是通过冻结原始模型权重并将更改应用于一组单独的权重来修改微调过程,然后将这些权重添加到原始参数中。这种方法将模型参数转换为较低秩维度,减少了需要训练的参数数量,从而加快了过程并降低了成本。

当微调和量化模型时,建立正确的顺序非常重要

  • 量化应该在微调之前还是之后进行更好?

从理论上讲,在微调之前量化应该产生更好的模型,因为 LoRA 权重是使用与其部署时相同的量化基础模型权重进行训练的。这避免了在浮点基础权重上训练然后在量化基础模型上部署时发生的精度损失。在这篇博文中,我们将演示 Olive(一个用于 ONNX Runtime 的最先进的模型优化工具包)如何帮助您回答何时量化以及为给定模型架构和场景使用哪种量化算法。

此外,作为回答何时量化问题的一部分,我们将展示以下不同的量化算法如何影响准确性

  • 激活感知权重量化 (AWQ) 是一种旨在优化大型语言模型 (LLM) 以实现高效执行的技术。AWQ 通过考虑推理期间产生的激活来量化模型的权重。这意味着量化过程考虑了激活中的实际数据分布,与传统的权重量化方法相比,可以更好地保持模型准确性
  • 广义后训练量化 (GPTQ) 是一种为生成式预训练 Transformer (GPT) 模型设计的后训练量化技术。它将模型的权重量化为较低的位宽(例如 4 位整数),以减少内存使用和计算需求,而不会显着影响模型的准确性。此技术独立量化权重矩阵的每一行,以找到最小化误差的权重版本

⚗️ 使用 Olive 运行实验

为了回答关于量化和微调正确顺序的问题,我们利用了 Olive (ONNX Live) - 一个先进的模型优化工具包,旨在简化使用 ONNX Runtime 优化 AI 模型以进行部署的过程。

注意:量化和微调都需要在 Nvidia A10 或 A100 GPU 机器上运行。

1. 💾 安装 Olive

我们使用 pip 安装了 Olive CLI

pip install olive-ai[finetune]
pip install autoawq
pip install auto-gptq

2. 🗜️ 量化

我们使用 AWQ 和 GPTQ 算法量化 Phi-3.5-mini-instruct,Olive 命令如下

# AWQ Quantization
olive quantize \
  --algorithm awq \
  --model_name_or_path microsoft/Phi-3.5-mini-instruct \
  --output_path models/phi-awq

# GPTQ Quantization
olive quantize \
  --algorithm gptq \
  --model_name_or_path microsoft/Phi-3.5-mini-instruct \
  --data_name wikitext \
  --subset wikitext-2-raw-v1 \
  --split train \
  --max_samples 128 \
  --output_path models/phi-gptq 

3. 🎚️ 微调

我们使用来自 Hugging Face 的 tiny codes 数据集微调量化模型。这是一个门控数据集,您需要请求访问权限。获得访问权限后,您应该使用您的 访问令牌 登录 Hugging Face

huggingface-clu login --token TOKEN

Olive 可以使用以下命令进行微调

# Finetune AWQ model
olive finetune \
  --model_name_or_path models/phi-awq \
  --data_name nampdn-ai/tiny-codes \
  --train_split "train[:4096]" \
  --eval_split "train[4096:4224]" \
  --text_template "### Language: {programming_language} \n### Question: {prompt} \n### Answer: {response}" \
  --per_device_train_batch_size 16 \
  --per_device_eval_batch_size 16 \
  --max_steps 100 \
  --logging_steps 25 \
  --output_path models/phi-awq-ft

# Finetune GPTQ model
olive finetune \
  --model_name_or_path models/phi-gptq \
  --data_name nampdn-ai/tiny-codes \
  --train_split "train[:4096]" \
  --eval_split "train[4096:4224]" \
  --text_template "### Language: {programming_language} \n### Question: {prompt} \n### Answer: {response}" \
  --per_device_train_batch_size 16 \
  --per_device_eval_batch_size 16 \
  --max_steps 100 \
  --logging_steps 25 \
  --output_path models/phi-gptq-ft

注意:我们也做了相反的顺序,即先进行微调,然后再运行量化。它们是相同的命令,但顺序不同。

4. 🎯 运行困惑度

我们使用 Olive 在模型上运行了 困惑度指标。首先,我们在名为 perplexity-config.yaml 的文件中定义了以下 Olive 配置,该文件使用了 Olive 的评估功能

input_model:
  type: HfModel
  model_path: models/phi-awq-ft/model
  adapter_path: models/phi-awq-ft/adapter
systems:
  local_system:
    type: LocalSystem
    accelerators:
      - device: gpu
        execution_providers:
          - CUDAExecutionProvider
data_configs:
  - name: tinycodes_ppl
    type: HuggingfaceContainer
    load_dataset_config:
      data_name: nampdn-ai/tiny-codes
      split: 'train[5000:6000]'
    pre_process_data_config:
      text_template: |-
        ### Language: {programming_language}
        ### Question: {prompt}
        ### Answer: {response}
      strategy: line-by-line
      max_seq_len: 1024
    dataloader_config:
      batch_size: 8
evaluators:
  common_evaluator:
    metrics:
      - name: tinycodes_ppl
        type: accuracy
        sub_types:
          - name: perplexity
        data_config: tinycodes_ppl
passes: {}
auto_optimizer_config:
  disable_auto_optimizer: true
evaluator: common_evaluator
host: local_system
target: local_system
output_dir: models/eval

注意:我们为其他模型定义了相同的配置,但更新了 input_model

然后我们使用以下命令执行了 Olive 配置

olive run --config perplexity-config.yaml

📊 结果

Phi-3.5-Mini-Instruct

下图显示了以下模型的困惑度指标

  1. 不同的量化和微调顺序(品红色)
  2. Phi-3.5-Mini-Instruct 基础模型(绿色虚线),未量化
  3. Phi-3.5-Mini-Instruct 微调模型(绿色实线),未量化
Perplexity metrics for Phi-3.5

目标是让量化模型尽可能接近微调模型(绿色实线)。有几个要点

  • 量化对模型质量没有显着影响 - 从量化模型的困惑度分数与微调基础模型的接近程度可以看出。
  • 微调之前量化确实比在微调之后量化产生更好的结果。
  • 在这种情况下,GPTQ 比 AWQ 提供更好的准确性。

Llama-3.1-8B-Instruct

下图显示了以下模型的困惑度指标

  1. 不同的量化和微调顺序(蓝色)
  2. Llama-3.1-8B-Instruct 基础模型(绿色虚线),未量化
  3. Llama-3.1-8B-Instruct 微调模型(绿色实线),未量化
Perplexity metrics for Llama-3.1-8B-Instruct

目标是让量化模型尽可能接近微调模型(绿色实线)。有几个要点

  • 量化对模型质量没有显着影响 - 从量化模型的困惑度分数与微调基础模型的接近程度可以看出。
  • 微调之前量化确实比在微调之后量化产生更好的结果。
  • GPTQ 和 AWQ 给出相似的模型质量结果。

结论

在这篇博文中,我们演示了如何利用 Olive 来解决常见的 AI 模型优化查询。我们的研究结果表明,对于 Phi-3.5-mini-instruct 和 Llama-3.1-8B-Instruct,在微调之前量化可以提高模型质量。这些量化变体在质量上与全精度 (FP32) 同类产品非常接近,同时需要的内存和存储空间更少。这突显了设备上 AI 在减少资源占用空间的同时提供高质量性能的潜力。