AI 模型与平台
唯一需要的指南:使用 QLoRA 微调 Llama 3 或其他开源模型
微调大型语言模型(LLM)如 Llama 3,涉及使用特定任务的数据集来适应预训练模型。这一过程利用了模型的预先存在的知识,使其比从头开始训练更高效、更具成本效益。在本指南中,我们将逐步介绍使用 QLoRA(量化 LoRA)微调 Llama 3 的步骤,QLoRA 是一种参数高效的方法,能够最小化内存使用和计算成本。
微调概述
微调涉及几个关键步骤:
- 选择预训练模型:选择一个与您期望的架构相符的基础模型。
- 收集相关数据集:收集和预处理一个特定于任务的数据集。
- 微调:使用数据集来适应模型,以提高其在特定任务上的性能。
- 评估:使用定性和定量指标来评估微调模型的性能。
概念和技术
完整微调
完整微调 更新模型的所有参数,使其特定于新任务。这种方法需要大量计算资源,通常对于非常大的模型来说是不切实际的。
参数高效微调(PEFT)
PEFT 只更新模型的参数子集,减少内存要求和计算成本。这种技术防止灾难性遗忘,并保持模型的通用知识。
低秩适应(LoRA)和量化 LoRA(QLoRA)
LoRA 只微调几个低秩矩阵,而 QLoRA 将这些矩阵量化为更低的精度(例如 4 位而不是 8 位),进一步减少内存占用。
微调方法
- 完整微调:这涉及在任务特定数据集上训练模型的所有参数。虽然这种方法可以很有效,但它也计算成本高昂,需要大量内存。
- 参数高效微调(PEFT):PEFT 只更新模型的参数子集,使其更具内存效率。像低秩适应(LoRA)和量化 LoRA(QLoRA)这样的技术属于这一类别。
什么是 LoRA?
LoRA 是一种改进的微调方法,其中,相比微调预训练模型的所有权重,两个小矩阵被微调以近似较大的矩阵。这些矩阵构成了 LoRA 适配器。然后将该微调适配器加载到预训练模型中并用于推理。
LoRA 的关键优势:
- 内存效率:LoRA 通过只微调小矩阵而不是整个模型来减少内存占用。
- 可重用性:原始模型保持不变,多个 LoRA 适配器可以与其一起使用,实现处理多个任务的同时减少内存要求。
什么是量化 LoRA(QLoRA)?
QLoRA 将 LoRA 进一步量化为更低的精度(例如 4 位而不是 8 位),从而进一步减少内存占用和存储要求,同时保持与全精度模型相似的性能水平。
QLoRA 的关键优势:
- 更大的内存效率:通过量化权重,QLoRA 大大减少了模型的内存和存储要求。
- 保持性能:尽管精度降低,QLoRA 的性能仍然接近全精度模型的水平。
任务特定适应
在微调过程中,模型的参数根据新数据集进行调整,有助于模型更好地理解和生成与特定任务相关的内容。该过程保留了预训练期间获得的通用语言知识,同时将模型适应于目标领域的细微差别。
实践中的微调
完整微调与 PEFT
- 完整微调:涉及训练整个模型,这可能计算成本高昂,需要大量内存。
- PEFT(LoRA 和 QLoRA):只微调参数的子集,减少内存要求,防止灾难性遗忘,使其成为一种更高效的替代方案。
实现步骤
- 设置环境:安装必要的库并设置计算环境。
- 加载和预处理数据集:加载数据集并将其预处理为模型可以使用的格式。
- 加载预训练模型:加载带有量化配置的基础模型(如果使用 QLoRA)。
- 标记化:标记化数据集以准备训练。
- 训练:使用准备好的数据集微调模型。
- 评估:使用定性和定量指标评估模型的性能。
一步一步的 LLM 微调指南
设置环境
我们将使用 Jupyter 笔记本进行此教程。像 Kaggle 这样的平台提供免费的 GPU 使用,或者 Google Colab 是运行这些实验的理想选择。
1. 安装所需库
首先,确保安装了必要的库:
!pip install -qqq -U bitsandbytes transformers peft accelerate datasets scipy einops evaluate trl rouge_score
2. 导入库并设置环境
<p>import os import torch from datasets import load_dataset from transformers import ( AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig, TrainingArguments, pipeline, HfArgumentParser ) from trl import ORPOConfig, ORPOTrainer, setup_chat_format, SFTTrainer from tqdm import tqdm import gc import pandas as pd import numpy as np from huggingface_hub import interpreter_login</p> <p># 禁用 Weights and Biases 日志记录 os.environ['WANDB_DISABLED'] = "true" interpreter_login()</p>
3. 加载数据集
我们将使用 DialogSum 数据集进行此教程:
预处理数据集以满足模型的要求,包括应用适当的模板和确保数据格式适合微调 (Hugging Face) (DataCamp)。
<p>dataset_name = "neil-code/dialogsum-test" dataset = load_dataset(dataset_name)</p>
检查数据集结构:
print(dataset['test'][0])
4. 创建 BitsAndBytes 配置
要以 4 位格式加载模型:
<p>compute_dtype = getattr(torch, "float16") bnb_config = BitsAndBytesConfig( load_in_4bit=True, bnb_4bit_quant_type='nf4', bnb_4bit_compute_dtype=compute_dtype, bnb_4bit_use_double_quant=False, )</p>
5. 加载预训练模型
使用 Microsoft (MSFT ) 的 Phi-2 模型进行此教程:
<p>model_name = 'microsoft/phi-2'
device_map = {"": 0}
original_model = AutoModelForCausalLM.from_pretrained(
model_name,
device_map=device_map,
quantization_config=bnb_config,
trust_remote_code=True,
use_auth_token=True
)</p>
6. 标记化
配置标记器:
<p>tokenizer = AutoTokenizer.from_pretrained( model_name, trust_remote_code=True, padding_side="left", add_eos_token=True, add_bos_token=True, use_fast=False ) tokenizer.pad_token = tokenizer.eos_token</p>
微调 Llama 3 或其他模型
当微调像 Llama 3 这样的模型或其他最先进的开源 LLM 时,需要考虑特定的调整和要求,以确保最佳性能。以下是针对不同模型(包括 Llama 3、GPT-3 和 Mistral)的详细步骤和见解。
5.1 使用 Llama 3
模型选择:
- 确保从 Hugging Face 模型中心获取正确的模型标识符。例如,Llama 3 模型可能在 Hugging Face 上标识为
meta-llama/Meta-Llama-3-8B。 - 确保请求访问并登录您的 Hugging Face 帐户(如果需要)以使用像 Llama 3 这样的模型 (Hugging Face)
标记化:
- 为 Llama 3 使用适当的标记器,确保它与模型兼容并支持所需的功能,如填充和特殊令牌。
内存和计算:
- 微调像 Llama 3 这样的大型模型需要大量计算资源。确保您的环境(如强大的 GPU 设置)可以处理内存和处理要求。确保环境可以处理内存要求,可以通过使用 QLoRA 等技术来减少内存占用 (Hugging Face 论坛)
示例:
model_name = 'meta-llama/Meta-Llama-3-8B'
device_map = {"": 0}
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype=torch.float16,
bnb_4bit_use_double_quant=True,
)
original_model = AutoModelForCausalLM.from_pretrained(
model_name,
device_map=device_map,
quantization_config=bnb_config,
trust_remote_code=True,
use_auth_token=True
)
标记化:
根据具体用例和模型要求,确保正确的标记器配置,不要有冗余的设置。例如,use_fast=True 推荐用于更好的性能 (Hugging Face) (GitHub)
tokenizer = AutoTokenizer.from_pretrained( model_name, trust_remote_code=True, padding_side="left", add_eos_token=True, add_bos_token=True, use_fast=False ) tokenizer.pad_token = tokenizer.eos_token
5.2 使用其他流行模型(例如 GPT-3、Mistral)
模型选择:
- 对于像 GPT-3 和 Mistral 这样的模型,确保从 Hugging Face 模型中心或其他来源使用正确的模型名称和标识符。
标记化:
- 与 Llama 3 类似,确保标记器正确设置并与模型兼容。
内存和计算:
- 每个模型可能有不同的内存要求。根据需要调整环境设置。
示例(GPT-3):
model_name = 'openai/gpt-3'
device_map = {"": 0}
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype=torch.float16,
bnb_4bit_use_double_quant=True,
)
original_model = AutoModelForCausalLM.from_pretrained(
model_name,
device_map=device_map,
quantization_config=bnb_config,
trust_remote_code=True,
use_auth_token=True
)
示例(Mistral):
model_name = 'mistral-7B'
device_map = {"": 0}
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype=torch.float16,
bnb_4bit_use_double_quant=True,
)
original_model = AutoModelForCausalLM.from_pretrained(
model_name,
device_map=device_map,
quantization_config=bnb_config,
trust_remote_code=True,
use_auth_token=True
)
标记化考虑: 每个模型可能有独特的标记化要求。确保标记器与模型匹配并正确配置。
Llama 3 标记器示例:
tokenizer = AutoTokenizer.from_pretrained( model_name, trust_remote_code=True, padding_side="left", add_eos_token=True, add_bos_token=True, use_fast=False ) tokenizer.pad_token = tokenizer.eos_token
GPT-3 和 Mistral 标记器示例:
tokenizer = AutoTokenizer.from_pretrained( model_name, use_fast=True )
7. 使用零样本推理测试模型
使用示例输入评估基础模型:
from transformers import set_seed
<p>set_seed(42)
index = 10
prompt = dataset['test'][index]['dialogue']
formatted_prompt = f"Instruct: Summarize the following conversation.\n{prompt}\nOutput:\n"</p>
<p># 生成输出
def gen(model, prompt, max_length):
inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
outputs = model.generate(**inputs, max_length=max_length)
return tokenizer.batch_decode(outputs, skip_special_tokens=True)</p>
<p>res = gen(original_model, formatted_prompt, 100)
output = res[0].split('Output:\n')[1]</p>
<p>print(f'INPUT PROMPT:\n{formatted_prompt}')
print(f'MODEL GENERATION - ZERO SHOT:\n{output}')
8. 预处理数据集
将对话-摘要对转换为提示:
<p>def create_prompt_formats(sample):
blurb = "Below is an instruction that describes a task. Write a response that appropriately completes the request."
instruction = "### Instruct: Summarize the below conversation."
input_context = sample['dialogue']
response = f"### Output:\n{sample['summary']}"
end = "### End"</p>
<p>parts = [blurb, instruction, input_context, response, end]
formatted_prompt = "\n\n".join(parts)
sample["text"] = formatted_prompt
return sample</p>
<p>dataset = dataset.map(create_prompt_formats)</p>
标记化格式化的数据集:
<p>def preprocess_batch(batch, tokenizer, max_length): return tokenizer(batch["text"], max_length=max_length, truncation=True)</p> <p>max_length = 1024 train_dataset = dataset["train"].map(lambda batch: preprocess_batch(batch, tokenizer, max_length), batched=True) eval_dataset = dataset["validation"].map(lambda batch: preprocess_batch(batch, tokenizer, max_length), batched=True)</p>
9. 为 QLoRA 准备模型
准备模型以进行参数高效的微调:
<p>original_model = prepare_model_for_kbit_training(original_model)</p>
超参数及其影响
超参数在优化模型性能方面起着至关重要的作用。以下是一些需要考虑的关键超参数:
- 学习率:控制模型更新其参数的速度。高学习率可能导致更快的收敛,但可能会超过最优解。低学习率可以确保稳定的收敛,但可能需要更多的轮数。
- 批次大小:在模型更新其参数之前处理的样本数量。较大的批次大小可以提高稳定性,但需要更多的内存。较小的批次大小可能会导致训练过程中的噪音增加。
- 梯度累积步骤:此参数通过在多个步骤中累积梯度来模拟较大的批次大小,然后再执行参数更新。
- 轮数数量:模型处理整个数据集的次数。更多的轮数可以提高性能,但如果不正确管理,可能会导致过拟合。
- 权重衰减:一种正则化技术,用于防止过拟合,方法是惩罚较大的权重。
- 学习率调度器:在训练过程中调整学习率,以提高性能和收敛性。
根据模型和任务的具体要求,自定义训练配置,调整超参数,如学习率、批次大小和梯度累积步骤。例如,Llama 3 模型可能需要与较小模型不同的学习率 (Weights & Biases) (GitHub)
示例训练配置
orpo_args = ORPOConfig( learning_rate=8e-6, lr_scheduler_type="linear",max_length=1024,max_prompt_length=512, beta=0.1,per_device_train_batch_size=2,per_device_eval_batch_size=2, gradient_accumulation_steps=4,optim="paged_adamw_8bit",num_train_epochs=1, evaluation_strategy="steps",eval_steps=0.2,logging_steps=1,warmup_steps=10, report_to="wandb",output_dir="./results/",)
10. 训练模型
设置训练器并开始训练:
trainer = ORPOTrainer(
model=original_model,
args=orpo_args,
train_dataset=train_dataset,
eval_dataset=eval_dataset,
tokenizer=tokenizer,)
trainer.train()
trainer.save_model("fine-tuned-llama-3")
评估微调模型
训练后,使用定性和定量方法评估模型的性能。
1. 人工评估
将生成的摘要与人工编写的摘要进行比较,以评估质量。
2. 定量评估
使用 ROUGE 等指标评估性能:
from rouge_score import rouge_scorer <p>scorer = rouge_scorer.RougeScorer(['rouge1', 'rouge2', 'rougeL'], use_stemmer=True) scores = scorer.score(reference_summary, generated_summary) print(scores)</p>
常见挑战和解决方案
1. 内存限制
使用 QLoRA 有助于通过量化模型权重为 4 位来缓解内存问题。确保您有足够的 GPU 内存来处理批次大小和模型大小。
2. 过拟合
监控验证指标以防止过拟合。使用早期停止和权重衰减等技术。
3. 训练速度慢
通过调整批次大小、学习率和使用梯度累积来优化训练速度。
4. 数据质量
确保您的数据集是干净和预处理良好的。数据质量差可能会显著影响模型性能。
结论
使用 QLoRA 微调 LLM 是一种高效的方法,用于将大型预训练模型适应特定任务,同时降低计算成本。通过遵循本指南,您可以微调 PHI、Llama 3 或其他开源模型,以在特定任务上实现高性能。














