量化HuggingFace的Transformers 模型

量化 Transformers 模型

原文地址:https://huggingface.co/docs/transformers/main/en/main_classes/quantization

AutoGPTQ 集成

Transformers 已集成了 optimum API 以对语言模型执行 GPTQ 量化。您可以在不大幅降低性能并提高推理速度的情况下,以 8、6、4 甚至 2 位加载并量化您的模型!大多数 GPU 硬件都支持这一功能。

要了解有关量化模型的更多信息,请查阅:

  • GPTQ 论文
  • 作为后端使用的 AutoGPTQ

依赖库

要运行下面的代码,您需要安装以下依赖库:

  • 安装最新的 AutoGPTQ
    pip install auto-gptq

  • 从源安装最新的 optimum
    pip install git+https://github.com/huggingface/optimum.git

  • 从源安装最新的 transformers
    pip install git+https://github.com/huggingface/transformers.git

  • 安装最新的 accelerate
    pip install --upgrade accelerate
    目前,GPTQ 集成仅支持文本模型,对于视觉、语音或多模态模型,您可能会遇到意外的行为。

加载并量化模型

GPTQ 是一种量化方法,需要在使用量化模型之前进行权重校准。如果您想从头开始量化 transformers 模型,可能需要一些时间才能产生量化模型(在 Google colab 上为 facebook/opt-350m 模型大约需要 10 分钟)。

因此,您可能会遇到两种使用GPTQ-量化模型的场景。第一种情况是加载已经被其他用户量化并上传到Hub的模型;第二种情况是从零开始量化您自己的模型,并保存或上传到Hub,这样其他用户也能使用它。

GPTQ 配置

为了加载并量化模型,您需要创建一个 [GPTQConfig]。您需要传递 bits 的数量,一个 dataset 以校准量化和模型的 tokenizer 以准备数据集。

model_id = "facebook/opt-125m"
tokenizer = AutoTokenizer.from_pretrained(model_id)
gptq_config = GPTQConfig(bits=4, dataset = "c4", tokenizer=tokenizer)

请注意,您可以将自己的数据集作为字符串列表传递。但强烈建议使用 GPTQ 论文中的数据集。

dataset = ["auto-gptq 是一个基于 GPTQ 算法的易于使用的模型量化库,具有用户友好的 api。"]
quantization = GPTQConfig(bits=4, dataset = dataset, tokenizer=tokenizer)
量化

您可以通过使用 from_pretrained 并设置 quantization_config 来量化模型。

from transformers import AutoModelForCausalLM
model = AutoModelForCausalLM.from_pretrained(model_id, quantization_config=gptq_config)

请注意,您需要一个GPU来进行模型的量化。我们会将模型放置在CPU中,并在GPU和CPU之间来回移动各个模块以进行量化。

如果您想在使用CPU offload的同时最大化您的GPU使用率,您可以设置 device_map = "auto"

from transformers import AutoModelForCausalLM
model = AutoModelForCausalLM.from_pretrained(model_id, device_map="auto", quantization_config=gptq_config)

请注意,不支持磁盘 offload。此外,如果由于数据集而导致内存不足,您可能需要在 from_pretained 中传递 max_memory。查看此指南以了解有关 device_mapmax_memory 的更多信息。

目前,GPTQ 量化仅适用于文本模型。此外,根据硬件,量化过程可能需要很长时间(使用 NVIDIA A100 的 175B 模型 = 4 个 GPU 小时)。请检查 Hub 上是否有该模型的 GPTQ 量化版本。如果没有,您可以在 github 上提交需求。

将量化模型推送到 Hub

您可以使用 push_to_hub 将量化模型推送到 Hub,就像任何 模型一样。量化配置将与模型一起保存并推送。

quantized_model.push_to_hub("opt-125m-gptq")
tokenizer.push_to_hub("opt-125m-gptq")

如果您想将您的量化模型保存到本地计算机,您也可以使用 save_pretrained

quantized_model.save_pretrained("opt-125m-gptq")
tokenizer.save_pretrained("opt-125m-gptq")

如果您已使用device_map量化了您的模型,在保存之前,请确保将整个模型移动到您的GPU之一或cpu上。

quantized_model.to("cpu")
quantized_model.save_pretrained("opt-125m-gptq")

从 Hub加载量化模型

