Diffusers 文档

bitsandbytes

Hugging Face's logo
加入 Hugging Face 社区

并获得增强的文档体验

开始

bitsandbytes

bitsandbytes 是将模型量化为 8 位和 4 位的最简单选项。8 位量化将 fp16 中的异常值与 int8 中的非异常值相乘,将非异常值转换回 fp16,然后将它们加在一起以返回 fp16 中的权重。这减少了异常值对模型性能的降级影响。

4 位量化进一步压缩模型,并且通常与 QLoRA 一起用于微调量化的 LLM。

本指南演示了量化如何使 FLUX.1-dev 能够在小于 16GB VRAM 的环境中运行,甚至可以在免费的 Google Colab 实例上运行。

comparison image

要使用 bitsandbytes,请确保您已安装以下库

pip install diffusers transformers accelerate bitsandbytes -U

现在,您可以通过将 BitsAndBytesConfig 传递给 from_pretrained() 来量化模型。这适用于任何模态的任何模型,只要它支持使用 Accelerate 加载并包含 torch.nn.Linear 层。

8 位
4 位

以 8 位量化模型可将内存使用量减半

Transformers 和 Diffusers 都支持 bitsandbytes,因此您可以量化 FluxTransformer2DModelT5EncoderModel

对于 Ada 及更高系列的 GPU,我们建议将 torch_dtype 更改为 torch.bfloat16

CLIPTextModelAutoencoderKL 未被量化,因为它们本身尺寸已经很小,并且 AutoencoderKL 只有少量的 torch.nn.Linear 层。

from diffusers import BitsAndBytesConfig as DiffusersBitsAndBytesConfig
from transformers import BitsAndBytesConfig as TransformersBitsAndBytesConfig

from diffusers import FluxTransformer2DModel
from transformers import T5EncoderModel

quant_config = TransformersBitsAndBytesConfig(load_in_8bit=True,)

text_encoder_2_8bit = T5EncoderModel.from_pretrained(
    "black-forest-labs/FLUX.1-dev",
    subfolder="text_encoder_2",
    quantization_config=quant_config,
    torch_dtype=torch.float16,
)

quant_config = DiffusersBitsAndBytesConfig(load_in_8bit=True,)

transformer_8bit = FluxTransformer2DModel.from_pretrained(
    "black-forest-labs/FLUX.1-dev",
    subfolder="transformer",
    quantization_config=quant_config,
    torch_dtype=torch.float16,
)

默认情况下,所有其他模块(如 torch.nn.LayerNorm)都将转换为 torch.float16。您可以使用 torch_dtype 参数更改这些模块的数据类型。

transformer_8bit = FluxTransformer2DModel.from_pretrained(
    "black-forest-labs/FLUX.1-dev",
    subfolder="transformer",
    quantization_config=quant_config,
+   torch_dtype=torch.float32,
)

让我们使用量化模型生成图像。

设置 device_map="auto" 会自动首先填充 GPU 上的所有可用空间,然后是 CPU,最后,如果仍然没有足够的内存,则填充硬盘驱动器(绝对最慢的选项)。

pipe = FluxPipeline.from_pretrained(
    "black-forest-labs/FLUX.1-dev",
    transformer=transformer_8bit,
    text_encoder_2=text_encoder_2_8bit,
    torch_dtype=torch.float16,
    device_map="auto",
)

pipe_kwargs = {
    "prompt": "A cat holding a sign that says hello world",
    "height": 1024,
    "width": 1024,
    "guidance_scale": 3.5,
    "num_inference_steps": 50,
    "max_sequence_length": 512,
}

image = pipe(**pipe_kwargs, generator=torch.manual_seed(0),).images[0]

当有足够的内存时,您还可以使用 .to("cuda") 将 pipeline 直接移动到 GPU,并应用 enable_model_cpu_offload() 以优化 GPU 内存使用率。

一旦模型被量化,您可以使用 push_to_hub() 方法将模型推送到 Hub。量化 config.json 文件首先被推送,然后是量化模型权重。您还可以使用 save_pretrained() 在本地保存序列化的 8 位模型。

仅支持使用 8 位和 4 位权重训练额外参数。

使用 get_memory_footprint 方法检查您的内存占用

print(model.get_memory_footprint())

可以从 from_pretrained() 方法加载量化模型,而无需指定 quantization_config 参数

from diffusers import FluxTransformer2DModel, BitsAndBytesConfig

quantization_config = BitsAndBytesConfig(load_in_4bit=True)

model_4bit = FluxTransformer2DModel.from_pretrained(
    "hf-internal-testing/flux.1-dev-nf4-pkg", subfolder="transformer"
)

8 位 (LLM.int8() 算法)

在此博客文章中了解有关 8 位量化的更多详细信息!

本节探讨了 8 位模型的一些具体功能,例如异常值阈值和跳过模块转换。

异常值阈值

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

要找到最适合您模型的阈值,我们建议您尝试 BitsAndBytesConfig 中的 llm_int8_threshold 参数

from diffusers import FluxTransformer2DModel, BitsAndBytesConfig

