【大模型微调学习7】-实战Hugging Face PEFT工具

实战Hugging Face PEFT工具

通过两个简单的案例来熟悉peft 库和 bitsandbytes 库的使用,来实现高效微调。

1.PEFT 库 LoRA 实战 - OPT-6.7B

介绍如何使用最新的 peft 库和 bitsandbytes 来以 8-bits 加载大语言模型,并对其进行高效微调。

微调方法将依赖于一种名为“低秩适配器”(LoRA)的方法,与其微调整个模型,您只需要微调这些适配器(Adapter)并在模型中正确加载它们。

(1)加载模型

Facebook opt-6.7b 模型,半精度(float16)模型权重大约需要13GB左右显存。

模型链接:Facebook opt-6.7b

下面我们以8-bits 加载它,只需要大约7GB左右显存。

import os

import torch
import torch.nn as nn
import bitsandbytes as bnb
from transformers import GPT2Tokenizer, AutoConfig, OPTForCausalLM

model_id = "./model/opt-6.7b"

from transformers import AutoModelForCausalLM, AutoTokenizer, set_seed
model = AutoModelForCausalLM.from_pretrained(model_id,load_in_8bit=True,device_map="auto")
tokenizer = GPT2Tokenizer.from_pretrained(model_id)
(2)PEFT 微调前的模型处理

在使用 peft 训练 int8 模型之前,需要进行一些预处理:

  • 将所有非 int8 模块转换为全精度(fp32)以保证稳定性
  • 为输入嵌入层添加一个 forward_hook,以启用输入隐藏状态的梯度计算
  • 启用梯度检查点以实现更高效的内存训练

使用 peft 库预定义的工具函数 prepare_model_for_int8_training,便可自动完成以上模型处理工作。

from peft import prepare_model_for_int8_training

model = prepare_model_for_int8_training(model)

获取当前模型占用的 GPU显存(差值为预留给 PyTorch 的显存)

# 获取当前模型占用的 GPU显存(差值为预留给 PyTorch 的显存)
memory_footprint_bytes = model.get_memory_footprint()
memory_footprint_mib = memory_footprint_bytes / (1024 ** 3)  # 转换为 GB

print(f"{memory_footprint_mib:.2f}GB")
#6.80GB
(3)LoRA Adapter 配置

peft 中使用LoRA非常简捷,借助 PeftModel抽象,我们可以快速使用低秩适配器(LoRA)到任意模型。

通过使用 peft 中的 get_peft_model 工具函数来实现。

关于 LoRA 超参数的说明:
M a t M u l ( B , A ) ∗ S c a l i n g S c a l i n g = L o R A A l p h a / R a n k MatMul(B,A) * Scaling \\ Scaling = LoRA_Alpha / Rank MatMul(B,A)ScalingScaling=LoRAAlpha/Rank

# 从peft库导入LoraConfig和get_peft_model函数
from peft import LoraConfig, get_peft_model

# 创建一个LoraConfig对象,用于设置LoRA(Low-Rank Adaptation)的配置参数
config = LoraConfig(
    r=8,  # LoRA的秩,影响LoRA矩阵的大小
    lora_alpha=32,  # LoRA适应的比例因子
    # 指定将LoRA应用到的模型模块,通常是attention和全连接层的投影
    target_modules = ["q_proj", "k_proj", "v_proj", "out_proj", "fc_in", "fc_out"],
    lora_dropout=0.05,  # 在LoRA模块中使用的dropout率
    bias="none",  # 设置bias的使用方式,这里没有使用bias
    task_type="CAUSAL_LM"  # 任务类型,这里设置为因果(自回归)语言模型
)

# 使用get_peft_model函数和给定的配置来获取一个PEFT模型
model = get_peft_model(model, config)

# 打印出模型中可训练的参数
model.print_trainable_parameters()

#trainable params: 8,388,608 || all params: 6,666,862,592 || trainable%: 0.12582542214183376
(4)数据处理
from datasets import load_dataset

dataset = load_dataset("./data/english_quotes")

from datasets import ClassLabel, Sequence
import random
import pandas as pd
from IPython.display import display, HTML

def show_random_elements(dataset, num_examples=10):
    assert num_examples <= len(dataset), "Can't pick more elements than there are in the dataset."
    picks = []
    for _ in range(num_examples):
        pick = random.randint(0, len(dataset)-1)
        while pick in picks:
            pick = random.randint(0, len(dataset)-1)
        picks.append(pick)
    
    df = pd.DataFrame(dataset[picks])
    for column, typ in dataset.features.items():
        if isinstance(typ, ClassLabel):
            df[column] = df[column].transform(lambda i: typ.names[i])
        elif isinstance(typ, Sequence) and isinstance(typ.feature, ClassLabel):
            df[column] = df[column].transform(lambda x: [typ.feature.names[i] for i in x])
    display(HTML(df.to_html()))
    
show_random_elements(dataset["train"])
tokenized_dataset = dataset.map(lambda samples: tokenizer(samples["quote"]), batched=True)

from transformers import DataCollatorForLanguageModeling

# 数据收集器,用于处理语言模型的数据,这里设置为不使用掩码语言模型(MLM)
data_collator = DataCollatorForLanguageModeling(tokenizer, mlm=False)
(5)微调模型
from transformers import TrainingArguments, Trainer
# 设置CUDA_VISIBLE_DEVICES,指定使用哪些GPU
# os.environ["CUDA_VISIBLE_DEVICES"] = "0"  # 使用cuda:0和cuda:1
model_dir = "models"
model_id='opt-6.7b'
training_args = TrainingArguments(
        output_dir=f"{model_dir}/{model_id}-lora",  # 指定模型输出和保存的目录
        per_device_train_batch_size=8,  # 每个设备上的训练批量大小
        learning_rate=2e-4,  # 学习率
        fp16=True,  # 启用混合精度训练,可以提高训练速度,同时减少内存使用
        logging_steps=50,  # 指定日志记录的步长,用于跟踪训练进度
        # max_steps=100, # 最大训练步长
        num_train_epochs=1  # 训练的总轮数
    )
trainer = Trainer(
    model=model,  # 指定训练时使用的模型
    train_dataset=tokenized_dataset["train"],  # 指定训练数据集
    args=training_args,
    data_collator=data_collator,
)
trainer.train()

在这里插入图片描述

(6)保存 LoRA 模型
model_path = f"./models/opt-6.7b-lora-int8"

#trainer.save_model(model_path)
model.save_pretrained(model_path)
(7)使用 LoRA 模型
lora_model = trainer.model
text = "Two things are infinite: "
inputs = tokenizer(text, return_tensors="pt").to(0)

out = lora_model.generate(**inputs, max_new_tokens=48)
print(tokenizer.decode(out[0], skip_special_tokens=True))

在这里插入图片描述

2.ChatGLM实战

基于ChatGLM-6B、ChatGLM2-6B、ChatGLM3-6B模型,进行下游具体任务微调,涉及Freeze、Lora、P-tuning、全参微调等。

参考项目:github

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值