Transformers 文档

Bitsandbytes

Hugging Face's logo
加入 Hugging Face 社区

并获得增强的文档体验

开始使用

Bitsandbytes

bitsandbytes 库通过 CUDA 函数的轻量级 Python 包装器,为 LLM 提供了量化工具。它通过减少内存占用,使得使用有限计算资源处理大型模型成为可能。

bitsandbytes 的核心功能包括:

  • 量化线性层:`Linear8bitLt` 和 `Linear4bit` 层取代了标准的 PyTorch 线性层,提供了内存效率更高的量化替代方案。
  • 优化器优化:通过其 `optim` 模块提供常见优化器的 8 位版本,从而能够以更低的内存需求训练大型模型。
  • 矩阵乘法:利用量化格式优化的矩阵乘法操作。

bitsandbytes 提供两个主要量化功能:

  1. LLM.int8() - 一种 8 位量化方法,使推理更易于访问,而不会显著降低性能。与朴素量化不同,LLM.int8() 动态地为关键计算保留更高的精度,防止模型敏感部分的 R 息丢失。

  2. QLoRA - 一种 4 位量化技术,通过插入少量可训练的低秩适应 (LoRA) 权重,进一步压缩模型,同时保持可训练性。

注意: 如需用户友好的量化体验,您可以使用 `bitsandbytes` 社区空间

运行以下命令安装 bitsandbytes。

pip install --upgrade transformers accelerate bitsandbytes

要从源代码编译,请遵循 bitsandbytes 安装指南 中的说明。

硬件兼容性

bitsandbytes 目前仅支持 CUDA 版本 11.0 - 12.8 的 CUDA GPU。但是,一项多后端工作正在开发中,目前处于 Alpha 阶段。如果您有兴趣提供反馈或进行测试,请查看 bitsandbytes 仓库 获取更多信息。

CUDA

特性 最低硬件要求
8 位优化器 NVIDIA Maxwell (GTX 900 系列, TITAN X, M40) 或更新的 GPU *
LLM.int8() NVIDIA Turing (RTX 20 系列, T4) 或更新的 GPU
NF4/FP4 量化 NVIDIA Maxwell (GTX 900 系列, TITAN X, M40) 或更新的 GPU *

多后端

后端 支持版本 Python 版本 架构支持 状态
AMD ROCm 6.1+ 3.10+ 最低 CDNA - gfx90a, RDNA - gfx1100 Alpha
Apple Silicon (MPS) 进行中 3.10+ M1/M2 芯片 计划中
Intel CPU v2.4.0+ (ipex) 3.10+ Intel CPU Alpha
英特尔 GPU v2.4.0+ (ipex) 3.10+ 英特尔 GPU 实验性
Ascend NPU 2.1.0+ (torch_npu) 3.10+ Ascend NPU 实验性

注意: Bitsandbytes 正在从多后端方法转向使用 Pytorch Custom Operators,作为支持新硬件和分派到正确后端的主要机制。

量化示例

通过将 BitsAndBytesConfig 传递给 from_pretrained() 来量化模型。只要模型支持 Accelerate 并且包含 torch.nn.Linear 层,此方法适用于任何模态的任何模型。

8位
4位
将模型量化为 8 位可将内存使用量减半,对于大型模型,设置 `device_map="auto"` 可有效将权重分布到所有可用的 GPU 上。
from transformers import AutoModelForCausalLM, BitsAndBytesConfig

quantization_config = BitsAndBytesConfig(load_in_8bit=True)

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

默认情况下,所有其他模块(如 torch.nn.LayerNorm)都设置为默认的 torch dtype。您可以使用 `torch_dtype` 参数更改这些模块的数据类型。设置 `torch_dtype="auto"` 会以模型 `config.json` 文件中定义的数据类型加载模型。

import torch
from transformers import AutoModelForCausalLM, BitsAndBytesConfig

quantization_config = BitsAndBytesConfig(load_in_8bit=True)

model_8bit = AutoModelForCausalLM.from_pretrained(
    "facebook/opt-350m", 
    device_map="auto",
    quantization_config=quantization_config, 
    torch_dtype="auto"
)
model_8bit.model.decoder.layers[-1].final_layer_norm.weight.dtype

一旦模型被量化为 8 位,除非您使用的是最新版本的 Transformers 和 bitsandbytes,否则无法将量化后的权重推送到 Hub。如果您有最新版本,则可以使用 push_to_hub() 将 8 位模型推送到 Hub。量化 config.json 文件首先被推送,然后是量化后的模型权重。

from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig

quantization_config = BitsAndBytesConfig(load_in_8bit=True)

model = AutoModelForCausalLM.from_pretrained(
    "bigscience/bloom-560m", 
    device_map="auto",
    quantization_config=quantization_config
)

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

8 位和 4 位训练仅支持训练*额外*参数。

使用 `get_memory_footprint` 检查您的内存占用。

print(model.get_memory_footprint())

