跳转到内容
主站 新闻 控制台

通过 100 步 GRPO 微调 3.5 亿参数模型,提升结构化输出能力

· Hugging Face
教程模型卡

本指南提供了一套完全公开且成本低廉的方法,用于显著提升小型模型对结构化输出的遵循能力。我们使用 TRL 库中的组相对策略优化(Group Relative Policy Optimization,GRPO)对 LFM2.5-350M 进行微调,并在 IFStruct 基准上进行评估。完整运行仅需约 500 个样本和 100 个训练步骤,规模足够小,可以在免费版 Colab 或 Kaggle GPU 上完成;相关内容已发布在 GitHub 上。结果表明,即使采用轻量级微调流程,模型在 IFStruct 基准上的性能也能从 22.6% 提升至 29.7%。

结构化输出是大语言模型(LLM)最常见的实际任务之一,但大多数基准会将其纳入更广泛的推理或信息抽取得分中,而不是单独进行衡量。模型能否可靠地按照要求的格式和结构返回有效、可解析的输出——也就是模式合规性(schema compliance)——往往决定了它是否能够真正接入下游系统。

请注意,这里介绍的训练流程并不是用于训练 IFStruct 博客中所述强化学习模型的流程。本 Notebook 并不旨在复现 IFStruct 基准得分,而是展示针对特定任务对较小模型进行微调后,如何提升其性能,使其达到与规模大得多的模型相当的水平。

前置条件

本指南分为两个部分,分别在不同环境中运行:

  • 微调需要 GPU。配套 Notebook 的规模适合在免费版 Colab 或 Kaggle GPU 上运行。

  • 评估可以通过 llama.cpp 在本地 MacBook 上运行(本文使用的是配备 Apple M5 Max 芯片和 36 GB 统一内存的 MacBook Pro)。llama.cpp 会提供一个兼容 OpenAI 的服务器,IFStruct 评估器将与该服务器通信。

我们需要使用 uv 进行 Python 工具管理,并使用 llama.cpp 提供模型服务。按照 Liquid AI 的 llama.cpp 部署文档,通过 Homebrew 安装 llama.cpp,并确认 llama-server 可用:

brew install llama.cpp
llama-server --version

在 LFM2.5-350M(基础模型)上评估 IFStruct

首先,让我们在 IFStruct 基准上评估 LFM2.5-350M,看看能否复现 21.1% 的报告得分。

IFStruct 是一个用于测试大语言模型输出有效性和模式遵循能力的基准。该基准在 Liquid4All/ifstruct 中开源,公开的基准数据集则托管在 Hugging Face 的 LiquidAI/ifstruct-v1.0 上。

git clone https://github.com/Liquid4All/ifstruct.git

为了进行评估对比,我们使用 llama.cpp 在 MacBook 上本地提供模型服务。这里使用 BF16 GGUF 模型(LiquidAI/LFM2.5-350M-GGUF)。

然后运行以下命令启动基础模型服务器:

llama-server \
-hf LiquidAI/LFM2.5-350M-GGUF:BF16 \
-c 32768 \
-np 4 \
-ngl 99 \
--alias LiquidAI/LFM2.5-350M \
--host 127.0.0.1 \
--port 8080
  • --alias:IFStruct 发送到兼容 OpenAI 的端点时使用的模型名称

  • -ngl 99:要求 llama.cpp 在可用时将所有层卸载到 GPU

  • -np 4:并行处理 4 个请求

  • -c 32768:提示词上下文的大小

服务器运行后,我们可以使用 2000 个样本运行完整基准:

uv run ifstruct-eval \
--model LiquidAI/LFM2.5-350M \
--base-url http://localhost:8080/v1 \
--api-key dummy \
--dataset data/test.jsonl \
--results-file results/lfm2.5-350m-llamacpp-base.json \
--n-threads 4 \
--max-tokens 2048 \
-v
============================================================
Model: LiquidAI/LFM2.5-350M
============================================================
Overall: 452/2000 passed (22.6%)
Average latency: 1453ms
By format:
JSON: 180/1000 passed (18.0%)
YAML: 272/1000 passed (27.2%)
By top-level structure:
Wrapper key 288/1011 passed (28.5%)
Bare list 164/989 passed (16.6%)
By entity type:
test__camera_review 6/83 passed (7.2%)
test__clinical_trial 20/104 passed (19.2%)
test__conference_schedule 7/87 passed (8.0%)
test__escaping__bug_report_batch 24/89 passed (27.0%)
test__escaping__config_snippet_audit 15/85 passed (17.6%)
test__escaping__customer_email_thread 5/73 passed (6.8%)
test__escaping__dialogue_sample 14/95 passed (14.7%)
test__escaping__interview_transcript_segment 21/80 passed (26.2%)
test__escaping__log_parser_examples 21/72 passed (29.2%)
test__escaping__pr_discussion 22/87 passed (25.3%)
test__escaping__repro_steps_batch 16/73 passed (21.9%)
test__escaping__screenplay_scene 16/92 passed (17.4%)
test__escaping__short_story_chapter 15/84 passed (17.9%)
test__escaping__support_ticket_batch 27/73 passed (37.0%)
test__escaping__terminal_session_notes 20/70 passed (28.6%)
test__event_ticket_booking 49/107 passed (45.8%)
test__gpu_review 6/94 passed (6.4%)
test__invoice 28/86 passed (32.6%)
test__job_posting 25/85 passed (29.4%)
test__real_estate_listing 31/82 passed (37.8%)
test__recipe 3/70 passed (4.3%)
test__rental_car_booking 27/79 passed (34.2%)
test__scientific_experiment 13/69 passed (18.8%)
test__travel_itinerary 21/81 passed (25.9%)
Common errors:
7228x required field missing
738x wrong item count
540x type mismatch
317x Unclosed code block
190x extraneous field 'notes'
181x extraneous field 'path'
175x extraneous field 'constraints'
170x extraneous field 'type'
170x missing code block
100x expected bare list, got wrapper

IFStruct 发布博客报告称,LFM2.5-350M 的得分为 21.1%。我们在本地使用 llama.cpp 和 BF16 的配置测得 22.6%,与 IFStruct 博客中报告的 21.1% 接近。我们将这一​​本地结果作为相同服务栈对比中的基线。

使用 TRL 对结构化输出进行 GRPO 微调

完整且可运行的流程位于配套 Notebook中。本节只介绍其中相关的部分。

训练数据

我们使用 nvidia/Nemotron-RL-instruction_following-structured_outputs 数据集,其中每个提示词都对应一个目标 JSON Schema 和预期字段数量。训练使用约 500 个样本。

由于 Nemotron 数据的分布与 IFStruct 评估数据不同,我们对提示词进行增强,以弥合两者之间的两个差异:

  • 40% 的样本会追加“将输出放在带围栏的代码块中返回”的指令,使模型学会遵循格式指令,而不是始终输出原始 JSON。

  • 另有互不重叠的 20% 样本会被转换为顶层数组任务(将 Schema 包装在一个 array 中,并要求指定的元素数量),以训练裸列表输出和元素数量遵循能力。

模型与 LoRA

我们加载 LiquidAI/LFM2.5-350M,并为其附加 LoRA 适配器。由于 LFM2.5 采用混合注意力/卷积架构,因此我们针对 LFM 特有的模块名称:

lora_config = LoraConfig(
r=16,
lora_alpha=32,
bias="none",
task_type="CAUSAL_LM",
target_modules=[
"q_proj", "k_proj", "v_proj", "out_proj