PEFT 文档

量化

Hugging Face's logo
加入 Hugging Face 社区

并获得增强的文档体验

开始使用

量化

量化用更少的比特位表示数据,使其成为减少内存使用和加速推理的有用技术,尤其是在大型语言模型 (LLM) 方面。 量化模型的方法有几种,包括

  • 使用 AWQ 算法优化量化的模型权重
  • 使用 GPTQ 算法独立量化权重矩阵的每一行
  • 使用 bitsandbytes 库量化到 8 位和 4 位精度
  • 使用 AQLM 算法量化到低至 2 位的精度

然而,模型量化后通常不会针对下游任务进行进一步训练,因为权重和激活的精度较低会导致训练不稳定。 但是,由于 PEFT 方法仅添加额外的可训练参数,这使您可以在量化模型之上训练 PEFT 适配器! 将量化与 PEFT 结合使用可能是单 GPU 上训练最大模型的良好策略。 例如,QLoRA 是一种将模型量化为 4 位,然后使用 LoRA 进行训练的方法。 此方法允许您在单个 48GB GPU 上微调 65B 参数模型!

在本指南中,您将了解如何将模型量化为 4 位并使用 LoRA 进行训练。

量化模型

bitsandbytes 是一个量化库,集成了 Transformers。 通过这种集成,您可以将模型量化为 8 位或 4 位,并通过配置 BitsAndBytesConfig 类启用许多其他选项。 例如,您可以

  • 设置 load_in_4bit=True 以在加载模型时将其量化为 4 位
  • 设置 bnb_4bit_quant_type="nf4" 以对从正态分布初始化的权重使用特殊的 4 位数据类型
  • 设置 bnb_4bit_use_double_quant=True 以使用嵌套量化方案来量化已量化的权重
  • 设置 bnb_4bit_compute_dtype=torch.bfloat16 以使用 bfloat16 进行更快的计算
import torch
from transformers import BitsAndBytesConfig

config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_quant_type="nf4",
    bnb_4bit_use_double_quant=True,
    bnb_4bit_compute_dtype=torch.bfloat16,
)

config 传递给 from_pretrained 方法。

from transformers import AutoModelForCausalLM

model = AutoModelForCausalLM.from_pretrained("mistralai/Mistral-7B-v0.1", quantization_config=config)

接下来,您应该调用 prepare_model_for_kbit_training() 函数来预处理量化模型以进行训练。

from peft import prepare_model_for_kbit_training

model = prepare_model_for_kbit_training(model)

现在量化模型已准备就绪,让我们设置一个配置。

LoraConfig

使用以下参数创建 LoraConfig(或选择您自己的参数)

from peft import LoraConfig

config = LoraConfig(
    r=16,
    lora_alpha=8,
    target_modules=["q_proj", "k_proj", "v_proj", "o_proj"],
    lora_dropout=0.05,
    bias="none",
    task_type="CAUSAL_LM"
)

然后使用 get_peft_model() 函数从量化模型和配置创建 PeftModel

from peft import get_peft_model

model = get_peft_model(model, config)

您已准备好使用您喜欢的任何训练方法进行训练!

LoftQ 初始化

LoftQ 初始化 LoRA 权重,以最大程度地减少量化误差,并且可以在训练量化模型时提高性能。 要开始使用,请按照 这些说明 进行操作。

总的来说,为了使 LoftQ 效果最佳,建议尽可能多地使用 LoRA 定位层,因为未定位的层无法应用 LoftQ。 这意味着传递 LoraConfig(..., target_modules="all-linear") 最有可能产生最佳结果。 此外,当使用 4 位量化时,您应该在量化配置中使用 nf4 作为量化类型,即 BitsAndBytesConfig(load_in_4bit=True, bnb_4bit_quant_type="nf4")

QLoRA 风格的训练

QLoRA 将可训练权重添加到 transformer 架构中的所有线性层。 由于这些线性层的属性名称可能因架构而异,因此将 target_modules 设置为 "all-linear" 以将 LoRA 添加到所有线性层

config = LoraConfig(target_modules="all-linear", ...)

GPTQ 量化

您可以在 GPTQModel 和 Transformers GPTQ 文档中了解有关基于 gptq 的 [2, 3, 4, 8] 位量化的更多信息。 量化后训练,PEFT 可以使用 GPTQModelAutoGPTQ 库,但我们建议使用 GPTQModel,因为 AutoGPTQ 将在未来版本中弃用。

# gptqmodel install
pip install gptqmodel --no-build-isolation
from transformers import AutoModelForCausalLM, AutoTokenizer, GPTQConfig

model_id = "facebook/opt-125m"
tokenizer = AutoTokenizer.from_pretrained(model_id)

gptq_config = GPTQConfig(bits=4, group_size=128, dataset="wikitext2", tokenizer=tokenizer)

quantized_model = AutoModelForCausalLM.from_pretrained(model_id, device_map="auto", quantization_config=gptq_config)

# save quantized model
quantized_model.save_pretrained("./opt-125m-gptq")
tokenizer.save_pretrained("./opt-125m-gptq")