您可以使用from_pretrained从Hub加载量化模型。
确保已推送的权重已量化,通过检查模型配置对象中是否存在quantization_config属性。

from transformers import AutoModelForCausalLM
model = AutoModelForCausalLM.from_pretrained("{your_username}/opt-125m-gptq")

如果您希望更快地加载模型并且不分配比所需更多的内存,device_map参数也适用于量化模型。确保您已安装accelerate库。

from transformers import AutoModelForCausalLM
model = AutoModelForCausalLM.from_pretrained("{your_username}/opt-125m-gptq", device_map="auto")

Exllama核心用于更快的推理

对于4位模型,您可以使用exllama核心以获得更快的推理速度。它默认是激活的。您可以通过在[GPTQConfig]中传递disable_exllama来改变这种行为。这将覆盖存储在配置中的量化配置。请注意,您只能覆盖与核心相关的属性。此外,如果您想使用exllama核心,您需要将整个模型放在gpu上。

import torch
gptq_config = GPTQConfig(bits=4, disable_exllama=False)
model = AutoModelForCausalLM.from_pretrained("{your_username}/opt-125m-gptq", device_map="auto", quantization_config = gptq_config)

请注意,现在只支持4位模型。此外,如果您正在使用peft微调量化模型,建议禁用exllama核心。

微调量化模型

借助Hugging Face生态系统中对适配器的官方支持,您可以微调已使用GPTQ量化的模型。
请查看peft库以获取更多详细信息。

示例演示

查看Google Colab 笔记本 以学习如何使用GPTQ量化您的模型以及如何使用peft微调量化模型。

GPTQConfig

[[autodoc]] GPTQConfig

bitsandbytes 集成

Transformers与bitsandbytes上最常用的模块紧密集成。您只需几行代码即可以8位精度加载模型。
0.37.0版本发布以来,大多数GPU硬件都支持此功能。

在LLM.int8() 论文或关于合作的博客文章中了解更多关于量化方法的信息。

自其0.39.0版本发布以来,您可以使用4位量化加载任何支持device_map的模型,利用FP4数据类型。

如果您想量化自己的pytorch模型,请查看来自 Accelerate库的文档。

以下是您可以使用bitsandbytes集成完成的操作:

通用使用

只要您的模型支持使用 Accelerate加载并包含torch.nn.Linear层,您就可以在调用[~PreTrainedModel.from_pretrained]方法时使用load_in_8bitload_in_4bit参数来量化模型。这应适用于任何模式。

from transformers import AutoModelForCausalLM

model_8bit = AutoModelForCausalLM.from_pretrained("facebook/opt-350m", load_in_8bit=True)
model_4bit = AutoModelForCausalLM.from_pretrained("facebook/opt-350m", load_in_4bit=True)

默认情况下,所有其他模块(例如torch.nn.LayerNorm)将转换为torch.float16,但如果您想更改其dtype,则可以覆盖torch_dtype参数:

>>> import torch
>>> from transformers import AutoModelForCausalLM

>>> model_8bit = AutoModelForCausalLM.from_pretrained("facebook/opt-350m", load_in_8bit=True, torch_dtype=torch.float32)
>>> model_8bit.model.decoder.layers[-1].final_layer_norm.weight.dtype
torch.float32

FP4 量化

要求

在运行以下任何代码片段之前,请确保已经安装了以下要求。

  • 最新的 bitsandbytes
    pip install bitsandbytes>=0.39.0

  • 安装最新的 accelerate
    pip install --upgrade accelerate

  • 安装最新的 transformers
    pip install --upgrade transformers

提示和最佳实践
  • 高级使用: 参考这个Google Colab笔记本以了解4位量化的高级用法以及所有可能的选项。

  • batch_size=1的更快推理: 从bitsandbytes的0.40.0版本开始,对于batch_size=1,你可以受益于快速推理。查看这些发布说明,确保版本大于0.40.0,以便开箱即用地使用此功能。

  • 训练: 根据QLoRA论文,对于训练4位基础模型(例如使用LoRA适配器),应使用bnb_4bit_quant_type='nf4'

  • 推理: 对于推理,bnb_4bit_quant_type对性能影响不大。但为了与模型权重的一致性,请确保使用相同的bnb_4bit_compute_dtypetorch_dtype参数。

以4bit加载大型模型

