🤗 PEFT:在低资源硬件上对十亿规模模型进行参数高效微调
动机
基于 Transformer 架构的大型语言模型 (LLMs),如 GPT、T5 和 BERT,在各种自然语言处理 (NLP) 任务中取得了最先进的成果。它们也开始涉足其他领域,例如计算机视觉 (CV) (VIT、Stable Diffusion、LayoutLM) 和音频 (Whisper、XLS-R)。传统的范式是在通用网络规模数据上进行大规模预训练,然后针对下游任务进行微调。与开箱即用的预训练 LLM(例如零样本推理)相比,在下游数据集上微调这些预训练 LLM 可带来巨大的性能提升。
然而,随着模型变得越来越大,在消费级硬件上进行完全微调变得不可行。此外,为每个下游任务独立存储和部署微调模型变得非常昂贵,因为微调模型与原始预训练模型大小相同。参数高效微调 (PEFT) 方法旨在解决这两个问题!
PEFT 方法仅微调少量(额外)模型参数,同时冻结预训练 LLM 的大部分参数,从而大大降低了计算和存储成本。这还克服了灾难性遗忘问题,这是一种在 LLM 全量微调过程中观察到的行为。PEFT 方法还被证明在低数据状态下优于微调,并且对域外场景具有更好的泛化能力。它可以应用于各种模态,例如图像分类和Stable Diffusion Dreambooth。
它还有助于可移植性,用户可以使用 PEFT 方法调整模型,以获得仅几 MB 的微小检查点,而完全微调会产生大型检查点,例如,`bigscience/mt0-xxl` 占用 40GB 存储空间,完全微调将导致每个下游数据集生成 40GB 检查点,而使用 PEFT 方法,每个下游数据集仅需几 MB,同时达到与完全微调相当的性能。PEFT 方法训练得到的小权重会添加到预训练 LLM 的顶部。因此,同一个 LLM 可以通过添加小权重用于多个任务,而无需替换整个模型。
简而言之,PEFT 方法使您能够以少量可训练参数获得与完全微调相当的性能。
今天,我们很高兴推出 🤗 PEFT 库,该库提供最新参数高效微调技术,并与 🤗 Transformers 和 🤗 Accelerate 无缝集成。这使得使用 Transformers 中最流行、性能最佳的模型,同时结合 Accelerate 的简单性和可扩展性成为可能。以下是目前支持的 PEFT 方法,更多方法即将推出:
- LoRA:LORA:大型语言模型的低秩适应
- 前缀调整:P-Tuning v2:Prompt Tuning 可以与在各种规模和任务上的微调普遍媲美
- Prompt Tuning:规模对于参数高效 Prompt Tuning 的力量
- P-Tuning:GPT 也理解
用例
我们在此探索了许多有趣的用例。以下是一些最有趣的:
使用 🤗 PEFT LoRA,在具有 11GB 内存的消费级硬件(例如 Nvidia GeForce RTX 2080 Ti、Nvidia GeForce RTX 3080 等)上,使用 🤗 Accelerate 的 DeepSpeed 集成微调 `bigscience/T0_3B` 模型(30 亿参数):peft_lora_seq2seq_accelerate_ds_zero3_offload.py。这意味着您可以在 Google Colab 中微调如此大型的 LLM。
通过使用 🤗 PEFT LoRA 和 bitsandbytes 在 Google Colab 中启用 `OPT-6.7b` 模型(67 亿参数)的 INT8 微调,将前面的示例提升一个档次:
使用 🤗 PEFT 在具有 11GB 内存的消费级硬件(例如 Nvidia GeForce RTX 2080 Ti、Nvidia GeForce RTX 3080 等)上进行 Stable Diffusion Dreambooth 训练。尝试 Space 演示,它应该可以在 T4 实例(16GB GPU)上无缝运行:smangrul/peft-lora-sd-dreambooth。
PEFT LoRA Dreambooth Gradio Space
使用 🤗 PEFT 训练你的模型
让我们考虑使用 LoRA 对 `bigscience/mt0-large` 进行微调的案例。
- 获取必要的导入
from transformers import AutoModelForSeq2SeqLM
+ from peft import get_peft_model, LoraConfig, TaskType
model_name_or_path = "bigscience/mt0-large"
tokenizer_name_or_path = "bigscience/mt0-large"
- 创建与 PEFT 方法对应的配置
peft_config = LoraConfig(
task_type=TaskType.SEQ_2_SEQ_LM, inference_mode=False, r=8, lora_alpha=32, lora_dropout=0.1
)
- 通过调用 `get_peft_model` 封装基础 🤗 Transformers 模型
model = AutoModelForSeq2SeqLM.from_pretrained(model_name_or_path)
+ model = get_peft_model(model, peft_config)
+ model.print_trainable_parameters()
# output: trainable params: 2359296 || all params: 1231940608 || trainable%: 0.19151053100118282
就是这样!其余的训练循环保持不变。请参阅示例 peft_lora_seq2seq.ipynb 以获取端到端示例。
- 当您准备好保存模型以进行推理时,只需执行以下操作。
model.save_pretrained("output_dir")
# model.push_to_hub("my_awesome_peft_model") also works
这将只保存训练过的增量 PEFT 权重。例如,您可以在此处找到使用 LoRA 在 `twitter_complaints` raft 数据集上微调的 `bigscience/T0_3B`:smangrul/twitter_complaints_bigscience_T0_3B_LORA_SEQ_2_SEQ_LM。请注意,它只包含 2 个文件:adapter_config.json 和 adapter_model.bin,其中后者仅为 19MB。
- 要加载它进行推理,请遵循以下代码片段
from transformers import AutoModelForSeq2SeqLM
+ from peft import PeftModel, PeftConfig
peft_model_id = "smangrul/twitter_complaints_bigscience_T0_3B_LORA_SEQ_2_SEQ_LM"
config = PeftConfig.from_pretrained(peft_model_id)
model = AutoModelForSeq2SeqLM.from_pretrained(config.base_model_name_or_path)
+ model = PeftModel.from_pretrained(model, peft_model_id)
tokenizer = AutoTokenizer.from_pretrained(config.base_model_name_or_path)
model = model.to(device)
model.eval()
inputs = tokenizer("Tweet text : @HondaCustSvc Your customer service has been horrible during the recall process. I will never purchase a Honda again. Label :", return_tensors="pt")
with torch.no_grad():
outputs = model.generate(input_ids=inputs["input_ids"].to("cuda"), max_new_tokens=10)
print(tokenizer.batch_decode(outputs.detach().cpu().numpy(), skip_special_tokens=True)[0])
# 'complaint'
后续步骤
我们发布了 PEFT,作为一种在下游任务和领域上微调大型 LLM 的高效方式,它节省了大量计算和存储,同时实现了与完全微调相当的性能。在未来几个月,我们将探索更多 PEFT 方法,例如 (IA)3 和瓶颈适配器。此外,我们将重点关注新的用例,例如在 Google Colab 中对 `whisper-large` 模型进行 INT8 训练,以及使用 PEFT 方法对 RLHF 组件(如策略和排序器)进行微调。
与此同时,我们很高兴看到行业从业者如何将 PEFT 应用于他们的用例——如果您有任何问题或反馈,请在我们的 GitHub 仓库上提出问题 🤗。
祝您参数高效微调愉快!