量化后,您可以使用 PEFT API 对 GPTQ 模型进行后训练。

AQLM 量化

语言模型加法量化 (AQLM) 是一种大型语言模型压缩方法。 它将多个权重一起量化,并利用它们之间的相互依赖性。 AQLM 将 8-16 个权重的组表示为多个向量代码的总和。 这使其可以将模型压缩到低至 2 位,而精度损失却非常低。

由于 AQLM 量化过程计算量很大,因此建议使用预量化模型。 可用模型的部分列表可以在官方 aqlm 存储库中找到。

这些模型支持 LoRA 适配器微调。 要微调量化模型,您需要安装 aqlm 推理库:pip install aqlm>=1.0.2。 微调后的 LoRA 适配器应单独保存,因为无法将它们与 AQLM 量化权重合并。

quantized_model = AutoModelForCausalLM.from_pretrained(
    "BlackSamorez/Mixtral-8x7b-AQLM-2Bit-1x16-hf-test-dispatch",
    torch_dtype="auto", device_map="auto", low_cpu_mem_usage=True,
)

peft_config = LoraConfig(...)

quantized_model = get_peft_model(quantized_model, peft_config)

您可以参考 Google Colab 示例,了解 AQLM+LoRA 微调的概述。

EETQ 量化

您还可以在 EETQ 量化模型上执行 LoRA 微调。 EETQ 包提供了一种简单有效的方法来执行 8 位量化,据称该方法比 LLM.int8() 算法更快。 首先,确保您拥有与 EETQ 兼容的 transformers 版本(例如,从最新的 pypi 或源代码安装)。

import torch
from transformers import EetqConfig

config = EetqConfig("int8")

config 传递给 from_pretrained 方法。

from transformers import AutoModelForCausalLM

model = AutoModelForCausalLM.from_pretrained("mistralai/Mistral-7B-v0.1", quantization_config=config)

并创建一个 LoraConfig 并将其传递给 get_peft_model

from peft import LoraConfig, get_peft_model

config = LoraConfig(
    r=16,
    lora_alpha=8,
    target_modules=["q_proj", "k_proj", "v_proj", "o_proj"],
    lora_dropout=0.05,
    bias="none",
    task_type="CAUSAL_LM"
)

model = get_peft_model(model, config)

HQQ 量化

使用大型机器学习模型半二次方量化 (HQQ) 量化的模型支持 LoRA 适配器微调。 要微调量化模型,您需要安装 hqq 库:pip install hqq

from hqq.engine.hf import HQQModelForCausalLM

quantized_model = HQQModelForCausalLM.from_quantized(save_dir_or_hfhub, device='cuda')
peft_config = LoraConfig(...)
quantized_model = get_peft_model(quantized_model, peft_config)

或者使用与 HQQ 兼容的 transformers 版本(例如,从最新的 pypi 或源代码安装)。

from transformers import HqqConfig, AutoModelForCausalLM

quant_config = HqqConfig(nbits=4, group_size=64)
quantized_model = AutoModelForCausalLM.from_pretrained(save_dir_or_hfhub, device_map=device_map, quantization_config=quant_config)
peft_config = LoraConfig(...)
quantized_model = get_peft_model(quantized_model, peft_config)

torchao (PyTorch 架构优化)

PEFT 支持使用 torchao (“ao”) 量化的 int8 量化模型。

from peft import LoraConfig, get_peft_model
from transformers import AutoModelForCausalLM, TorchAoConfig

model_id = ...
quantization_config = TorchAoConfig(quant_type="int8_weight_only")
base_model = AutoModelForCausalLM.from_pretrained(model_id, quantization_config=quantization_config)
peft_config = LoraConfig(...)
model = get_peft_model(base_model, peft_config)

注意事项:

  • 使用最新版本的 torchao (>= v0.4.0) 和 transformers (> 4.42)。
  • 目前仅支持线性层。
  • 目前不支持 quant_type = "int4_weight_only"
  • NF4 尚未在 transformers 中实现,因此也不支持。
  • 目前,DoRA 仅适用于 quant_type = "int8_weight_only"
  • 当与 LoRA 一起使用时,torchao 具有显式支持。 但是,当 torchao 量化层时,其类不会更改,只会更改底层张量的类型。 因此,LoRA 以外的 PEFT 方法通常也适用于 torchao,即使未明确支持也是如此。 但是请注意,合并仅在 LoRA 和 quant_type = "int8_weight_only" 的情况下才能正确工作。 如果您使用不同的 PEFT 方法或 dtype,合并很可能会导致错误,即使没有错误,结果仍然不正确。

其他支持的 PEFT 方法

除了 LoRA 之外,以下 PEFT 方法也支持量化

  • VeRA(支持 bitsandbytes 量化)
  • AdaLoRA(同时支持 bitsandbytes 和 GPTQ 量化)
  • (IA)³(支持 bitsandbytes 量化)

下一步

如果您有兴趣了解有关量化的更多信息,以下内容可能会有所帮助

< > 在 GitHub 上更新