LLM 课程文档

实践练习:使用 GRPO 微调模型

Hugging Face's logo
加入 Hugging Face 社区

并获得增强的文档体验

开始使用

Ask a Question Open In Colab

实践练习:使用 GRPO 微调模型

既然您已经了解了理论,那么让我们将其付诸实践吧!在此练习中,您将使用 GRPO 微调模型。

本练习由 LLM 微调专家 @mlabonne 撰写。

安装依赖项

首先,让我们为本次练习安装依赖项。

!pip install -qqq datasets==3.2.0 transformers==4.47.1 trl==0.14.0 peft==0.14.0 accelerate==1.2.1 bitsandbytes==0.45.2 wandb==0.19.7 --progress-bar off
!pip install -qqq flash-attn --no-build-isolation --progress-bar off

现在我们将导入必要的库。

import torch
from datasets import load_dataset
from peft import LoraConfig, get_peft_model
from transformers import AutoModelForCausalLM, AutoTokenizer
from trl import GRPOConfig, GRPOTrainer

导入并登录 Weights & Biases

Weights & Biases 是用于记录和监控实验的工具。我们将使用它来记录我们的微调过程。

import wandb

wandb.login()

您可以在不登录 Weights & Biases 的情况下完成此练习,但建议登录以跟踪您的实验并解释结果。

加载数据集

现在,让我们加载数据集。在本例中,我们将使用 mlabonne/smoltldr 数据集,其中包含短篇故事列表。

dataset = load_dataset("mlabonne/smoltldr")
print(dataset)

加载模型

现在,让我们加载模型。

在此练习中,我们将使用 SmolLM2-135M 模型。

这是一个小型 135M 参数模型,可在有限的硬件上运行。这使得该模型非常适合学习,但它并不是最强大的模型。如果您可以访问更强大的硬件,可以尝试微调更大的模型,例如 SmolLM2-1.7B

model_id = "HuggingFaceTB/SmolLM-135M-Instruct"
model = AutoModelForCausalLM.from_pretrained(
    model_id,
    torch_dtype="auto",
    device_map="auto",
    attn_implementation="flash_attention_2",
)
tokenizer = AutoTokenizer.from_pretrained(model_id)

加载 LoRA

现在,让我们加载 LoRA 配置。我们将利用 LoRA 来减少可训练参数的数量,从而减少微调模型所需的内存占用。

如果您不熟悉 LoRA,可以在第 11 章中阅读更多信息。

# Load LoRA
lora_config = LoraConfig(
    task_type="CAUSAL_LM",
    r=16,
    lora_alpha=32,
    target_modules="all-linear",
)
model = get_peft_model(model, lora_config)
print(model.print_trainable_parameters())
Total trainable parameters: 135M

定义奖励函数

如上一节所述,GRPO 可以使用任何奖励函数来改进模型。在本例中,我们将使用一个简单的奖励函数,它鼓励模型生成长度为 50 个标记的文本。

# Reward function
ideal_length = 50


def reward_len(completions, **kwargs):
    return [-abs(ideal_length - len(completion)) for completion in completions]

定义训练参数

现在,让我们定义训练参数。我们将使用 GRPOConfig 类以典型的 transformers 风格定义训练参数。

如果这是您第一次定义训练参数,您可以查看 TrainingArguments 类以获取更多信息,或查看第 2 章以获取详细介绍。

# Training arguments
training_args = GRPOConfig(
    output_dir="GRPO",
    learning_rate=2e-5,
    per_device_train_batch_size=8,
    gradient_accumulation_steps=2,
    max_prompt_length=512,
    max_completion_length=96,
    num_generations=8,
    optim="adamw_8bit",
    num_train_epochs=1,
    bf16=True,
    report_to=["wandb"],
    remove_unused_columns=False,
    logging_steps=1,
)

现在,我们可以使用模型、数据集和训练参数初始化训练器并开始训练。

# Trainer
trainer = GRPOTrainer(
    model=model,
    reward_funcs=[reward_len],
    args=training_args,
    train_dataset=dataset["train"],
)

# Train model
wandb.init(project="GRPO")
trainer.train()

在单个 A10G GPU 上训练大约需要 1 小时,该 GPU 可在 Google Colab 或通过 Hugging Face Spaces 获得。

在训练期间将模型推送到 Hub

如果我们将 push_to_hub 参数设置为 True,并将 model_id 参数设置为有效的模型名称,则模型将在训练期间推送到 Hugging Face Hub。如果您想立即开始测试模型,这非常有用!

解释训练结果

GRPOTrainer 会记录您的奖励函数中的奖励、损失以及一系列其他指标。

我们将重点关注奖励函数中的奖励和损失。

如您所见,随着模型的学习,奖励函数中的奖励值趋近于 0。这是一个很好的迹象,表明模型正在学习生成正确长度的文本。

Reward from reward function

您可能会注意到,损失从零开始,然后在训练期间增加,这似乎违反直觉。这种行为在 GRPO 中是预期的,并且与算法的数学公式直接相关。GRPO 中的损失与 KL 散度(相对于原始策略的上限)成正比。随着训练的进行,模型学习生成更符合奖励函数的文本,导致它与初始策略的偏差更大。这种不断增加的偏差反映在不断上升的损失值中,这实际上表明模型正在成功地适应以优化奖励函数。

Loss

保存并发布模型

让我们与社区分享模型!

merged_model = trainer.model.merge_and_unload()
merged_model.push_to_hub(
    "SmolGRPO-135M", private=False, tags=["GRPO", "Reasoning-Course"]
)

生成文本

🎉 您已成功使用 GRPO 微调了模型!现在,让我们使用模型生成一些文本。

首先,我们将定义一个非常长的文档!

prompt = """
# A long document about the Cat

The cat (Felis catus), also referred to as the domestic cat or house cat, is a small 
domesticated carnivorous mammal. It is the only domesticated species of the family Felidae.
Advances in archaeology and genetics have shown that the domestication of the cat occurred
in the Near East around 7500 BC. It is commonly kept as a pet and farm cat, but also ranges
freely as a feral cat avoiding human contact. It is valued by humans for companionship and
its ability to kill vermin. Its retractable claws are adapted to killing small prey species
such as mice and rats. It has a strong, flexible body, quick reflexes, and sharp teeth,
and its night vision and sense of smell are well developed. It is a social species,
but a solitary hunter and a crepuscular predator. Cat communication includes
vocalizations—including meowing, purring, trilling, hissing, growling, and grunting—as
well as body language. It can hear sounds too faint or too high in frequency for human ears,
such as those made by small mammals. It secretes and perceives pheromones.
"""

messages = [
    {"role": "user", "content": prompt},
]

现在,我们可以使用模型生成文本。

# Generate text
from transformers import pipeline

generator = pipeline("text-generation", model="SmolGRPO-135M")

## Or use the model and tokenizer we defined earlier
# generator = pipeline("text-generation", model=model, tokenizer=tokenizer)

generate_kwargs = {
    "max_new_tokens": 256,
    "do_sample": True,
    "temperature": 0.5,
    "min_p": 0.1,
}

generated_text = generator(messages, generate_kwargs=generate_kwargs)

print(generated_text)

结论

在本章中,我们学习了如何使用 GRPO 微调模型。我们还学习了如何解释训练结果并使用模型生成文本。

< > 在 GitHub 上更新