使用load_in_4bit=True调用 .from_pretrained 方法时,您可以将内存使用量减少4倍(大致)。

# pip install transformers accelerate bitsandbytes
from transformers import AutoModelForCausalLM, AutoTokenizer

model_id = "bigscience/bloom-1b7"

tokenizer = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForCausalLM.from_pretrained(model_id, device_map="auto", load_in_4bit=True)

请注意,一旦以4位加载了模型,目前无法将量化权重推送到Hub。还要注意,目前还不支持训练4位权重。但是您可以使用4位模型来训练额外的参数,这将在下一节中介绍。

以8bit加载大型模型

您可以通过使用load_in_8bit=True参数调用 .from_pretrained 方法大致将内存需求减半。

# pip install transformers accelerate bitsandbytes
from transformers import AutoModelForCausalLM, AutoTokenizer

model_id = "bigscience/bloom-1b7"

tokenizer = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForCausalLM.from_pretrained(model_id, device_map="auto", load_in_8bit=True)

然后,像通常使用[PreTrainedModel]一样使用你的模型。

你可以使用get_memory_footprint方法检查你的模型的内存占用。

print(model.get_memory_footprint())

通过这种集成,我们能够在较小的设备上加载大型模型并毫无问题地运行它们。

请注意,一旦模型已经以8位加载,目前无法将量化权重推送到Hub,除非您使用最新的transformersbitsandbytes。还要注意,目前还不支持训练8位权重。但是您可以使用8位模型来训练额外的参数,这将在下一节中介绍。
还要注意,device_map是可选的,但是设置device_map = 'auto'是推荐的,因为它会高效地将模型分派到可用的资源上。

高级用例

在这里,我们将介绍您可以使用FP4量化执行的一些高级用例。

改变计算数据类型

计算数据类型用于改变计算期间使用的数据类型。例如,隐藏状态可以是float32,但计算可以设置为bf16以加速。默认情况下,计算数据类型设置为float32

import torch
from transformers import BitsAndBytesConfig

quantization_config = BitsAndBytesConfig(load_in_4bit=True, bnb_4bit_compute_dtype=torch.bfloat16)
使用NF4(Normal Float 4)数据类型

你还可以使用NF4数据类型,这是一种新的4位数据类型,适用于使用正态分布初始化的权重。为此运行:

from transformers import BitsAndBytesConfig

nf4_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_quant_type="nf4",
)

model_nf4 = AutoModelForCausalLM.from_pretrained(model_id, quantization_config=nf4_config)
使用嵌套量化进行更高效的内存推理

我们还建议用户使用嵌套量化技术。这可以节省更多的内存,而不需要额外的性能 - 根据我们的经验观察,这使得在NVIDIA-T4 16GB上以序列长度为1024、批量大小为1和梯度积累步骤为4进行微调llama-13b模型成为可能。

from transformers import BitsAndBytesConfig

double_quant_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_use_double_quant=True,
)

model_double_quant = AutoModelForCausalLM.from_pretrained(model_id, quantization_config=double_quant_config)

将量化模型推送到 Hub

您可以通过简单地使用 push_to_hub 方法将一个量化模型推送到 Hub。这将首先推送量化配置文件,然后推送量化的模型权重。确保使用 bitsandbytes>0.37.2 (在撰写本文时,我们在 bitsandbytes==0.38.0.post1 上测试过)来使用此功能。

from transformers import AutoModelForCausalLM, AutoTokenizer

model = AutoModelForCausalLM.from_pretrained("bigscience/bloom-560m", device_map="auto", load_in_8bit=True)
tokenizer = AutoTokenizer.from_pretrained("bigscience/bloom-560m")

model.push_to_hub("bloom-560m-8bit")

强烈建议将8位模型推送到 Hub,尤其是大型模型。这将允许社区从内存占用减少中受益,并例如在 Google Colab 上加载大型模型。

从 Hub 加载一个量化模型

您可以使用 from_pretrained 方法从 Hub 加载一个量化模型。确保推送的权重是量化的,通过检查模型配置对象中是否存在 quantization_config 属性。

from transformers import AutoModelForCausalLM, AutoTokenizer

model = AutoModelForCausalLM.from_pretrained("{your_username}/bloom-560m-8bit", device_map="auto")

