Hugging Face 用 bitsandbytes 与 4-bit 量化让 LLM 更易获取
Making LLMs even more accessible with bitsandbytes, 4-bit quantization and QLoRA
Hugging Face 与 bitsandbytes 合作,在 transformers 中支持 4-bit 量化加载模型,覆盖文本、视觉、多模态等大多数 HF 模型,并可在 4bit 模型上训练 LoRA 适配器。
Hugging Face 与 bitsandbytes 集成在 transformers 中开放 4-bit 量化,并给出可直接复用的加载与微调配置。
众所周知,LLM 规模庞大,在消费级硬件上运行或训练它们对用户和可访问性来说是一个巨大的挑战。
我们的 LLM.int8 博客文章 展示了 LLM.int8 论文 中的技术是如何通过 bitsandbytes 库集成到 transformers 中的。
为了努力使模型对任何人都更加可访问,我们决定再次与 bitsandbytes 合作,允许用户以 4 位精度运行模型。这包括绝大多数 HF 模型,适用于任何模态(文本、视觉、多模态等)。用户还可以利用 HF Mirror 生态系统中的工具,在 4 位模型之上训练适配器。这是 Dettmers 等人在今天的 QLoRA 论文中介绍的一种新方法。论文摘要如下:
我们提出了 QLoRA,这是一种高效的微调方法,它减少内存使用量,足以在单个 48GB GPU 上微调一个 65B 参数的模型,同时保持完整的 16 位微调任务性能。QLoRA 通过冻结的 4 位量化预训练语言模型将梯度反向传播到低秩适配器(LoRA)中。我们最好的模型系列,我们将其命名为 Guanaco,在 Vicuna 基准测试中优于所有先前公开发布的模型,达到 ChatGPT 性能水平的 99.3%,而只需在单个 GPU 上进行 24 小时的微调。QLoRA 引入了多项创新,在不牺牲性能的情况下节省内存:(a) 4 位 NormalFloat (NF4),一种新的数据类型,在信息论上对于正态分布的权重是最优的;(b) 双量化,通过量化量化常数来减少平均内存占用;以及 (c) 分页优化器来管理内存峰值。我们使用 QLoRA 微调了 1000 多个模型,对 8 个指令数据集、多种模型类型(LLaMA、T5)以及使用常规微调无法运行的模型规模(例如 33B 和 65B 参数模型)进行了指令遵循和聊天机器人性能的详细分析。我们的结果表明,即使在比之前的最先进技术更小的模型上,使用 QLoRA 在小型高质量数据集上进行微调也能达到最先进的结果。我们基于人类和 GPT-4 评估对聊天机器人性能进行了详细分析,表明 GPT-4 评估是人类评估的一种廉价且合理的替代方案。此外,我们发现当前的聊天机器人基准测试不足以准确评估聊天机器人的性能水平。一项柠檬采摘分析展示了 Guanaco 与 ChatGPT 相比失败的地方。我们发布了所有模型和代码,包括用于 4 位训练的 CUDA 内核。
资源
这篇博客文章和发布附带了多个资源,可帮助您开始使用 4 位模型和 QLoRA:
- 原始论文
- 基本用法 Google Colab 笔记本 - 此笔记本展示了如何在使用所有变体的情况下进行 4 位模型的推理,以及如何在免费的 Google Colab 实例上运行 GPT-neo-X(一个 20B 参数的模型)🤯
- 微调 Google Colab 笔记本 - 此笔记本展示了如何使用 HF Mirror 生态系统在下游任务上微调 4 位模型。我们展示了可以在 Google Colab 实例上微调 GPT-neo-X 20B!
- 用于复现论文结果的原始仓库
- Guanaco 33b 演练场 - 或查看下面的演练场部分
介绍
如果您不熟悉模型精度和最常见的数据类型(float16、float32、bfloat16、int8),我们建议您仔细阅读我们的第一篇博客文章中的介绍,该文章以通俗易懂的方式并通过可视化详细阐述了这些概念的细节。
如需了解更多信息,我们建议通过这份 wikibook 文档阅读浮点表示的基础知识。
最近的 QLoRA 论文探讨了不同的数据类型:4-bit Float 和 4-bit NormalFloat。这里我们将讨论 4-bit Float 数据类型,因为它更容易理解。
FP8 和 FP4 分别代表 8 位和 4 位浮点精度。它们属于 minifloats 浮点值家族(在其他精度中,minifloats 家族还包括 bfloat16 和 float16)。
让我们首先看看如何以 FP8 格式表示浮点值,然后再了解 FP4 格式是什么样的。
FP8 格式
正如我们之前的博客文章中所讨论的,浮点数包含 n 个比特位,每个比特位都属于一个特定的类别,负责表示该数字的一个组成部分(符号、尾数和指数)。它们分别代表以下含义。
FP8(8 位浮点数)格式最早在论文“FP8 for Deep Learning”中提出,包含两种不同的 FP8 编码:E4M3(4 位指数和 3 位尾数)和 E5M2(5 位指数和 2 位尾数)。
![]() |
|---|
8 位浮点(FP8)格式概述。来源:sgugger 的原创内容 |
尽管将位数从 32 位减少到 8 位会大幅降低精度,但这两种版本都可以用于各种场景。目前可以使用Transformer Engine 库,该库也通过 accelerate 与 HF 生态系统集成。
E4M3 格式可以表示的潜在浮点数范围为 -448 到 448,而在 E5M2 格式中,随着指数位数的增加,范围扩大到 -57344 到 57344——但由于可能的表示数量保持不变,精度会有所损失。 经验证明,E4M3 最适合前向传播,而第二种版本最适合反向计算。
简而言之,FP4 精度
符号位表示正负号(+/-),指数位表示以 2 为底、以这些位所表示的整数为指数的幂(例如 2^{010} = 2^{2} = 4),而小数或尾数则是负二次幂之和,对于每个为“1”的位,相应的幂是“激活”的。如果某一位为“0”,则对于 2^-i 的该次幂,小数保持不变,其中 i 是该位在比特序列中的位置。例如,对于尾数位 1010,我们有 (0 + 2^-1 + 0 + 2^-3) = (0.5 + 0.125) = 0.625。要得到一个值,我们将 1 加到小数上,并将所有结果相乘,例如,对于 2 个指数位和 1 个尾数位,表示 1101 将是:
-1 * 2^(2) * (1 + 2^-1) = -1 * 4 * 1.5 = -6
对于 FP4,没有固定格式,因此可以尝试不同的尾数/指数组合。一般来说,在大多数情况下,3 个指数位表现稍好。但有时 2 个指数位和 1 个尾数位会产生更好的性能。
QLoRA 论文,一种民主化量化大型 Transformer 模型的新方式
简而言之,QLoRA 减少了 LLM 微调的内存占用,而与标准的 16 位模型微调相比没有性能损失。该方法使得在单个 24GB GPU 上微调 33B 模型和在单个 46GB GPU 上微调 65B 模型成为可能。
更具体地说,QLoRA 使用 4 位量化来压缩预训练语言模型。然后,LM 参数被冻结,并以低秩适配器的形式向模型添加相对较少数量的可训练参数。在微调过程中,QLoRA 将梯度通过冻结的 4 位量化预训练语言模型反向传播到低秩适配器中。LoRA 层是训练期间唯一被更新的参数。阅读原始 LoRA 论文以了解更多关于 LoRA 的信息。
QLoRA 有一个存储数据类型(通常是 4 位 NormalFloat)用于基础模型权重,以及一个计算数据类型(16 位 BrainFloat)用于执行计算。QLoRA 将权重从存储数据类型反量化到计算数据类型以执行前向和后向传递,但仅计算使用 16 位 bfloat 的 LoRA 参数的权重梯度。权重仅在需要时被解压缩,因此训练和推理期间内存使用保持较低。
在广泛的实验中,QLoRA 调优被证明与 16 位微调方法相匹配。此外,Guanaco 模型——它在OpenAssistant 数据集(OASST1)上对 LLaMA 模型使用 QLoRA 微调——是最先进的聊天机器人系统,并且在 Vicuna 基准测试上接近 ChatGPT。这进一步展示了 QLoRA 调优的强大能力。
如需更详细的阅读,我们推荐您阅读QLoRA 论文。
如何在 transformers 中使用它?
在本节中,让我们介绍该方法的 transformers 集成、如何使用它以及哪些模型可以被有效量化。
快速开始
作为快速开始,通过(在撰写本文时)从源代码安装 accelerate 和 transformers 来以 4 位加载模型,并确保您已安装最新版本的 bitsandbytes 库(0.39.0)。
pip install -q -U bitsandbytes
pip install -q -U git+https://github.com/huggingface/transformers.git
pip install -q -U git+https://github.com/huggingface/peft.git
pip install -q -U git+https://github.com/huggingface/accelerate.git
快速开始
以 4 位加载模型的基本方法是在调用 from_pretrained 方法时,通过提供设备映射来传递参数 load_in_4bit=True(传递 "auto" 以获取将自动推断的设备映射)。
from transformers import AutoModelForCausalLM
model = AutoModelForCausalLM.from_pretrained("facebook/opt-350m", load_in_4bit=True, device_map="auto")
...
这就是您需要的全部!
作为一般规则,我们建议用户在使用 device_map 加载模型后不要手动设置设备。因此,在该行之后,应避免对模型或任何模型子模块进行任何设备分配调用——除非您知道自己在做什么。
请记住,加载量化模型会自动将其他模型的子模块转换为 float16 数据类型。您可以通过向 from_pretrained 方法传递 torch_dtype=dtype 来更改此行为,(例如,如果您希望将层归一化保持为 float32)。
高级用法
您可以尝试不同的 4 位量化变体,例如 NF4(规范化浮点 4(默认))或纯 FP4 量化。基于论文中的理论考虑和实证结果,我们推荐使用 NF4 量化以获得更好的性能。
其他选项包括 bnb_4bit_use_double_quant,它在第一次量化之后使用第二次量化,以每个参数额外节省 0.4 位。最后是计算类型。虽然 4 位 bitsandbytes 以 4 位存储权重,但计算仍然以 16 位或 32 位进行,这里可以选择任意组合(float16、bfloat16、float32 等)。
如果使用 16 位计算数据类型(默认 torch.float32),矩阵乘法和训练将会更快。你应该利用 transformers 中最近的 BitsAndBytesConfig 来更改这些参数。下面是一个示例,使用 NF4 量化加载 4 位模型,采用双重量化,计算数据类型为 bfloat16,以实现更快的训练:
from transformers import BitsAndBytesConfig
nf4_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_use_double_quant=True,
bnb_4bit_compute_dtype=torch.bfloat16
)
model_nf4 = AutoModelForCausalLM.from_pretrained(model_id, quantization_config=nf4_config)
更改计算数据类型
如上所述,你只需更改 BitsAndBytesConfig 中的 bnb_4bit_compute_dtype 参数,即可更改量化模型的计算数据类型。
import torch
from transformers import BitsAndBytesConfig
quantization_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_compute_dtype=torch.bfloat16
)
嵌套量化
要启用嵌套量化,你可以使用 BitsAndBytesConfig 中的 bnb_4bit_use_double_quant 参数。这将在第一次量化之后启用第二次量化,以每个参数额外节省 0.4 位。我们也在训练 Google colab 笔记本中使用了这个功能。
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)
当然,如本节开头所述,所有这些组件都是可组合的。你可以将所有参数组合在一起,找到适合你的最佳用例。一个经验法则是:如果遇到内存问题,使用双重量化;为了更高精度,使用 NF4;为了更快的微调,使用 16 位数据类型。例如,在 推理演示中,我们使用嵌套量化、bfloat16 计算数据类型和 NF4 量化,将 gpt-neo-x-20b(40GB)完全以 4 位形式放入单个 16GB GPU 中。
常见问题
在本节中,我们还将解答任何人可能对这项集成提出的常见问题。
FP4 量化有任何硬件要求吗?
请注意,此方法仅与 GPU 兼容,因此无法在 CPU 上以 4 位量化模型。在 GPU 中,此方法不应有任何硬件要求,因此只要安装了 CUDA>=11.2,任何 GPU 都可以用于运行 4 位量化。还请记住,计算不是以 4 位进行的,权重和激活被压缩为该格式,而计算仍以所需或原生数据类型进行。
支持哪些模型?
与这篇博文中介绍的 LLM.int8 集成类似,该集成严重依赖于 accelerate 库。因此,任何支持 accelerate 加载的模型(即在调用 from_pretrained 时使用 device_map 参数)都应该可以进行 4 位量化。还要注意,这与模态完全无关,只要模型可以用 device_map 参数加载,就可以对它们进行量化。
对于文本模型,在撰写本文时,这将包括大多数使用的架构,如 Llama、OPT、GPT-Neo、GPT-NeoX(文本模型)、Blip2(多模态模型)等。
在撰写本文时,支持 accelerate 的模型有:
[
'bigbird_pegasus', 'blip_2', 'bloom', 'bridgetower', 'codegen', 'deit', 'esm',
'gpt2', 'gpt_bigcode', 'gpt_neo', 'gpt_neox', 'gpt_neox_japanese', 'gptj', 'gptsan_japanese',
'lilt', 'llama', 'longformer', 'longt5', 'luke', 'm2m_100', 'mbart', 'mega', 'mt5', 'nllb_moe',
'open_llama', 'opt', 'owlvit', 'plbart', 'roberta', 'roberta_prelayernorm', 'rwkv', 'switch_transformers',
't5', 'vilt', 'vit', 'vit_hybrid', 'whisper', 'xglm', 'xlm_roberta'
]
请注意,如果你喜欢的模型不在其中,你可以在 transformers 中打开 Pull Request 或提出 issue,为该架构添加 accelerate 加载支持。
我们可以训练 4 位/8 位模型吗?
无法在这些模型上执行纯 4 位训练。但是,你可以利用参数高效微调方法(PEFT)来训练这些模型,例如在它们之上训练适配器。这就是论文中所做的,并得到了 HF Mirror 的 PEFT 库的官方支持。我们还提供了一个训练笔记本,并建议有兴趣复现论文结果的用户查看QLoRA 仓库。
![]() |
|---|
| 原始(冻结的)预训练权重的输出激活(左)由包含权重矩阵 A 和 B 的低秩适配器(右)进行增强。 |
还有哪些其他影响?
这种集成可以为社区和 AI 研究带来若干积极影响,因为它可以影响多个用例和可能的应用。 在 RLHF(基于人类反馈的强化学习)中,可以加载单个基础模型,以 4bit 加载,并在其上训练多个适配器,一个用于奖励建模,另一个用于价值策略训练。很快会针对这个用例发布更详细的博文和公告。
我们还对这种量化方法在消费级硬件上训练大型模型的影响进行了一些基准测试。我们在 NVIDIA T4(16GB)上对两种不同架构 Llama 7B(fp16 下为 15GB)和 Llama 13B(fp16 下为 27GB)进行了微调实验,以下是结果
| 模型名称 | 半精度模型大小(GB) | 硬件类型 / 总 VRAM | 量化方法(CD=计算数据类型 / GC=梯度检查点 / NQ=嵌套量化) | batch_size | 梯度累积步数 | 优化器 | seq_len | 结果 |
|---|---|---|---|---|---|---|---|---|
| <10B 规模模型 | ||||||||
| decapoda-research/llama-7b-hf | 14GB | 1xNVIDIA-T4 / 16GB | LLM.int8 (8-bit) + GC | 1 | 4 | AdamW | 512 | 无 OOM |
| decapoda-research/llama-7b-hf | 14GB | 1xNVIDIA-T4 / 16GB | LLM.int8 (8-bit) + GC | 1 | 4 | AdamW | 1024 | OOM |
| decapoda-research/llama-7b-hf | 14GB | 1xNVIDIA-T4 / 16GB | 4bit + NF4 + bf16 CD + no GC | 1 | 4 | AdamW | 512 | 无 OOM |
| decapoda-research/llama-7b-hf | 14GB | 1xNVIDIA-T4 / 16GB | 4bit + FP4 + bf16 CD + no GC | 1 | 4 | AdamW | 512 | 无 OOM |
| decapoda-research/llama-7b-hf | 14GB | 1xNVIDIA-T4 / 16GB | 4bit + NF4 + bf16 CD + no GC | 1 | 4 | AdamW | 1024 | OOM |
| decapoda-research/llama-7b-hf | 14GB | 1xNVIDIA-T4 / 16GB | 4bit + FP4 + bf16 CD + no GC | 1 | 4 | AdamW | 1024 | OOM |
| decapoda-research/llama-7b-hf | 14GB | 1xNVIDIA-T4 / 16GB | 4bit + NF4 + bf16 CD + GC | 1 | 4 | AdamW | 1024 | 无 OOM |
| 10B+ 规模模型 | ||||||||
| decapoda-research/llama-13b-hf | 27GB | 2xNVIDIA-T4 / 32GB | LLM.int8 (8-bit) + GC | 1 | 4 | AdamW | 512 | 无 OOM |
| decapoda-research/llama-13b-hf | 27GB | 1xNVIDIA-T4 / 16GB | LLM.int8 (8-bit) + GC | 1 | 4 | AdamW | 512 | OOM |
| decapoda-research/llama-13b-hf | 27GB | 1xNVIDIA-T4 / 16GB | 4bit + FP4 + bf16 CD + no GC | 1 | 4 | AdamW | 512 | OOM |
| decapoda-research/llama-13b-hf | 27GB | 1xNVIDIA-T4 / 16GB | 4bit + FP4 + fp16 CD + no GC | 1 | 4 | AdamW | 512 | OOM |
| decapoda-research/llama-13b-hf | 27GB | 1xNVIDIA-T4 / 16GB | 4bit + NF4 + fp16 CD + GC | 1 | 4 | AdamW | 512 | 无 OOM |
| decapoda-research/llama-13b-hf | 27GB | 1xNVIDIA-T4 / 16GB | 4bit + NF4 + fp16 CD + GC | 1 | 4 | AdamW | 1024 | OOM |
| decapoda-research/llama-13b-hf | 27GB | 1xNVIDIA-T4 / 16GB | 4bit + NF4 + fp16 CD + GC + NQ | 1 | 4 | AdamW | 1024 | 无 OOM |
我们使用了 TRL 库中最近的 SFTTrainer,基准测试脚本可以在这里找到
Playground
在playground 中或直接在下方试用论文中提到的 Guananco 模型
致谢
HF 团队想感谢来自 University of Washington 参与该项目的所有人,以及让社区可以使用它。
作者还要感谢Pedro Cuenca 对博文的细心审阅,Olivier Dehaene 和Omar Sanseviero 对将论文的产物集成到 HF Hub 上给予的快速而有力的支持。
来源:Hugging Face Blog · hf-mirror.com

