通过 bitsandbytes、4 位量化和 QLoRA 让 LLM 更易于访问

发布于 2023 年 5 月 24 日
在 GitHub 上更新

众所周知,LLM 体积庞大,在消费级硬件上运行或训练它们对用户和可访问性来说是一个巨大的挑战。我们的LLM.int8 博客文章展示了如何在 Transformer 中使用 `bitsandbytes` 库集成LLM.int8 论文中的技术。为了让模型更易于访问,我们决定再次与 bitsandbytes 合作,允许用户以 4 位精度运行模型。这包括绝大多数 Hugging Face 模型,支持任何模态(文本、视觉、多模态等)。用户还可以利用 Hugging Face 生态系统中的工具在 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 微调可以获得最先进的结果,即使使用的模型比以前的 SoTA 小。我们根据人工和 GPT-4 评估提供了详细的聊天机器人性能分析,表明 GPT-4 评估是人工评估的一种廉价且合理的替代方案。此外,我们发现当前的聊天机器人基准测试不可靠,无法准确评估聊天机器人的性能水平。一个精心挑选的分析展示了 Guanaco 与 ChatGPT 相比的不足之处。我们发布了所有模型和代码,包括用于 4 位训练的 CUDA 内核。

资源

这篇博客文章和发布附带了多项资源,可帮助您开始使用 4 位模型和 QLoRA

引言

如果您不熟悉模型精度和最常见的数据类型(float16、float32、bfloat16、int8),我们建议您仔细阅读我们第一篇博客文章中的介绍,其中通过可视化简单地阐述了这些概念的细节。

有关更多信息,我们建议您通过这篇维基教科书文档阅读浮点表示的基础知识。

最近的 QLoRA 论文探讨了不同的数据类型:4 位浮点和 4 位 NormalFloat。这里我们将讨论 4 位浮点数据类型,因为它更容易理解。

FP8 和 FP4 分别代表 8 位和 4 位浮点精度。它们是浮点值微浮点家族的一部分(在该家族中,还有其他精度,包括 bfloat16 和 float16)。

我们首先来看看如何在 FP8 格式中表示浮点值,然后了解 FP4 格式的特点。

FP8 格式

正如我们在之前的博客文章中讨论的,浮点数包含 n 位,其中每个位都属于一个特定类别,负责表示数字的组成部分(符号位、尾数和指数)。它们代表以下内容:

FP8(8 位浮点)格式首次在论文“FP8 for Deep Learning”中提出,包含两种不同的 FP8 编码:E4M3(4 位指数和 3 位尾数)和 E5M2(5 位指数和 2 位尾数)。

fp8_scheme
8 位浮点 (FP8) 格式概述。来源:sgugger 的原创内容

尽管通过将位数从 32 位减少到 8 位,精度大幅降低,但这两个版本都可以在各种情况下使用。目前可以使用Transformer Engine 库,它也通过 accelerate 集成到 HF 生态系统中。

E4M3 格式可以表示的潜在浮点数范围是 -448 到 448,而 E5M2 格式,由于指数位数增加,范围扩大到 -57344 到 57344 - 但精度有所损失,因为可表示的数量保持不变。经验证明,E4M3 最适合前向传播,而第二种版本最适合反向计算。

FP4 精度简介

符号位表示符号(+/-),指数位表示以 2 为底,指数为由这些位表示的整数(例如,`2^{010} = 2^{2} = 4`),而小数部分或尾数是负 2 的幂之和,这些幂在每个“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 参数被冻结,并以低秩适配器 (Low-Rank Adapters) 的形式向模型添加相对较少的可训练参数。在微调过程中,QLoRA 通过冻结的 4 位量化预训练语言模型将梯度反向传播到低秩适配器中。LoRA 层是训练期间唯一被更新的参数。有关 LoRA 的更多信息,请阅读原始 LoRA 论文

QLoRA 有一个用于基础模型权重的存储数据类型(通常是 4 位 NormalFloat)和一个用于执行计算的计算数据类型(16 位 BrainFloat)。QLoRA 将权重从存储数据类型反量化到计算数据类型以执行前向和后向传播,但仅计算使用 16 位 bfloat 的 LoRA 参数的权重梯度。权重仅在需要时才解压缩,因此在训练和推理期间内存使用率保持较低。

QLoRA 微调在广泛的实验中与 16 位微调方法表现出了一致的性能。此外,使用 QLoRA 在 OpenAssistant 数据集 (OASST1) 上对 LLaMA 模型进行微调的 Guanaco 模型,是当前最先进的聊天机器人系统,在 Vicuna 基准测试中与 ChatGPT 表现接近。这进一步证明了 QLoRA 微调的强大之处。

如需更详细的阅读,我们建议您阅读 QLoRA 论文

如何在 Transformers 中使用?

在本节中,我们将介绍该方法在 Transformer 中的集成,如何使用它以及哪些模型可以有效地量化。

开始使用