注意,在这种情况下,您不需要指定 load_in_8bit=True 参数,但您需要确保已安装 bitsandbytesaccelerate。同样注意,device_map 是可选的,但设置 device_map = 'auto' 在推理时是首选,因为它会有效地将模型分派到可用的资源上。

高级用例

本节面向希望探索除了加载和运行8位模型之外还可以做什么的高级用户。

cpugpu 之间进行卸载

这其中的一个高级用例是能够加载一个模型并在 CPUGPU 之间分派权重。请注意,将在 CPU 上分派的权重不会被转换为8位,因此保持为 float32。此功能面向希望适应非常大的模型并在 GPU 和 CPU 之间分派模型的用户。

首先,从 transformers 加载一个 [BitsAndBytesConfig],并将属性 llm_int8_enable_fp32_cpu_offload 设置为 True

from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig

quantization_config = BitsAndBytesConfig(llm_int8_enable_fp32_cpu_offload=True)

假设您想加载 bigscience/bloom-1b7 模型,而您的 GPU RAM 只足够适应整个模型,除了 lm_head。因此,如下所示编写一个自定义的 device_map:

device_map = {
    "transformer.word_embeddings": 0,
    "transformer.word_embeddings_layernorm": 0,
    "lm_head": "cpu",
    "transformer.h": 0,
    "transformer.ln_f": 0,
}

然后如下加载您的模型:

model_8bit = AutoModelForCausalLM.from_pretrained(
    "bigscience/bloom-1b7",
    device_map=device_map,
    quantization_config=quantization_config,
)

就是这样!尽情享受您的模型吧!

使用 llm_int8_threshold 进行玩耍

您可以使用 llm_int8_threshold 参数更改离群值的阈值。"离群值"是一个隐藏状态值,大于某个阈值。这对应于 LLM.int8() 论文中描述的离群值检测的离群值阈值。任何超过此阈值的隐藏状态值都将被视为离群值,这些值上的操作将以 fp16 进行。值通常呈正态分布,即大多数值在范围 [-3.5, 3.5] 内,但对于大型模型,有一些特殊的系统性离群值分布非常不同。这些离群值通常在区间 [-60, -6] 或 [6, 60] 内。Int8 量化对于大约为5的值工作得很好,但超过此值,性能将受到重大影响。一个好的默认阈值是6,但更不稳定的模型(小模型,微调)可能需要较低的阈值。这个参数可能会影响模型的推理速度。我们建议您玩弄这个参数,找

到最适合您用例的值。

from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig

model_id = "bigscience/bloom-1b7"

quantization_config = BitsAndBytesConfig(
    llm_int8_threshold=10,
)

model_8bit = AutoModelForCausalLM.from_pretrained(
    model_id,
    device_map=device_map,
    quantization_config=quantization_config,
)
tokenizer = AutoTokenizer.from_pretrained(model_id)
跳过某些模块的转换

有些模型有几个模块需要不转换为8位以确保稳定性。例如 Jukebox 模型有几个 lm_head 模块应该被跳过。使用 llm_int8_skip_modules 进行玩耍:

from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig

model_id = "bigscience/bloom-1b7"

quantization_config = BitsAndBytesConfig(
    llm_int8_skip_modules=["lm_head"],
)

model_8bit = AutoModelForCausalLM.from_pretrained(
    model_id,
    device_map=device_map,
    quantization_config=quantization_config,
)
tokenizer = AutoTokenizer.from_pretrained(model_id)
微调已加载为8位的模型

凭借 Hugging Face 生态系统对适配器的官方支持,您可以微调已加载为8位的模型。这使得在单个 Google Colab 中微调大型模型,如 flan-t5-largefacebook/opt-6.7b 成为可能。请查看 peft 库以获取更多详细信息。

注意,加载模型进行训练时,您不需要传递 device_map。它将自动在您的 GPU 上加载您的模型。如有需要,您还可以将 device map 设置为特定的设备(例如 cuda:00torch.device('cuda:0'))。请注意,device_map=auto 仅用于推理。

BitsAndBytesConfig

[[autodoc]] BitsAndBytesConfig

使用 optimum 进行量化

请查看 Optimum 文档 以了解 optimum 支持的量化方法,并查看这些是否适用于您的用例。

你可能感兴趣的:(python,模型量化,huggingface,NLP,自然语言处理,大语言模型)