使用 from_pretrained() 加载量化模型,无需 `quantization_config`。

from transformers import AutoModelForCausalLM, AutoTokenizer

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

LLM.int8

本节探讨 8 位量化的一些特定功能,例如卸载、离群值阈值、跳过模块转换和微调。

卸载

8 位模型可以在 CPU 和 GPU 之间卸载权重,以将非常大的模型适应内存。调度到 CPU 的权重以 float32 存储,不会转换为 8 位。例如,通过 BitsAndBytesConfigbigscience/bloom-1b7 启用卸载。

from transformers import AutoModelForCausalLM, BitsAndBytesConfig

quantization_config = BitsAndBytesConfig(llm_int8_enable_fp32_cpu_offload=True)

设计一个自定义设备映射,将所有内容都放在 GPU 上,除了 `lm_head`,它被调度到 CPU。

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

现在,使用自定义 `device_map` 和 `quantization_config` 加载您的模型。

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

离群值阈值

“异常值”是指超过某个阈值的隐藏状态值,这些值以 fp16 形式计算。虽然这些值通常呈正态分布([-3.5, 3.5]),但对于大型模型,此分布可能非常不同([-60, 6] 或 [6, 60])。8 位量化对于 ~5 的值效果很好,但超出此范围,性能会显著下降。一个好的默认阈值是 6,但对于更不稳定的模型(小型模型或微调),可能需要更低的阈值。

要为您的模型找到最佳阈值,请在 BitsAndBytesConfig 中尝试使用 `llm_int8_threshold` 参数。例如,将阈值设置为 `0.0` 可以显著加快推理速度,但可能会损失一些准确性。

from transformers import AutoModelForCausalLM, BitsAndBytesConfig

model_id = "bigscience/bloom-1b7"

quantization_config = BitsAndBytesConfig(
    llm_int8_threshold=0.0,
    llm_int8_enable_fp32_cpu_offload=True
)

model_8bit = AutoModelForCausalLM.from_pretrained(
    model_id,
    torch_dtype="auto",
    device_map=device_map,
    quantization_config=quantization_config,
)

跳过模块转换

对于某些模型,例如 Jukebox,您不需要将每个模块都量化为 8 位,因为这实际上可能导致不稳定。对于 Jukebox,有几个 `lm_head` 模块应该使用 BitsAndBytesConfig 中的 `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,
    torch_dtype="auto",
    device_map="auto",
    quantization_config=quantization_config,
)

微调

PEFT 库支持使用 8 位量化微调大型模型,如 flan-t5-largefacebook/opt-6.7b。您无需传递 `device_map` 参数进行训练,因为它会自动将模型加载到 GPU 上。但是,您仍然可以使用 `device_map` 参数自定义设备映射(`device_map="auto"` 仅应用于推理)。

QLoRA

本节探讨 4 位量化的一些特定功能,例如更改计算数据类型、普通浮点 4 (NF4) 数据类型和嵌套量化。

计算数据类型

更改 BitsAndBytesConfig 中的数据类型,从 float32(默认值)更改为 bf16 以加速计算。

import torch
from transformers import BitsAndBytesConfig

quantization_config = BitsAndBytesConfig(load_in_4bit=True, bnb_4bit_compute_dtype=torch.bfloat16)

普通浮点 4 (NF4)

NF4 是 QLoRA 论文中的 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, torch_dtype="auto", quantization_config=nf4_config)

对于推理,`bnb_4bit_quant_type` 对性能影响不大。但是,为了与模型权重保持一致,您应该使用 `bnb_4bit_compute_dtype` 和 `torch_dtype` 值。

嵌套量化

嵌套量化可以在不增加额外性能成本的情况下节省额外的内存。此功能对已经量化的权重执行第二次量化,以额外节省 0.4 比特/参数。例如,使用嵌套量化,您可以在具有 1024 序列长度、1 批量大小和启用 4 步梯度累积的 16GB NVIDIA T4 GPU 上微调 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("meta-llama/Llama-2-13b-chat-hf", torch_dtype="auto", quantization_config=double_quant_config)

Bitsandbytes 模型去量化

一旦量化,您可以 dequantize() 模型至原始精度,但这可能导致一些质量损失。请确保您有足够的 GPU 内存来适应去量化后的模型。

from transformers import AutoModelForCausalLM, BitsAndBytesConfig, AutoTokenizer

model = AutoModelForCausalLM.from_pretrained("facebook/opt-125m", BitsAndBytesConfig(load_in_4bit=True))
model.dequantize()

资源

使用 Hugging Face Transformers、Accelerate 和 bitsandbytes 对大型 Transformer 进行 8 位矩阵乘法的温和介绍 中了解更多关于 8 位量化的细节。

在 此 notebook 中尝试 4 位量化,并在 通过 bitsandbytes、4 位量化和 QLoRA 使 LLM 更易于访问 中了解更多细节。

< > 在 GitHub 上更新