Llama - 微调

时间:2024-07-18 07:14:11

本文翻译整理自:
https://llama.meta.com/docs/how-to-guides/fine-tuning


文章目录

    • 微调
    • 实验跟踪
    • Recipes PEFT LoRA
    • torchtune
    • Hugging Face PEFT LoRA
    • QLoRA微调


如果你想通过编写代码来学习,强烈建议你查看 了解Llama 3 notebook。这是一个开始对Meta Llama进行最常见实施的好地方。


微调

全参数微调是一种对预训练模型的所有层的所有参数进行微调的方法,一般来说,它可以达到最佳性能但也是最耗费资源和时间的:它需要大多数GPU资源并且花费的时间最长。

PEFT或参数高效微调允许以最少的资源和成本微调模型。有两种重要的PEFT方法:LoRA(低秩自适应)和QLoRA(量化LoRA),其中预训练模型分别作为量化的8位和4位权重加载到GPU。
您很可能可以使用LoRA或QLoRA微调来微调Llama13B模型,使用具有24GB内存的单个消费类GPU,使用QLoRA需要比LoRA更少的GPU内存和微调时间。

通常,应该尝试LoRA,或者如果资源极其有限,首先尝试QLoRA,然后在微调完成后评估性能。只有在性能不理想时才考虑完全微调。


实验跟踪

在评估LoRA和QLoRA等各种微调方法时,实验跟踪至关重要。
它确保了可重复性,维护了结构化的版本历史,允许轻松协作,并有助于确定最佳训练配置。
特别是在大量迭代、超参数和模型版本的情况下,权重和偏差(W&B)等工具变得不可或缺。
通过无缝集成到多个框架中,W&B提供了一个全面的仪表板,用于可视化指标、比较运行和管理模型检查点。
这通常就像在训练脚本中添加一个参数来实现这些好处一样简单——我们将在拥抱面部PEFT LoRA部分展示一个例子。


Recipes PEFT LoRA

骆驼食谱库详细介绍了不同的 微调(FT)提供的示例脚本支持的替代方案。

特别是,它强调了PEFT作为首选FT方法的使用,因为它降低了硬件要求并防止了灾难性的遗忘。

对于特定情况,全参数FT仍然有效,并且可以使用不同的策略来防止对模型进行过多修改。此外,FT可以在单gpu 中完成 或 多gpuFSDP。


为了运行recipes,请按照以下步骤操作:

  1. 使用pytorch和其他依赖项创建conda环境
  2. 安装 recipes 可见 这里
  3. 使用 git-lfs 或 使用llama下载脚本从hf下载所需的模型。
  4. 配置好所有内容后,运行以下命令:
python -m llama_recipes.finetuning \
    --use_peft --peft_method lora --quantization \
    --model_name ../llama/models_hf/7B \
    --output_dir ../llama/models_ft/7B-peft \
    --batch_size_training 2 --gradient_accumulation_steps 2

torchtune

torchtune是一个PyTorch原生库,可用于微调Meta Llama系列模型,包括Meta Llamas 3。它支持 端到端微调生命周期,包括:

  • 下载模型检查点和数据集
  • 微调Llama 3
  • 支持单GPU微调,能够在具有24GB VRAM的消费级GPU上运行
  • 使用PyTorch FSDP将微调扩展到多个GPU
  • 使用权重和偏差记录训练期间的指标和模型检查点
  • 使用EleutherAI的LM评估工具评估微调模型
  • 基于TorchAO的微调模型训练后量化
  • 与包括ExecuTorch在内的推理引擎的互操作性

安装torchtune 使用如下命令

pip install torchtune


按照 Hugging Face meta-llama r 上的说明进行操作 ,以确保您可以访问Llama 3模型权重。
确认访问后,您可以运行以下命令将权重下载到本地计算机。
这也将下载标记器模型和负责任的使用指南。


tune download meta-llama/Meta-Llama-3-8B \
    --output-dir <checkpoint_dir> \
    --hf-token <ACCESS TOKEN>


设置环境变量HF_TOKEN或将–HF令牌传递给命令,以验证您的访问权限。您可以在以下网址找到您的token https://huggingface.co/settings/tokens

Llama 3单设备LoRA微调的基本命令是

tune run lora_finetune_single_device --config llama3/8B_lora_single_device


Torchtune包含以下内置配方:

  • 单设备 和 [带FSDP的多设备] (https://github.com/pytorch/torchtune/blob/main/recipes/full_finetune_distributed.py) 上全量微调
  • 单设备带FSDP的多设备 上 LoRA 微调
  • 单设备 上 QLoRA 微调,使用 QLoRA 指定 配置

通过阅读 torchtune 入门,您可以找到有关微调Meta Llama模型的更多信息


Hugging Face PEFT LoRA

https://github.com/huggingface/peft

使用低秩适配(LoRA),Meta Llama作为量化的8位权重加载到GPU内存。

使用PEFT LoRA(链接)的拥抱脸微调非常简单——使用OpenAssistant数据集在Meta Llama 2 7b上运行的微调示例可以通过三个简单的步骤完成:

pip install trl
git clone https://github.com/huggingface/trl

python trl/examples/scripts/sft.py \
    --model_name meta-llama/Llama-2-7b-hf \
    --dataset_name timdettmers/openassistant-guanaco \
    --load_in_4bit \
    --use_peft \
    --batch_size 4 \
    --gradient_accumulation_steps 2 \
    --log_with wandb

这在单个GPU上大约需要16小时,使用不到10GB的GPU内存;将批量大小更改为8/16/32将使用超过11/16/25GB的GPU内存。
微调完成后,您将在名为“输出”的新目录中看到至少 adapter_config.jsonadapter_model.bin – 运行下面的脚本来推断基本模型和新模型,新模型是通过将基本模型与微调模型合并生成的:

import torch
from transformers import (
    AutoModelForCausalLM,
    AutoTokenizer,
    pipeline,
)
from peft import LoraConfig, PeftModel
from trl import SFTTrainer

model_name = "meta-llama/Llama-2-7b-chat-hf"
new_model = "output"
device_map = {"": 0}

base_model = AutoModelForCausalLM.from_pretrained(
    model_name,
    low_cpu_mem_usage=True,
    return_dict=True,
    torch_dtype=torch.float16,
    device_map=device_map,
)
model = PeftModel.from_pretrained(base_model, new_model)
model = model.merge_and_unload()

tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True)
tokenizer.pad_token = tokenizer.eos_token
tokenizer.padding_side = "right"

