前言
在本教程中,我们将介绍如何使用最新的peft库和bitsandbytes库以8位格式加载大型模型,进而对大型语言模型进行微调。微调方法将依赖于一种最近的方法,称为“低秩适配器”(LoRA)。您无需微调整个模型,只需微调这些适配器并将它们正确加载到模型中即可。微调模型后,您还可以在🤗 Hub上分享您的适配器,并且可以非常轻松地加载它们。让我们开始吧!
src link: https://huggingface.co/spaces/PEFT/quantization/blob/main/Finetune_opt_bnb_peft.ipynb
Operating System: Ubuntu 22.04.4 LTS
参考文档
安装依赖项
首先,运行下面的单元格以安装所需的依赖项:
!pip install -q bitsandbytes datasets accelerate
!pip install -q transformers peft
模型加载
在这里,我们加载opt-6.7b模型,它在Hub上的半精度(float16)权重大约为13GB!如果我们以8位格式加载,则只需要大约7GB的内存。
import os
import torch
import torch.nn as nn
import bitsandbytes as bnb
from transformers import AutoTokenizer, AutoConfig, AutoModelForCausalLM
model = AutoModelForCausalLM.from_pretrained("facebook/opt-6.7b", load_in_8bit=True)
tokenizer = AutoTokenizer.from_pretrained("facebook/opt-6.7b")
为训练准备模型
在使用peft训练这样的int8模型之前,需要进行一些预处理,因此让我们导入一个实用函数prepare_model_for_int8_training,该函数将执行以下操作:
- 将所有非int8模块转换为全精度(fp32)以提高稳定性。
- 向输入嵌入层添加一个forward_hook,以启用输入隐藏状态的梯度计算。
- 启用梯度检查点以进行更节省内存的训练。
from peft import prepare_model_for_int8_training
model = prepare_model_for_int8_training(model)
应用LoRA
现在是peft的神奇之处!让我们加载一个PeftModel,并使用peft的get_peft_model实用函数指定我们将使用低秩适配器(LoRA)。
def print_trainable_parameters(model):
"""
Prints the number of trainable parameters in the model.
"""
trainable_params = 0
all_param = 0
for _, param in model.named_parameters():
all_param += param.numel()
if param.requires_grad:
trainable_params += param.numel()
print(
f"trainable params: {trainable_params} || all params: {all_param} || trainable%: {100 * trainable_params / all_param}"
)
from peft import LoraConfig, get_peft_model
config = LoraConfig(
r=16, lora_alpha=32, target_modules=["q_proj", "v_proj"], lora_dropout=0.05, bias="none", task_type="CAUSAL_LM"
)
model = get_peft_model(model, config)
print_trainable_parameters(model)
训练
import transformers
from datasets import load_dataset
data = load_dataset("Abirate/english_quotes")
data = data.map(lambda samples: tokenizer(samples["quote"]), batched=True)
trainer = transformers.Trainer(
model=model,
train_dataset=data["train"],
args=transformers.TrainingArguments(
per_device_train_batch_size=4,
gradient_accumulation_steps=4,
warmup_steps=100,
max_steps=200,
learning_rate=2e-4,
fp16=True,
logging_steps=1,
output_dir="outputs",
),
data_collator=transformers.DataCollatorForLanguageModeling(tokenizer, mlm=False),
)
model.config.use_cache = False # silence the warnings. Please re-enable for inference!
trainer.train()
在🤗 Hub上分享适配器。
from huggingface_hub import notebook_login
notebook_login()
model.push_to_hub("ybelkada/opt-6.7b-lora", use_auth_token=True)
从Hub加载适配器。
您还可以使用以下命令直接从Hub加载适配器:
import torch
from peft import PeftModel, PeftConfig
from transformers import AutoModelForCausalLM, AutoTokenizer
peft_model_id = "ybelkada/opt-6.7b-lora"
config = PeftConfig.from_pretrained(peft_model_id)
model = AutoModelForCausalLM.from_pretrained(
config.base_model_name_or_path, return_dict=True, load_in_8bit=True, device_map="auto"
)
tokenizer = AutoTokenizer.from_pretrained(config.base_model_name_or_path)
# Load the Lora model
model = PeftModel.from_pretrained(model, peft_model_id)
推理
然后,您可以直接使用训练好的模型或从🤗 Hub加载的模型进行推理,就像在transformers中通常所做的那样。
batch = tokenizer("Two things are infinite: ", return_tensors="pt")
with torch.cuda.amp.autocast():
output_tokens = model.generate(**batch, max_new_tokens=50)
print("\n\n", tokenizer.decode(output_tokens[0], skip_special_tokens=True))
正如您所看到的,通过微调几步,我们几乎恢复了阿尔伯特·爱因斯坦在训练数据中的引用。
结语
第二百七十一篇博文写完,开心!!!!
今天,也是充满希望的一天。