作为快速入门,请通过(截至本文撰写时)从源代码安装 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` 数据类型。您可以通过将 `torch_dtype=dtype` 传递给 `from_pretrained` 方法来更改此行为(例如,如果您希望层范数使用 `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 量化、双重量化和计算数据类型 bfloat16 来更快训练的 4 位模型加载示例。

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 中,此方法不应有任何硬件要求,因此任何 GPU 都可以用于运行 4 位量化,只要安装了 CUDA >= 11.2。还要记住,计算并非以 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'
]  

请注意,如果您喜欢的模型不在其中,您可以打开 Pull Request 或在 transformers 中提出 issue,以添加对该架构的 accelerate 加载支持。

我们可以训练 4 位/8 位模型吗?

无法对这些模型进行纯 4 位训练。但是,您可以利用参数高效微调方法 (PEFT) 训练这些模型,例如在其之上训练适配器。论文中就是这样做的,并且 Hugging Face 的 PEFT 库也正式支持。我们还提供了一个训练笔记本,并建议用户查看QLoRA 存储库,如果他们有兴趣重现论文中的结果。

lora-gif
原始(冻结的)预训练权重的输出激活(左)通过由权重矩阵 A 和 B 组成的低秩适配器(右)进行增强。

还有哪些其他影响?

这项集成可以为社区和人工智能研究带来多项积极影响,因为它能影响多个用例和可能的应用。在 RLHF(基于人类反馈的强化学习)中,可以加载单个 4 位基础模型,并在其之上训练多个适配器,一个用于奖励建模,另一个用于价值策略训练。关于此用例的更详细的博客文章和公告将很快发布。

我们还对这种量化方法在消费级硬件上训练大型模型的影响进行了一些基准测试。我们对微调两种不同架构进行了多次实验:Llama 7B(fp16 格式为 15GB)和 Llama 13B(fp16 格式为 27GB),均在 NVIDIA T4(16GB)上进行,结果如下:

模型名称 半精度模型大小(GB) 硬件类型 / 总显存 量化方法 (CD=计算数据类型 / GC=梯度检查点 / NQ=嵌套量化) 批处理大小 梯度累积步数 优化器 序列长度 结果
<10B 规模模型
decapoda-research/llama-7b-hf 14GB 1xNVIDIA-T4 / 16GB LLM.int8 (8 位) + GC 1 4 AdamW 512 无 OOM
decapoda-research/llama-7b-hf 14GB 1xNVIDIA-T4 / 16GB LLM.int8 (8 位) + GC 1 4 AdamW 1024 OOM
decapoda-research/llama-7b-hf 14GB 1xNVIDIA-T4 / 16GB 4 位 + NF4 + bf16 CD + 无 GC 1 4 AdamW 512 无 OOM
decapoda-research/llama-7b-hf 14GB 1xNVIDIA-T4 / 16GB 4 位 + FP4 + bf16 CD + 无 GC 1 4 AdamW 512 无 OOM
decapoda-research/llama-7b-hf 14GB 1xNVIDIA-T4 / 16GB 4 位 + NF4 + bf16 CD + 无 GC 1 4 AdamW 1024 OOM
decapoda-research/llama-7b-hf 14GB 1xNVIDIA-T4 / 16GB 4 位 + FP4 + bf16 CD + 无 GC 1 4 AdamW 1024 OOM
decapoda-research/llama-7b-hf 14GB 1xNVIDIA-T4 / 16GB 4 位 + NF4 + bf16 CD + GC 1 4 AdamW 1024 无 OOM
10B+ 规模模型
decapoda-research/llama-13b-hf 27GB 2xNVIDIA-T4 / 32GB LLM.int8 (8 位) + GC 1 4 AdamW 512 无 OOM
decapoda-research/llama-13b-hf 27GB 1xNVIDIA-T4 / 16GB LLM.int8 (8 位) + GC 1 4 AdamW 512 OOM
decapoda-research/llama-13b-hf 27GB 1xNVIDIA-T4 / 16GB 4 位 + FP4 + bf16 CD + 无 GC 1 4 AdamW 512 OOM
decapoda-research/llama-13b-hf 27GB 1xNVIDIA-T4 / 16GB 4 位 + FP4 + fp16 CD + 无 GC 1 4 AdamW 512 OOM
decapoda-research/llama-13b-hf 27GB 1xNVIDIA-T4 / 16GB 4 位 + NF4 + fp16 CD + GC 1 4 AdamW 512 无 OOM
decapoda-research/llama-13b-hf 27GB 1xNVIDIA-T4 / 16GB 4 位 + NF4 + fp16 CD + GC 1 4 AdamW 1024 OOM
decapoda-research/llama-13b-hf 27GB 1xNVIDIA-T4 / 16GB 4 位 + NF4 + fp16 CD + GC + NQ 1 4 AdamW 1024 无 OOM

我们使用了 TRL 库中最新的 `SFTTrainer`,基准测试脚本可以在这里找到

游乐场

游乐场或直接在下面尝试论文中引用的 Guananco 模型

致谢

Hugging Face 团队衷心感谢华盛顿大学参与此项目的所有人员,以及他们为社区所做的贡献。

作者还要感谢 Pedro Cuenca 审阅了博客文章,以及 Olivier DehaeneOmar Sanseviero 对论文成果在 HF Hub 上集成的迅速而有力的支持。

社区

你好

注册登录以评论