prompt = "Who wrote the book Innovator's Dilemma?"

pipe = pipeline(task="text-generation", model=base_model, tokenizer=tokenizer, max_length=200)
result = pipe(f"<s>[INST] {prompt} [/INST]")
print(result[0]['generated_text'])

pipe = pipeline(task="text-generation", model=model, tokenizer=tokenizer, max_length=200)
result = pipe(f"<s>[INST] {prompt} [/INST]")
print(result[0]['generated_text'])

QLoRA微调QLoRA(Q表示量化)比LoRA更具内存效率。在QLoRA中,预训练模型作为量化的4位权重加载到GPU。使用QLoRA进行微调也很容易运行——使用OpenAssistant微调Llama 2-7b的示例可以通过四个快速步骤完成:

git clone https://github.com/artidoro/qlora
cd qlora
pip install -U -r requirements.txt
./scripts/finetune_llama2_guanaco_7b.sh

在单个GPU上运行大约需要6.5小时,使用GPU的11GB内存。微调完成后,./script/finetune_llama2_guanaco_7b.sh 中指定的 output_dir 将有checkoutpoint-xxx 子文件夹,保存微调的适配器模型文件。要运行推理,请使用以下脚本:

from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig, pipeline
from peft import LoraConfig, PeftModel
import torch

model_id = "meta-llama/Llama-2-7b-hf"
new_model = "output/llama-2-guanaco-7b/checkpoint-1875/adapter_model" # change if needed
quantization_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_compute_dtype=torch.bfloat16,
    bnb_4bit_use_double_quant=True,
    bnb_4bit_quant_type='nf4'
)
model = AutoModelForCausalLM.from_pretrained(
    model_id,
    low_cpu_mem_usage=True,
    load_in_4bit=True,
    quantization_config=quantization_config,
    torch_dtype=torch.float16,
    device_map='auto'
)
model = PeftModel.from_pretrained(model, new_model)
tokenizer = AutoTokenizer.from_pretrained(model_id)

prompt = "Who wrote the book innovator's dilemma?"
pipe = pipeline(task="text-generation", model=model, tokenizer=tokenizer, max_length=200)
result = pipe(f"<s>[INST] {prompt} [/INST]")
print(result[0]['generated_text'])

Axolotl 是另一个开源库,您可以使用它来简化Llama 2的微调。
在这里 有一个很好的例子,使用Axolotl对Meta Llama进行微调,四个笔记本涵盖了整个微调过程(生成数据集、使用LoRA微调模型、评估和基准测试)。


QLoRA微调

注意:这仅在Meta Llama 2型号上进行了测试。

QLoRA(Q表示量化)比LoRA内存效率更高。在QLoRA中,预训练模型作为量化的4位权重加载到GPU。
使用QLoRA进行微调也很容易运行 – 使用OpenAssistant微调Llama 2-7b的示例可以通过四个快速步骤完成:

git clone https://github.com/artidoro/qlora
cd qlora
pip install -U -r requirements.txt
./scripts/finetune_llama2_guanaco_7b.sh

在单个GPU上运行大约需要6.5小时,使用GPU的11GB内存。微调完成后,./script/finetune_llama2_guanaco_7b.sh 中指定的 output_dir 将有 checkoutpoint-xxx 子文件夹,保存微调的适配器模型文件。要运行推理,请使用以下脚本:

from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig, pipeline
from peft import LoraConfig, PeftModel
import torch

model_id = "meta-llama/Llama-2-7b-hf"
new_model = "output/llama-2-guanaco-7b/checkpoint-1875/adapter_model" # change if needed
quantization_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_compute_dtype=torch.bfloat16,
    bnb_4bit_use_double_quant=True,
    bnb_4bit_quant_type='nf4'
)
model = AutoModelForCausalLM.from_pretrained(
    model_id,
    low_cpu_mem_usage=True,
    load_in_4bit=True,
    quantization_config=quantization_config,
    torch_dtype=torch.float16,
    device_map='auto'
)
model = PeftModel.from_pretrained(model, new_model)
tokenizer = AutoTokenizer.from_pretrained(model_id)

prompt = "Who wrote the book innovator's dilemma?"
pipe = pipeline(task="text-generation", model=model, tokenizer=tokenizer, max_length=200)
result = pipe(f"<s>[INST] {prompt} [/INST]")
print(result[0]['generated_text'])

注意:这仅在Meta Llama 2型号上进行了测试。


2024-07-16(二)