quantization_config = BitsAndBytesConfig(
    load_in_8bit=True, llm_int8_threshold=10,
)

model_8bit = FluxTransformer2DModel.from_pretrained(
    "black-forest-labs/FLUX.1-dev",
    subfolder="transformer",
    quantization_config=quantization_config,
)

跳过模块转换

对于某些模型,您不需要将每个模块都量化为 8 位,这实际上可能会导致不稳定。例如,对于像 Stable Diffusion 3 这样的扩散模型,可以使用 BitsAndBytesConfig 中的 llm_int8_skip_modules 参数跳过 proj_out 模块

from diffusers import SD3Transformer2DModel, BitsAndBytesConfig

quantization_config = BitsAndBytesConfig(
    load_in_8bit=True, llm_int8_skip_modules=["proj_out"],
)

model_8bit = SD3Transformer2DModel.from_pretrained(
    "stabilityai/stable-diffusion-3-medium-diffusers",
    subfolder="transformer",
    quantization_config=quantization_config,
)

4 位 (QLoRA 算法)

在此博客文章中了解有关其详细信息的更多信息。

本节探讨了 4 位模型的一些具体功能,例如更改计算数据类型、使用 Normal Float 4 (NF4) 数据类型以及使用嵌套量化。

计算数据类型

为了加速计算,您可以使用 BitsAndBytesConfig 中的 bnb_4bit_compute_dtype 参数将数据类型从 float32(默认值)更改为 bf16

import torch
from diffusers import BitsAndBytesConfig

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

Normal Float 4 (NF4)

NF4 是 QLoRA 论文中的 4 位数据类型,适用于从正态分布初始化的权重。您应该使用 NF4 训练 4 位基础模型。这可以使用 BitsAndBytesConfig 中的 bnb_4bit_quant_type 参数进行配置

from diffusers import BitsAndBytesConfig as DiffusersBitsAndBytesConfig
from transformers import BitsAndBytesConfig as TransformersBitsAndBytesConfig

from diffusers import FluxTransformer2DModel
from transformers import T5EncoderModel

quant_config = TransformersBitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_quant_type="nf4",
)

text_encoder_2_4bit = T5EncoderModel.from_pretrained(
    "black-forest-labs/FLUX.1-dev",
    subfolder="text_encoder_2",
    quantization_config=quant_config,
    torch_dtype=torch.float16,
)

quant_config = DiffusersBitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_quant_type="nf4",
)

transformer_4bit = FluxTransformer2DModel.from_pretrained(
    "black-forest-labs/FLUX.1-dev",
    subfolder="transformer",
    quantization_config=quant_config,
    torch_dtype=torch.float16,
)

对于推理,bnb_4bit_quant_type 对性能没有巨大影响。但是,为了与模型权重保持一致,您应该使用 bnb_4bit_compute_dtypetorch_dtype 值。

嵌套量化

嵌套量化是一种可以节省额外内存且不增加性能成本的技术。此功能对已量化的权重执行二次量化,以额外节省 0.4 比特/参数。

from diffusers import BitsAndBytesConfig as DiffusersBitsAndBytesConfig
from transformers import BitsAndBytesConfig as TransformersBitsAndBytesConfig

from diffusers import FluxTransformer2DModel
from transformers import T5EncoderModel

quant_config = TransformersBitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_use_double_quant=True,
)

text_encoder_2_4bit = T5EncoderModel.from_pretrained(
    "black-forest-labs/FLUX.1-dev",
    subfolder="text_encoder_2",
    quantization_config=quant_config,
    torch_dtype=torch.float16,
)

quant_config = DiffusersBitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_use_double_quant=True,
)

transformer_4bit = FluxTransformer2DModel.from_pretrained(
    "black-forest-labs/FLUX.1-dev",
    subfolder="transformer",
    quantization_config=quant_config,
    torch_dtype=torch.float16,
)

解量化 bitsandbytes 模型

一旦量化,您可以将模型解量化到其原始精度,但这可能会导致少量质量损失。请确保您有足够的 GPU RAM 来容纳解量化后的模型。

from diffusers import BitsAndBytesConfig as DiffusersBitsAndBytesConfig
from transformers import BitsAndBytesConfig as TransformersBitsAndBytesConfig

from diffusers import FluxTransformer2DModel
from transformers import T5EncoderModel

quant_config = TransformersBitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_use_double_quant=True,
)

text_encoder_2_4bit = T5EncoderModel.from_pretrained(
    "black-forest-labs/FLUX.1-dev",
    subfolder="text_encoder_2",
    quantization_config=quant_config,
    torch_dtype=torch.float16,
)

quant_config = DiffusersBitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_use_double_quant=True,
)

transformer_4bit = FluxTransformer2DModel.from_pretrained(
    "black-forest-labs/FLUX.1-dev",
    subfolder="transformer",
    quantization_config=quant_config,
    torch_dtype=torch.float16,
)

text_encoder_2_4bit.dequantize()
transformer_4bit.dequantize()

资源

< > 更新 on GitHub