使用GRPO训练调度事件的语言模型!
参考:https://huggingface.co/blog/anakin87/qwen-scheduler-grpo
现在是2025年,在DeepSeek热潮之后,每个人都想使用GRPO训练自己的推理模型。
作为一名实践者,我也想这样做:仅使用提示和奖励来训练语言模型是一件非常有趣的事情——不像监督微调那样需要完整的输出。
你在网上能找到的大多数例子都是在GSM8K或Countdown游戏上训练模型。我想尝试一些原创的东西,并亲自动手。
于是我想:我能否让模型从事件列表和优先级中创建一个日程安排?
我的第一次实验表明,ChatGPT通常可以解决这类问题,而小型语言模型(小于14B)则struggled。这是一个很好的挑战!
我没有意识到的是,选择一个原创问题将迫使我思考问题设置、生成数据、选择基础模型、设计奖励函数,并进行多轮训练,希望我的模型能学到一些东西。
这里有很多东西需要学习,这正是我想在这篇文章中与你分享的内容。
你可以在👑 🗓️ Qwen Scheduler GRPO仓库中找到所有代码。
跟着我一起学习吧!
本文主要是关于我的实践经验。了解一些GRPO的理论知识会有所帮助。你可以在网上找到一些资源,比如DeepSeekMath论文和Hugging Face推理课程。
问题定义
让我们描述一下我们希望语言模型解决的问题。
我们给模型一个事件列表(包含开始/结束时间)并告诉它哪些是高优先级的。目标是创建一个日程安排,使所选事件的总加权持续时间最大化。
在这个设置中,优先级事件权重为2,普通事件权重为1。
📌 你可能会注意到,问题定义是清晰合理的,但有点任意。也许你更喜欢最大化利润,或者也许一个塞满的日程表并不是你想要的。这完全没问题。那将是一个不同的问题,你也可以用GRPO训练一个模型来解决。
我认为一旦你能在提示中向模型清楚地解释任务,找出如何奖励好的输出,有时还能识别模型中要培养的行为,你就处于一个尝试使用GRPO的好位置。稍后我会详细讨论这点。
让我们看一个问题示例。
示例输入
以下是提示的简短版本(你可以在下面的文章中找到完整提示)。
任务:根据给定的事件创建优化的日程安排。
规则:...
你必须使用这种格式:
<think>...</think>
<schedule>
<event>
<n>...</n>
<start>...</start>
<end>...</end>
</event>
...
</schedule>
---
事件:
- Event A (01:27 - 01:42)
- Event B (01:15 - 02:30)
- Event C (15:43 - 17:43)
优先级:
- Event B
示例输出
<think>详细的推理过程</think>
<schedule>
<event>
<n>Event B</n>
<start>01:15</start>
<end>02:30</end>
</event>
<event>
<n>Event C</n>
<start>15:43</start>
<end>17:43</end>
</event>
</schedule>
经过一些研究,我发现这类问题属于区间调度。
这个特定问题是加权区间调度问题的一个变体,可以使用动态规划有效地解决。
这很好,因为它使我们能够轻松计算任何给定输入的最佳可能分数,这是我们的模型在训练期间要达到的目标。
数据集生成
现在问题已经定义明确,我们可以开始构建数据集用于训练和评估模型。
数据集中每一行的核心就是一个包含事件列表和优先级的提示,供模型进行调度。
与监督微调不同,我们不需要提供模型应该遵循的参考完成。这也是为什么在数学等可验证领域中,构建GRPO数据集通常更容易的原因之一。
我们还在每一行中包含最优分数(最大可能的加权持续时间)。模型在训练期间不会看到这个,但我们用它来计算推动模型朝正确方向前进的奖励。
鉴于这些要求,编写数据集生成脚本相对容易。
- 我们使用不同类别的事件名称(🎶音乐节、🎓大学、🧑💻技术会议等)。
- 每个示例包含随机数量的事件(在4到8之间)和不同的持续时间。
- 我们确保一些事件重叠。
- 我们随机标记一些事件为优先级。
我们为训练集生成了500个示例,为测试集生成了100个示例。
你可以在这里找到数据集生成脚本。
生成的数据集可以在Hugging Face上获取。
训练
完整的📓训练笔记本在这里。
现在有几个训练库支持GRPO。
Hugging Face TRL是一个很好的选择,它还支持使用vLLM进行更快的样本生成。
在我的案例中,我决定使用Unsloth。这是一个修补TRL的库,可以大大减少GPU内存使用。
我使用了NVIDIA A6000 GPU(48GB VRAM),但通过一些小的调整和一点耐心,你可以在16GB VRAM的免费Colab/Kaggle实例上复现相同的实验。
如果你GPU资源不足,Unsloth可以很好地用于实验,但正如我们稍后将看到的,它有一些令人沮丧的bug。
选择并加载要训练的模型
我决定训练Qwen2.5-Coder-7B-Instruct,这是Qwen系列中特定于代码的语言模型。
这个决定有些经验主义,基于两个主要考虑:
-
我首先尝试了较小的模型(0.5B和1.5B)。观察这些模型对我的调度提示的输出,我注意到这些非常小的模型产生的推理几乎没有意义。这是我的第一个教训:如果基础模型的预训练或规模使其能力与所需的相差太远,GRPO不能创造奇迹。
-
我使用代码模型而不是通用模型,部分原因是这对数学任务很常见,部分是因为我注意到这个模型已经很擅长遵循所需的格式(
<think>
,<schedule>
等)。
现在我们可以使用Unsloth加载模型。我们将使用QLoRA进行训练以节省GPU资源。
from unsloth import FastLanguageModel
max_seq_length = 2048
lora_rank = 32
model, tokenizer = FastLanguageModel.from_pretrained(model_name = "Qwen/Qwen2.5-Coder-7B-Instruct",max_seq_length = max_seq_length,load_in_4bit = True,fast_inference = True,max_lora_rank = lora_rank,gpu_memory_utilization = 0.85, # 如果内存不足请减小这个值
)
model = FastLanguageModel.get_peft_model(model,r = lora_rank,target_modules = ["q_proj", "k_proj", "v_proj", "o_proj","gate_proj", "up_proj", "down_proj",], # 如果内存不足可以移除QKVOlora_alpha = lora_rank,use_gradient_checkpointing = "unsloth", # 启用长上下文微调random_state = 3407,)
如果你的VRAM少于48GB,可以调整几个参数:gpu_memory_utilization
、lora_rank
和target_modules
;后两者会影响你的模型能学习的量。
数据集准备
我们的数据集中的每个示例都包含事件和优先级。
我们预处理数据集,以系统和用户消息的形式添加常规任务描述和指令。
import datasets
SYSTEM_PROMPT = """You are a precise event scheduler.
1. First, reason through the problem inside <think> and </think> tags. Here you can create drafts,
compare alternatives, and check for mistakes.
2. When confident, output the final schedule inside <schedule> and </schedule> tags.
Your schedule must strictly follow the rules provided by the user."""USER_PROMPT ="""Task: create an optimized schedule based on the given events.
Rules:
- The schedule MUST be in strict chronological order.
Do NOT place priority events earlier unless their actual start time is earlier.
- Event start and end times are ABSOLUTE. NEVER change, shorten, adjust, or split them.
- Priority events (weight = 2) carry more weight than normal events (weight = 1),
but they MUST still respect chronological order.
- Maximize the sum of weighted event durations.
- No overlaps allowed. In conflicts, include the event with the higher weighted time.
- Some events may be excluded if needed to meet these rules.
You must use this format:
<think>...</think>
<schedule>
<event>
<n>...</n>
<start>...</start>
<end>...</end>
</event>
...
</schedule>
---
"""ds = datasets.load_dataset("anakin87/events-scheduling", split="train")
ds = ds.map(lambda x: {"prompt": [{"role": "system", "content": SYSTEM_PROMPT},{"role": "user", "content": USER_PROMPT + x["prompt"]},]}
)
奖励函数
GRPO是一种强化学习算法,其中为每个提示生成多个样本(在我们的例子中是8个)。在训练期间,模型的参数会更新以生成高奖励的响应。
因此,虽然我们不需要数据集中的完成,但奖励函数的设计至关重要。
在像从GSM8K学习这样的更简单问题中,常见的选择是定义多个奖励函数并将它们相加:
- 一个检查输出格式是否正确。
- 另一个检查最终答案是否与已知解决方案匹配。
有关从GSM8K学习的绝佳示例,请查看William Brown的这个gist。有关为TRL/Unsloth创建自定义奖励函数的指南,请参阅文档。
在我们的实验中,我们可以轻松设计一个用于格式的奖励函数。
import re
overall_pattern = (r"<think>.+</think>.*<schedule>.*(<event>.*<n>.+</n>.*<start>\d{2}:\d{2}</start>.*"
r"<end>\d{2}:\d{2}</end>.*</event>)+.*</schedule>")
overall_regex = re.compile(overall_pattern, re.DOTALL)def format_reward(prompts, completions, **kwargs):responses = [completion[0]['content'] for completion in completions]return [0.0 if not overall_regex.match(response) else 10.0 for response in responses]
现在,奖励日程安排本身的质量更难。
一个有效的日程安排具有以下特点:
- 事件来自原始提示(没有虚构的事件或更改的时间)。
- 事件按时间顺序排序。
- 没有重叠的事件。
- 至少有两个事件。
我们还希望鼓励模型产生一个能最大化总加权持续时间的日程安排。
在确定下面所示的解决方案之前,我尝试了不同数量的奖励函数。我也得出了一些观察结果。
我尝试使用一个单一的评分奖励函数,如果日程安排有效(满足上述所有标准)则给出schedule_score/optimal_score
,否则给出0。结果表明这是一个糟糕的想法,因为它太不连续了,大多数时候返回0,没有提供足够的信号来指导模型的学习。
另一方面,我尝试使用几个奖励函数,每个上述要求一个:现有事件、时间顺序、无重叠等。在这种情况下,我发现即使模型正在学习一些东西,但训练并不能有效地产生良好的日程安排。使用太多奖励函数也可能不好。
在"太多奖励"阶段,我遇到了一个经典的RL问题:奖励黑客。
我最初忘记丢弃少于两个事件的日程安排。突然,我的奖励看起来很棒!
模型在格式、时间顺序、无重叠等方面获得了高分…
我查看了实际输出,发现它找到了一个漏洞:它只生成包含一个事件的日程安排(通常是高优先级的)。这完全满足了我的大多数单独奖励函数。
这不是模型聪明;这是我的奖励设置可被利用。一次很好的经验。🙃
最终,我使用了一个鼓励产生按时间顺序排序日程安排的奖励函数和另一个最大化分数的函数。正如你在下面看到的,我试图在这两个奖励函数中包含并因此偏爱其他要求。
def sorted_events_reward(completions, **kwargs):scores = []responses = [completion[0]['content'] for completion in completions]for response in responses:scheduled_events = get_events(response)# not a valid schedule: should be discardedif len(scheduled_events) < 2:scores.append(0.0)continuescheduled_events_minutes = [(ev[0], time_to_minutes(ev[1]), time_to_minutes(ev[2]))for ev in scheduled_events]if all(scheduled_events_minutes[i][1] < scheduled_events_minutes[i+1][1]for i in range(len(scheduled_events_minutes)-1)):scores.append(20.0)else:scores.append(0)return scoresdef score_reward(prompts, completions, events, priority_events, optimal_score, **kwargs):scores = []responses = [completion[0]['content'] for completion in completions]for content, valid_events, priorities, opt_score in zip(responses, events, priority_events, optimal_score):scheduled_events = get_events(content)# Get valid scheduled eventsexisting_events = {ev for ev in scheduled_events if [ev[0], ev[1], ev[2]] in valid_events}# penalize choosing nonexistent events or less than 2 events (not a valid schedule)if len(existing_events)<len(scheduled_events) or len(existing_events) < 2:scores.append(0.0)continue# Convert to minutesexisting_events_minutes = [(ev[0], time_to_minutes(ev[1]), time_to_minutes(ev[2]))for ev in existing_events]# remove overlapping events and remove both events - to penalize overlapsoverlapping_events = set()for j in range(len(existing_events_minutes)):for k in range(j + 1, len(existing_events_minutes)):if (existing_events_minutes[j][1] <= existing_events_minutes[k][2] andexisting_events_minutes[j][2] >= existing_events_minutes[k][1]):overlapping_events.add(existing_events_minutes[j])overlapping_events.add(existing_events_minutes[k])existing_events_minutes = [ev for ev in existing_events_minutesif ev not in overlapping_events]# Calculate scorescore = sum(2 * (ev[2] - ev[1]) if ev[0] in prioritieselse ev[2] - ev[1] for ev in existing_events_minutes)scores.append((score/opt_score) * 70)return scores
简而言之,在我的实验中,我使用了以下奖励函数:
- 格式 (0-10)
- 排序事件 (0-20)
- 分数 (0-70)
累积奖励可以在0到100之间变化。
我在这一步上进行了很多迭代。正如我们将看到的,它仍然不完美,但确实让模型学习到了一些东西。
设置训练配置并开始训练!
from trl import GRPOConfig, GRPOTrainertokenized_prompts = [tokenizer.apply_chat_template(prompt, tokenize=True, add_generation_prompt=True)for prompt in ds['prompt']]
exact_max_prompt_length = max([len(tokenized_prompt) for tokenized_prompt in tokenized_prompts])
max_prompt_length = 448 # 手动调整new_model_id="anakin87/qwen-scheduler-7b-grpo"
training_args = GRPOConfig(learning_rate = 8e-6,adam_beta1 = 0.9,adam_beta2 = 0.99,weight_decay = 0.1,warmup_ratio = 0.01,lr_scheduler_type = "cosine",optim = "paged_adamw_8bit",logging_steps = 1,per_device_train_batch_size = 8,gradient_accumulation_steps = 1,num_generations = 8, # 如果内存不足请减小max_prompt_length = max_prompt_length,max_completion_length = max_seq_length - max_prompt_length,max_grad_norm = 0.1,output_dir = "outputs",overwrite_output_dir = True,push_to_hub = True,hub_model_id=new_model_id,hub_strategy="every_save",save_strategy="steps",save_steps=50,save_total_limit=1,num_train_epochs=3,
)trainer = GRPOTrainer(model = model,processing_class = tokenizer,reward_funcs=[format_reward,sorted_events_reward,score_reward,],args = training_args,train_dataset = ds,
)trainer.train()
max_prompt_length
是提示的最大长度。更长的提示将被截断。
我们可以轻松计算这个值,然后手动调整它。
num_generations
是GRPO的一个关键参数,表示为每个提示生成的样本数量。
该算法基于比较不同样本来学习,并引导模型生成具有更高奖励的样本。
更多样本给它提供了更多学习信息,可能导致更好的结果,但生成它们需要更多时间和内存。
有关其他GRPOConfig参数的详细信息,请查看TRL API参考。
结果
训练曲线
让我们看看训练曲线。
关注奖励,我们看到模型在训练期间有所改进。从一开始,样本在格式对齐方面就获得了很好的分数。尊重时间顺序和为日程安排获得良好分数随着时间的推移而提高,表明模型确实学习了奖励函数中形式化的行为。
其他记录的指标,如reward_std
(奖励组内的平均标准差)和kl
(模型与参考模型之间的平均KL散度)显示可接受的值。
你可以在这个Weight and Biases报告中探索所有训练曲线和指标。
检查样本
在训练期间,我们记录了生成的样本的随机子集。
你可以在这里浏览完整日志。
检查这些完成很有趣且富有洞察。这就是我如何意识到较小的模型根本不理解:随着时间的推移,它们的推理没有明显改善。
以下是不同训练阶段同一输入提示的示例:
事件:
- Analyzing product performance (04:33 - 06:03)
- One-on-one with manager (08:41 - 08:56)
- Client call with Acme Corp (09:13 - 10:58)
- Meeting with Lisa at café (10:14 - 11:14)
- Updating website content (12:21 - 13:36)
- Preparing PTO handover (16:07 - 17:37)
- Marketing standup on Zoom (17:58 - 19:43)
- Brainstorming with Luke and Patrick (19:11 - 19:56)
优先级:
- Analyzing product performance
- Meeting with Lisa at café
步骤 473/1500
<think>
At first glance, the events overlap in the time slot from 10:14 to 11:14. The priority event
"Meeting with Lisa at café" is higher in weight compared to "Client call with Acme Corp", so we must
include it. However, this will exclude the client call if we want to prioritize "Meeting with Lisa
at café". To resolve this, we need to decide whether to exclude the client call or the brainstorming
session (19:11 - 19:56) which is a normal event.Since "Meeting with Lisa at café" is a priority event and it overlaps with the client call, we should
include "Meeting with Lisa at café" and exclude the client call. This will give us more time for
"Updating website content" (12:21 - 13:36) and "Preparing PTO handover" (16:07 - 17:37), which are
also normal events.Here is the adjusted schedule:
[...]
This schedule maximizes the sum of weighted event durations while respecting all the rules provided.
</think>
<schedule>
<event>
<n>Analyzing product performance</n>
<start>04:33</start>
<end>06:03</end>
</event>
<event>
<n>One-on-one with manager</n>
<start>08:41</start>
<end>08:56</end>
</event>
<event>
<n>Client call with Acme Corp</n>
<start>09:13</start>
<end>10:14</end>
</event>
<event>
<n>Meeting with Lisa at café</n>
<start>10:14</start>
<end>11:14</end>
</event>
<event>
<n>Updating website content</n>
<start>12:21</start>
<end>13:36</end>
</event>
<event>
<n>Preparing PTO handover</n>
<start>16:07</start>
<end>17:37</end>
</event>
<event>
<n>Brainstorming with Luke and Patrick</n>
<start>19:11</start>
<end>19:56</end>
</event>
</schedule>
好多了!在这里,模型明确考虑了权重并生成了有效的日程安排。
步骤 1470/1500
<think>
The goal is to create a schedule that maximizes the sum of weighted event durations while respecting
the chronological order, priorities, and non-overlapping constraints. Let\'s analyze the events and
prioritize them:1. **Analyzing product performance**: Start time: 04:33, End time: 06:03, Priority: 2
2. **One-on-one with manager**: Start time: 08:41, End time: 08:56, Priority: 1
3. **Client call with Acme Corp**: Start time: 09:13, End time: 10:58, Priority: 1
4. **Meeting with Lisa at café**: Start time: 10:14, End time: 11:14, Priority: 2
5. **Updating website content**: Start time: 12:21, End time: 13:36, Priority: 1
6. **Preparing PTO handover**: Start time: 16:07, End time: 17:37, Priority: 1
7. **Marketing standup on Zoom**: Start time: 17:58, End time: 19:43, Priority: 1
8. **Brainstorming with Luke and Patrick**: Start time: 19:11, End time: 19:56, Priority: 1Given the priorities, we must ensure that "Analyzing product performance" and "Meeting with Lisa
at café" are included. Let\'s try to fit the rest while avoiding overlaps:1. **Analyzing product performance**: 04:33 - 06:03 (Priority 2)
2. **One-on-one with manager**: 08:41 - 08:56 (Priority 1)
3. **Client call with Acme Corp**: 09:13 - 10:58 (Priority 1)
4. **Meeting with Lisa at café**: 10:14 - 11:14 (Priority 2)
5. **Updating website content**: 12:21 - 13:36 (Priority 1)
6. **Preparing PTO handover**: 16:07 - 17:37 (Priority 1)The next event, "Marketing standup on Zoom", starts at 17:58, but the availability is only until
19:43. We can fit "Brainstorming with Luke and Patrick" from 19:11 to 19:56 before the standup.1. **Analyzing product performance**: 04:33 - 06:03 (Priority 2)
2. **One-on-one with manager**: 08:41 - 08:56 (Priority 1)
3. **Client call with Acme Corp**: 09:13 - 10:58 (Priority 1)
4. **Meeting with Lisa at café**: 10:14 - 11:14 (Priority 2)
5. **Updating website content**: 12:21 - 13:36 (Priority 1)
6. **Preparing PTO handover**: 16:07 - 17:37 (Priority 1)
7. **Brainstorming with Luke and Patrick**: 19:11 - 19:56 (Priority 1)Final schedule:
- Analyzing product performance: 04:33 - 06:03
- One-on-one with manager: 08:41 - 08:56
- Client call with Acme Corp: 09:13 - 10:58
- Meeting with Lisa at café: 10:14 - 11:14
- Updating website content: 12:21 - 13:36
- Preparing PTO handover: 16:07 - 17:37
- Brainstorming with Luke and Patrick: 19:11 - 19:56This schedule respects the chronological order, includes the high-priority events, and avoids
any overlaps.
</think>
<schedule>
<event>
<n>Analyzing product performance</n>
<start>04:33</start>
<end>06:03</end>
</event>
<event>
<n>One-on-one with manager</n>
<start>08:41</start>
<end>08:56</end>
</event>
<event>
<n>Client call with Acme Corp</n>
<start>09:13</start>
<end>10:58</end>
</event>
<event>
<n>Meeting with Lisa at café</n>
<start>10:14</start>
<end>11:14</end>
</event>
<event>
<n>Updating website content</n>
<start>12:21</start>
<end>13:36</end>
</event>
<event>
<n>Preparing PTO handover</n>
<start>16:07</start>
<end>17:37</end>
</event>
<event>
<n>Brainstorming with Luke and Patrick</n>
<start>19:11</start>
<end>19:56</end>
</event>
</schedule>
有趣的是…在这个样本中,尽管有长篇的推理过程,模型仍然在最终日程安排中放入了两个重叠的事件。
查看样本很好,但我们需要系统性的评估。
关于"啊哈时刻"
在DeepSeek-R1论文中,作者展示了在GRPO训练期间出现的"啊哈时刻",其中"模型学会使用拟人化语调重新思考"。
这是他们模型和GRPO的卖点之一,促使从业者在训练期间寻找/复现这种行为。
最近的研究(1; 2)对此提出了一些质疑。
他们发现,在任何GRPO训练开始之前,基础模型中就可以找到类似的"啊哈时刻"。
基于这些令人信服的原因,我没有花时间寻找"啊哈时刻"。
不过,我发现这方面的研究非常有趣,特别是努力区分从基础模型中引出已有行为与教授全新行为之间的差异。
评估
对于评估,我们可以使用我们的事件调度数据集的测试集,我们的模型以前从未见过这些数据。
我们将评估阶段分为两个步骤:
- 推理:为每个测试提示生成一个日程安排。
- 评分:根据我们的规则检查每个生成的日程安排(格式正确,>=2个事件,只有现有事件,按时间顺序排列,无重叠)。
如果任何规则被违反,该日程安排在该提示中的得分为0。如果有效,其得分为(weighted_duration/optimal_weighted_duration) * 100
。
你可以在GitHub仓库中找到这些脚本。
❌ Unsloth 的bug:在推理过程中,我遇到了一个问题。用Unsloth训练的模型无法可靠地转换为标准的Hugging Face Transformers模型;尝试这样做可能会得到一个不同的模型。
这是一个已知问题。如果我需要将其用于生产工作,比如用vLLM提供服务,这将是一个主要障碍,令人相当沮丧。
对于这个实验,我只是使用Unsloth运行评估推理。
由于Unsloth修补了TRL,使用TRL很容易调整代码,它更稳定。只需注意,你将需要更多的GPU VRAM。
我想比较qwen-scheduler-7b-grpo(我们的模型)、Qwen2.5-Coder-7B-Instruct(原始模型)和Qwen2.5-Coder-14B-Instruct(同一系列的更大模型)。
由于样本表明模型可能在第2个和第3个epoch之间有所下降,我还评估了第2个epoch结束时的检查点。
模型 | 格式错误 | <2个事件 | 重叠 | 未排序 | 不存在 | 有效日程安排 | 平均分数 |
---|---|---|---|---|---|---|---|
Qwen2.5-Coder-7B-Instruct | 3 | 1 | 31 | 29 | 27 | 9 | 8.05 |
Qwen2.5-Coder-14B-Instruct | 1 | 1 | 38 | 6 | 6 | 48 | 45.85 |
qwen-scheduler-7b-grpo | 0 | 0 | 36 | 0 | 1 | 62 | 58.54 |
qwen-scheduler-7b-grpo (第2个epoch) | 0 | 0 | 30 | 2 | 1 | 67 | 62.25 |
快速观察:
- GRPO确实有效!它在引导模型产生期望行为方面相当有效。
- 我们调优的模型在这个任务上甚至优于一个两倍大小的模型。
- 模型几乎完美地学习了格式、时间顺序和只使用现有事件。
- 模型仍然在处理重叠方面存在困难,这在测试集的相当大一部分中很明显。
如何改进?
我用于这个项目的时间和计算资源已经用完,但这是我接下来会尝试的一些改进方法。
主要问题显然是重叠。我们看到模型没有有效地学会避免它们。此外,第3个epoch中的轻微性能下降可能表明模型正在学习次优策略。
关于奖励函数的想法:
- 更强的重叠惩罚:在
score_reward
函数中,我们从分数计算中移除重叠事件。我们可以实施更严厉的惩罚… - 专门的重叠奖励:或者,添加一个只检查重叠的奖励函数。
让我们也记住,默认情况下奖励函数是相加的,所以根据我们如何设计惩罚,两种不同的方法在数学上可能是等价的。
结论和关键学习
在本文中,我们通过使用GRPO对语言模型进行后训练,使其能够完成一个新的可验证任务:从事件列表和优先级创建日程安排。
我们涵盖了问题定义、数据集生成、基础模型选择、奖励函数设计、使用Unsloth进行训练和评估。
亲自动手教会了我关于GRPO和应用强化学习于LLMs的几个方面。
GRPO对可验证任务很酷
它简化了典型的RL设置(例如在PPO中使用的):没有价值模型;奖励模型通常被确定性奖励函数替代(使用可验证奖励的强化学习)。由于你的数据集只需要提示(不需要完成),数据收集变得比SFT更容易、更便宜。
引导
使用GRPO和类似算法更多的是从训练模型中引导出期望行为,而不是教它完全新的东西。如果你需要根本性的新技能,指令微调(和蒸馏)可能更有效(参见强化学习真的能激励LLMs中的推理能力超越基础模型吗?论文)。如果你对这些主题感兴趣,请关注Nathan Lambert和Interconnects博客。
基础模型很重要
如果基础模型在采样期间从未在任务上表现出有希望的行为,GRPO可能对你的问题无效。你可能首先需要一个更大或更好的基础模型。
"啊哈时刻"可能被过度宣传
在DeepSeek-R1论文中,作者表明在GRPO期间"模型学会使用拟人化语调重新思考"。奇迹?最近的研究表明基础模型中也存在类似行为。
奖励函数设计至关重要
你的奖励应该捕捉你的目标,提供可学习的信号(对模型的鼓励),并且要健壮。如果它们不健壮,你可能会遇到奖励黑客:模型找到捷径来最大化奖励,而不是真正解决你心中的问题。这既有趣又令人沮丧😅
Unsloth:节省GPU很好,但要小心
如果你没有太多GPU或处于实验阶段,Unsloth可能很有帮助。这些人在GPU效率方面做了令人印象深刻的工作。然而,目前该库带有难以解决的bug,使其不适合严肃的用例。如果你有足够的VRAM,TRL会更稳定。
如果你喜欢这篇文章,欢迎在Hugging Face和LinkedIn上关注我。
如果你注意到任何错误或不准确之处,请随时联系我。
资源和参考
Qwen Scheduler GRPO
- GitHub仓库:这里你可以找到我用于这个实验的所有代码。
- Hugging Face集合:数据集和模型。
GRPO论文和资源
- DeepSeekMath: 推动开放语言模型数学推理的极限
- Hugging Face推理课程
- DeepSeek-R1: 通过强化学习激励LLMs中的推理能力
- R1-Zero类训练中可能没有啊哈时刻 — 一项初步研究
- 理解R1-Zero类训练:一个批判性视角
- 强化学习真的能激励LLMs中的推理能力超越基础模型吗?
- Nathan Lambert的Interconnects博客
Updating website content
12:21
13:36
Preparing PTO handover
16:07
17:37
Marketing standup on Zoom
17:58
19:43
Brainstorming with Luke and Patrick
19:11
19:56
在这个阶段,模型展示了有希望的能力来反思给定的约束,但错误地改变了一些事件的时间以最大化花费的时间。步骤 973/1500
To create an optimized schedule, I need to prioritize events based on provided weights and ensure no overlaps. The priority events are "Analyzing product performance" and "Meeting with Lisa at café". Let\'s evaluate the schedule step-by-step.
- Analyzing product performance (04:33 - 06:03) - This is a priority event (weight = 2).
- One-on-one with manager (08:41 - 08:56) - This is a normal event (weight = 1).
- Client call with Acme Corp (09:13 - 10:58) - This is a normal event (weight = 1). It conflicts
with “Meeting with Lisa at café”, which is also a priority event. Since “Meeting with Lisa at café”
has higher priority, we exclude this event. - Meeting with Lisa at café (10:14 - 11:14) - This is a priority event (weight = 2). However,
it conflicts with “Client call with Acme Corp” as discussed. We need to decide whether to exclude
this event or find another slot. - Updating website content (12:21 - 13:36) - This is a normal event (weight = 1).
- Preparing PTO handover (16:07 - 17:37) - This is a normal event (weight = 1).
- Marketing standup on Zoom (17:58 - 19:43) - This is a normal event (weight = 1). It conflicts
with “Preparing PTO handover” as they overlap. We need to decide whether to exclude one of them. - Brainstorming with Luke and Patrick (19:11 - 19:56) - This is a normal event (weight = 1).
It conflicts with “Marketing standup on Zoom” as they overlap. We need to decide whether to exclude
one of them.
To maximize the sum of weighted event durations, we should exclude conflicts with the highest priority
events first.
- Exclude “Client call with Acme Corp” since it conflicts with “Meeting with Lisa at café”
(higher priority). - Exclude “Marketing standup on Zoom” since it conflicts with “Preparing PTO handover” and does not
interfere with any higher priority events.
Thus, the optimized schedule is as follows:
Analyzing product performance
04:33
06:03
One-on-one with manager
08:41
08:56
Meeting with Lisa at café
10:14
11:14
相关文章:
使用GRPO训练调度事件的语言模型!
参考:https://huggingface.co/blog/anakin87/qwen-scheduler-grpo 现在是2025年,在DeepSeek热潮之后,每个人都想使用GRPO训练自己的推理模型。 作为一名实践者,我也想这样做:仅使用提示和奖励来训练语言模型是一件非常…...
关于 js:9. Node.js 后端相关
一、Node 环境搭建与执行流程 Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境,它让 JS 不再局限于浏览器内,而是可以在服务器、终端、本地脚本中运行。 核心定位:让我们可以用 JS 写本地程序、脚本、爬虫、加密逻辑、hook 工具、…...
More Effective C++:改善编程与设计(上)
More Effective C: 目录 More Effective C: 条款1:仔细区别pointers和 references 条款2:最好使用C转型操作符 条款3:绝对不要以多态方式处理数组 条款4:非必要不要提供default constructor 条款5:对定制的“类型转换函数”保持警觉 …...
SCDN如何有效防护网站免受CC攻击?——安全加速网络的实战解析
在互联网安全威胁日益复杂化的今天,CC(Challenge Collapsar)攻击已成为网站运营者面临的主要挑战之一。这种攻击通过模拟大量合法用户请求,消耗服务器资源,导致正常用户无法访问。而**安全内容分发网络(SCD…...
关于并发编程AQS的学习
目录 1. AQS的核心作用 2. AQS的核心结构 3. 关键方法 4. AQS的应用示例 4.1、ReentrantLock的实现 4.2、CountDownLatch的实现 5. AQS的优势 6. 对比其他同步机制 前言 AQS(AbstractQueuedSynchronizer) 是Java并发编程中一个核心的同步器框架…...
16S18S基础知识(1)
相关内容: https://blog.csdn.net/weixin_34315189/article/details/86397125?fromshareblogdetail&sharetypeblogdetail&sharerId86397125&sharereferPC&sharesource2302_80012625&sharefromfrom_link https://metagenome.blog.csdn.net/art…...
Java Spring Boot 控制器中处理用户数据详解
目录 一、获取请求参数1.1 获取查询参数1.2 获取路径参数 二、处理表单提交2.1 处理表单数据 三、处理 JSON 数据3.1 接收 JSON 数据 四、返回 JSON 数据五、处理文件上传5.1 单文件上传5.2 多文件上传 六、总结 在 Spring Boot 应用开发中,控制器(Contr…...
AI产品上市前的“安全通行证“
首席数据官高鹏律师团队 如今AI 产品如雨后春笋般涌现,从智能音箱到自动驾驶汽车,从语音助手到医疗诊断软件,它们正全方位渗透进我们的生活。然而,在 AI 产品迈向市场、走进千家万户之前,有一系列强制性安全认证如同坚…...
sql server 2019 将单用户状态修改为多用户状态
记录两种将单用户状态修改为多用户状态,我曾经成功过的方法,供参考 第一种方法 USE master; GO -- 终止所有活动连接 DECLARE kill_connections NVARCHAR(MAX) ; SELECT kill_connections KILL CAST(session_id AS NVARCHAR(10)) ; FROM sys.dm_ex…...
[滑动窗口]越短越合法(可转化成越长越合法)
题目链接 题意 给你一个整数数组 nums 和一个整数 k ,请你返回子数组内所有元素的乘积严格小于k 的连续子数组的数目。 首先当ans增加时 我们认为r固定 方法一、转化成越长越合法 思路 算出乘积 ≥ k \ge k ≥k的子数组数量 再用所有子数组数量减去上面算出来…...
idea中编写spark程序
### 在 IntelliJ IDEA 中配置和编写 Spark 程序 要在 IntelliJ IDEA 中高效地开发 Spark 程序,需要完成一系列必要的环境配置以及项目搭建工作。以下是详细的说明。 --- #### 1. 安装与配置 IntelliJ IDEA 为了确保 IDE 可以支持 Scala 开发,首先需要…...
机器学习入门(一)
机器学习入门(一) 文章目录 机器学习入门(一)一、机器学习分类1.1 监督学习1.2 半监督学习1.3 无监督学习1.4 强化学习 二、scikit-learn工具介绍scikit-learn安装 三、数据集3.1 sklearn玩具数据集介绍3.2 sklearn现实世界数据集…...
力扣每日一题之移动零
题目说明: 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 请注意 ,必须在不复制数组的情况下原地对数组进行操作。 思路分析:我们可以考虑使用双指针来解答该题。双指针分…...
GaiaEx 盖亚:从合规出发,一家新兴交易平台的全球化路径探索
在加密货币交易平台日益激烈的竞争中,监管趋严、安全要求提升、用户体验优化已成为行业发展的三大核心议题。2025年初正式上线的GaiaEx 盖亚交易所,正是在这一市场背景下,以“合规 产品 生态”的多维路径,逐步建立起自身的发展方…...
车载网关--- 职责边界划分与功能解耦设计
我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 钝感力的“钝”,不是木讷、迟钝,而是直面困境的韧劲和耐力,是面对外界噪音的通透淡然。 生活中有两种人,一种人格外在意别人的眼光;另一种人无论…...
EasyRTC嵌入式音视频通信SDK打造带屏IPC全场景实时通信解决方案
一、方案概述 在智能安防与物联网快速发展的背景下,带屏IPC(网络摄像机)不仅承担着视频采集与监控的基础功能,还逐渐向多样化交互与智能化方向演进。EasyRTC作为一款强大的实时通信框架,具备低延迟、高稳定性、跨平…...
STM32入门笔记(05):内部高速8Mhz时钟最大时钟可以设置 64 Mhz?如何修改system_stm32f10x.c里面的代码?
6.2 Clocks 最大系统时钟频率 当 STM32F103 系列仅使用内部高速振荡器(HSI,8 MHz)作为时钟源,并通过 PLL 放大时,最大可达 64 MHz。([forum.mikroe.com][1], [keil.com][2]) HSI 被内部除以 2(即 4 M…...
iOS 阅后即焚功能的实现
iOS阅后即焚功能实现步骤 一、功能设计要点 消息类型支持:文本、图片、视频、音频等。销毁触发条件: 接收方首次打开消息后启动倒计时。消息存活时间可配置(如5秒、1分钟)。 安全要求: 端到端加密(E2EE&a…...
二叉树前中后序遍历统一迭代法详解:空标记法与栈操作的艺术
二叉树的 前序、中序、后序 遍历是算法中的经典问题。递归实现简单直观,而迭代法则能更好地理解栈的操作逻辑。前文中(中序,前序与后序)所讲过传统的迭代法需要为每种遍历设计不同的入栈顺序,但 统一迭代法 通过引入 空标记节点&a…...
Spark 集群配置、启动与监控指南
Spark 集群的配置和启动需要几个关键步骤。以下是完整的操作流程,包含配置修改、集群启动、任务提交和常见错误排查方法。 1. 修改 Spark 配置文件 首先需要编辑 Spark 配置文件,设置集群参数: bash # 进入 Spark 配置目录 cd $SPARK_HOM…...
综述:拓扑材料的热磁性质
Adv. Funct. Mater. 2025, 2506631 https://doi.org/10.1002/adfm.202506631 近年来,越来越多的拓扑材料表现出优异的热磁(TM)性能,其显著的双极效应和线性能带带来的高载流子迁移率改善了这种性能。 本文综述了TM输运理论、基于…...
lanqiaoOJ 652:一步之遥 ← 扩展欧几里得定理
【题目来源】 https://www.lanqiao.cn/problems/652/learning/ 【题目背景】 本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。 【题目描述】 从昏迷中醒来,小明发现自己被关在X星球的废矿车里。矿车停在平直的废弃…...
双目云台摄像机:双摄安防功能全方位
双目云台摄像机是一种具有革命性设计的云台摄像机设备,其核心在于其独特的双摄像头配置。以下是对这种先进安防设备的详细介绍: 一、核心原理 双目云台摄像机的核心原理在于利用两个摄像头从不同角度捕捉同一场景,通过先进的算法计算两个图…...
Linux - 基础指令
目录 linux下基本指令 ls pwd cd touch mkdir rmdir rm man cp mv cat more less head tail | 匿名管道 find 指令 which alias grep zip/unzi rz/sz tar 重要的⼏个热键 学习linux操作系统,学习指令是必不可少的 尽管有图形化的linux操作系统供学者学习&am…...
深圳无人机展览即将开始,无人机舵机为什么选择伟创动力
深圳无人机展览即将开始,无人机舵机为什么选择伟创动力 2025年5月23日至25日,伟创动力(Kpower)将携旗下多款高性能舵机及微型驱动系统方案亮相2025国际低空经济与无人系统博览会(深圳无人机展),全面展示其在无人机、机…...
ajax提交form表单数据举例
目录 一、HTML 表单准备二、JavaScript 文件(form.js)三、服务器端处理(Spring Boot 示例)四、运行和测试五、总结在现代 Web 开发中,为了提供更流畅、无需页面刷新的用户体验,AJAX(Asynchronous JavaScript and XML)技术被广泛应用于提交表单数据。本文将通过一个具体…...
IDEA 新建 SpringBoot 项目时,没有高版本 SpringBoot 可选
环境描述 IDEA 2025.1.1JDK17Maven 3.9.9 问题描述 IDEA 新建 SpringBoot 项目时,没有高版本 SpringBoot 可选,可以看到此时的最高版本为 3.0.2: 问题分析 返回上一步,可以发现 Spring Initializr 的服务地址为阿里云&#…...
下载的旧版的jenkins,为什么没有旧版的插件
下载的旧版的jenkins,为什么没有旧版的插件,别急 我的jenkins版本: 然后我去找对应的插件 https://updates.jenkins.io/download/plugins/ 1、Maven Integration plugin: Maven 集成管理插件。 然后点击及下载成功 然后 注意&…...
java连数据库
一、准备工作 安装MySQL数据库 确保已安装MySQL服务器并启动服务 下载JDBC驱动 官方驱动:MySQL Connector/JMaven依赖: <dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactI…...
常见排序算法及其java实现
常见排序算法 一、冒泡排序(Bubble Sort)二、选择排序(Selection Sort) 三、插入排序(Insertion Sort)四、快速排序(Quick Sort) 五、归并排序(Me…...
【Python 算法零基础 2.模拟 ④ 基于矩阵】
目录 基于矩阵 Ⅰ、 2120. 执行所有后缀指令 思路与算法 ① 初始化结果列表 ② 方向映射 ③ 遍历每个起始位置 ④ 记录结果 Ⅱ、1252. 奇数值单元格的数目 思路与算法 ① 初始化矩阵 ② 处理每个操作 ③ 统计奇数元素 Ⅲ、 832. 翻转图像 思路与算法 ① 水平翻转图像 ② 像素值…...
2025年PMP 学习十三 第9章 项目资源管理(9.1,9.2)
2025年PMP 学习十三 第9章 项目资源管理(9.1,9.2) 序号过程过程组9.1规划资源管理规划9.2估算活动资源规划9.3获取资源执行9.4建设团队执行9.5管理团队执行9.6控制资源监控 文章目录 2025年PMP 学习十三 第9章 项目资源管理(9.1,9.2…...
IEEE802.16 标准介绍
IEEE802.16 标准又称为IEEE Wireless MAN 空中接口标准,对工作于不同频带的无线接入系统空中接口进行了规范。由于它所规定的无线系统覆盖范围在公里量级,因此802.16 系统主要应用于城域网。 根据使用频带高低的不同,802.16 系统可分为应用于…...
Nginx配置与应用案例详解
Nginx 是一款高性能的 HTTP 服务器和反向代理服务器,广泛用于负载均衡、静态资源托管和动态内容转发。以下是对 Nginx 配置的详细解析及常见应用场景案例。 一、Nginx 配置文件结构 Nginx 的配置文件通常位于 /etc/nginx/nginx.conf,包含以下核心模块: 全局块 (Main Contex…...
Hadoop-HDFS-Packet含义及作用
在 HDFS(Hadoop Distributed File System)中,Packet 是数据读写过程中用于数据传输的基本单位。它是 HDFS 客户端与数据节点(DataNode)之间进行数据交互时的核心概念,尤其在写入和读取文件时,Pa…...
作业帮Android面试题及参考答案
简单描述 Java 类加载机制 Java 类加载机制是将类的字节码载入 JVM 并生成对应的 Class 对象的过程,主要包括以下几个阶段。 加载是类加载的第一个阶段,通过类的全限定名来获取其字节码流,然后将字节码流解析成方法区中的运行时数据结构&…...
分布式1(cap base理论 锁 事务 幂等性 rpc)
目录 分布式系统介绍 一、定义与概念 二、分布式系统的特点 三、分布式系统面临的挑战 四、分布式系统的常见应用场景 CAP 定理 BASE 理论 BASE理论是如何保证最终一致性的 分布式锁的常见使用场景有哪些? 1. 防止多节点重复操作 2. 资源互斥访问 3. 分…...
如何下载 MySQL 驱动 JAR 包
下载 MySQL 驱动 JAR 包的 4 种方式: 官网下载:从 MySQL 官网 下载对应版本的 ZIP 包Maven:在 pom.xml 添加 mysql-connector-java 依赖Gradle:在 build.gradle 使用 implementation mysql:mysql-connector-java:8.0.x直接下载&a…...
unordered_map和unordered的介绍和使用
目录 unordered系列关联式容器 unordered_map unordered_map的接口说明 unordered_map的定义方式 unordered_map接口的使用 unordered_map的容量 unordered_map的迭代器 unordered_map的元素访问 unordered_map的查询 unordered_map的修改操作 unordered_multimap u…...
【原创】使用阿里云存放一个临时共享的文件
在某些场合,需要临时将一个文件存储到一个可被公网访问的地方,某个服务需要访问一下这个文件。这个文件基本上就是一次寿命,也就是你上传一下,然后被访问一下,这个文件的寿命就结束了。 对于这种需求,自建…...
C++学习细节回顾(汇总二)
一.初始化列表相关 1.初始化顺序受申明顺序影响 2.在必要时可以部分不采用初始化列表,避免受特性1影响 二.非类型模板参数 template< class T , size_t N 10 > 三.特化–特殊化处理 template< class T > bool less(T left , T right) { return left&…...
【行为型之访问者模式】游戏开发实战——Unity灵活数据操作与跨系统交互的架构秘诀
文章目录 🧳 访问者模式(Visitor Pattern)深度解析一、模式本质与核心价值二、经典UML结构三、Unity实战代码(游戏物品系统)1. 定义元素与访问者接口2. 实现具体元素类3. 实现具体访问者4. 对象结构管理5. 客户端使用 …...
ubuntu系统安装配置adb工具
获取adb tools 1. 下载最新版(替换链接中的版本号) wget https://dl.google.com/android/repository/platform-tools-latest-linux.zip2. 解压到当前目录 unzip platform-tools-latest-linux.zip3. 移动文件到系统目录 sudo mv platform-tools /usr/…...
基于Python的量化交易实盘部署与风险管理指南
基于Python的量化交易实盘部署与风险管理指南 一、模拟交易与参数优化 1.1 券商API接入与模拟交易 在量化交易落地前,模拟交易是策略验证的“安全沙箱”,其核心价值在于用零成本环境暴露策略缺陷。以股票市场为例,同花顺与通达信模拟盘接口…...
MySQL 入门大全:数据类型
🧑 博主简介:CSDN博客专家,历代文学网(PC端可以访问:https://literature.sinhy.com/#/literature?__c1000,移动端可微信小程序搜索“历代文学”)总架构师,15年工作经验,…...
WPF Datagrid 数据加载和性能
这篇文章并非讨论 WPF Datagrid 的性能数据,而只是简单介绍一下为了使其性能良好,你需要注意哪些方面。我不太想使用性能分析器来展示实际数据,而是尽可能地使用了 Stopwatch 类。这篇文章不会深入探讨处理海量数据的技术,例如分页…...
商城小程序源码介绍
今天要为大家介绍一款基于ThinkPHP、FastAdmin以及UniApp开发的商城小程序源码,这款源码在设计和功能上都有不俗的表现,非常适合想要搭建线上商城的开发者。 该源码采用了ThinkPHP作为后端框架,利用其强大的性能和灵活性,保障了系…...
【大模型】OpenManus 项目深度解析:构建通用 AI Agent的开源框架
OpenManus 项目深度解析:构建通用 AI Agent的开源框架 一、项目概述项目特点 二、项目运行方式与执行步骤(一)环境准备方法 1:使用 conda方法 2:使用 uv(推荐) (二)配置&…...
数据科学和机器学习的“看家兵器”——pandas模块 之一
目录 pandas 模块介绍 4.1 pandas 数据结构 一、课程目标 二、Series 对象介绍 三、DataFrame 对象介绍 四、Series 和 DataFrame 在具体应用中的注意事项 (一)Series 注意事项 (二)DataFrame 注意事项 五、实战案例 案例 1:学生成绩分析 案例 2:销售数据分析 案例 3:股…...
Linux服务之lvs集群与dr模式部署
目录 一.lvs相关概述 1.lvs集群的工作模式 2.lvs调度算法 3.ipvsadm工具 二.DR模式部署 一.lvs相关概述 1.lvs集群的工作模式 lvs-nat:修改请求报文的目标IP,多目标IP的DNAT lvs-dr:操纵封装新的MAC地址(直接路由)lvs-tu…...