用标注数据微调 LLM
用研究自己的标签,通过 SFT、DPO、奖励模型或过程奖励模型训练 LLM,在留出条目上给每个模型打分,并发布到 Hub。
v2.14.0 新增
本教程在 Potato 研究收集到的答案上训练四种语言模型。llm-sft 训练器在书面答案或修正后的智能体轨迹上微调 LLM,llm-dpo 在成对选择上调优 LLM,reward-model 在比较结果上拟合标量奖励模型,prm-reward 在步骤评分上拟合过程奖励模型。本页面向已经在 Potato 中收集偏好或轨迹数据的团队,他们想用这些标签得到第一个模型,而不必把数据导出到单独的训练脚本。每一节都会指出产生数据的方案,给出能通过 Potato 验证器的配置,列出值得调整的参数,并说明留出得分衡量什么,以及预测是否会作为预标签送回给标注者。模型训练概览介绍训练页面,训练你的第一个模型则用一个不需要 GPU 的分类器走完整个循环。
按标注方案划分的训练器
本页的每个训练器每次运行只从一个标注方案学习,训练页面只为训练器能够学习的方案提供该训练器。下表列出每个训练器所学习的方案:
| 训练器 | 方案 | 模型学到什么 | 留出主指标 | 是否展示给标注者 |
|---|---|---|---|---|
llm-sft | text | 写出标注者所写的答案 | token F1 | 是,生成的答案会填入文本框 |
llm-sft | trajectory_edit | 把智能体的步骤改写成修正后的步骤 | closer_to_correction | 否,只存储和打分 |
llm-dpo | binary 模式的 pairwise | 偏好标注者选择的回复 | 准确率,不计平局 | 是,被偏好回复的卡片处于选中状态 |
llm-dpo | trajectory_edit | 偏好修正后的步骤而非原始步骤 | closer_to_correction | 否,只存储和打分 |
reward-model | pairwise(binary 和 scale)、ranking、bws | 每条回复的得分 | 准确率、方向准确率、Kendall's tau 或最佳-最差准确率 | 是,作为方案自己的答案 |
prm-reward | process_reward | 对每个步骤给出正确、中性或错误的评分 | step_macro_f1 | 通过“AI pre-label steps”按钮提供 |
开始之前
Potato 的训练 extra 会为这四个训练器安装 PyTorch、Transformers 和 PEFT:
pip install "potato-annotation[train-llm]"
pip install "potato-annotation[train-text]"第一个 extra 覆盖 llm-sft 和 llm-dpo,第二个覆盖 reward-model 和 prm-reward。pip install "potato-annotation[train]" 一次安装全部训练 extra。缺少所需包的训练器会在训练页面上列为“not installed”,并附上安装这些包的命令。
每个训练器在 train 划分少于 20 个条目时都拒绝拟合(即 min_instances 参数)。默认划分把 70% 的已标注条目放进 train,15% 放进 val,15% 放进 test,因此第一次运行之前要准备约 30 个已标注条目。val 和 test 条目留在训练之外,用来给模型打分。
llm-sft 和 llm-dpo 从 Qwen/Qwen2.5-0.5B-Instruct 起步,reward-model 从 distilbert/distilroberta-base 起步,prm-reward 从 answerdotai/ModernBERT-base 起步。LLM 训练器设计为在 GPU 上运行。运行 Potato 的机器没有 GPU 时,远程训练会通过 ssh 把运行发送到 GPU 服务器,或发送到 SLURM 集群。
收集偏好和改写的研究
第一个配置针对每条客服提示提出两个问题。标注者从两条回复中选出更好的一条,并写出标注者希望助手给出的答案。选择用于训练 llm-dpo 和 reward-model,书面答案用于训练 llm-sft。data/answers.jsonl 的每一行包含一条提示和两条回复:
{"id": "q001", "prompt": "How do I reset my router to factory settings?", "responses": ["Hold the reset button on the back for 10 seconds until the lights blink, then wait two minutes for the router to restart.", "Routers can be reset. Check the manual."]}该配置把提示显示为条目的文本,把两条回复显示为卡片 A 和 B:
annotation_task_name: "Support answers: preferences and rewrites"
task_dir: .
data_files:
- data/answers.jsonl
item_properties:
id_key: id
text_key: prompt
output_annotation_dir: annotation_output
user_config:
allow_all_users: true
annotation_schemes:
- annotation_type: pairwise
name: preferred
description: "Which response answers the question better?"
mode: binary
items_key: responses
allow_tie: true
tie_label: "No preference"
- annotation_type: text
name: rewrite
description: "Write the answer you would want the assistant to give."
multiline: true
rows: 4
model_training:
enabled: true
writeback:
schemas: [preferred]
min_confidence: 0.7text_key: prompt 有两重作用,因为提示既是标注者阅读的内容,也是 llm-sft 放在问题之后的内容。items_key: responses 指明成对卡片所来自的列表,顺序与数据中一致,因此 A 是第一条回复。writeback.schemas 只列出 preferred,所以标注者看到的是模型的选择,而不是生成的改写。预标签会锚定标注者,因此要等 llm-sft 运行的留出得分足以支持展示模型的文本之后,再把 rewrite 加进列表。min_confidence: 0.7 让模型把握较小的预测不出现在页面上,同时仍然存储这些预测。启动服务器之前,先用 Potato 的验证器检查配置:
python -m potato.validate_cli config.yaml --strict启动 Potato,至少标注 30 条提示,然后以管理员身份打开 /admin/training。下面的运行也可以通过 API 启动,把配置中的 admin_api_key 放在 $KEY 里。
用 llm-sft 做监督微调
llm-sft 把每个已标注条目变成一个训练样本。提示是方案的 description(标注者看到的问题)加上条目的文本,目标是标注者写下的答案。损失只覆盖答案的 token,因此模型学的是作答,而不是复述提示。默认训练 LoRA 适配器,而不是训练全部权重。
在训练页面上选择 llm-sft 和 rewrite 方案,然后点击 Train now,或者通过 API 启动同样的运行:
curl -X POST -H "X-API-Key: $KEY" -H "Content-Type: application/json" \
http://localhost:8000/admin/training/api/runs \
-d '{"trainer": "llm-sft", "schemas": ["rewrite"], "params": {"max_new_tokens": 256}}'大多数运行只改动下表中的参数:
| 参数 | 默认值 | 含义 |
|---|---|---|
model_name | Qwen/Qwen2.5-0.5B-Instruct | Hugging Face Hub 上的因果语言模型,或本地目录。 |
lora | true | false 训练全部权重,需要数倍的内存。{quantize: 4bit} 以 4 位加载基础模型(见 QLoRA)。 |
max_length | 1024 | 每个样本的 token 数。过长的提示会丢失开头的 token,答案则保留。 |
max_new_tokens | 256 | 模型生成的最长答案。 |
instruction | 方案的 description | 放在每个条目文本之前的文字。 |
system_prompt | 无 | 为带聊天模板的模型提供的系统消息。 |
gradient_checkpointing | false | 节省激活内存,代价是多用约三分之一的时间。 |
learning_rate | 使用 LoRA 时 2e-4,不使用时 1e-5 |
运行会保留 val 损失最低的检查点。由于运行是在 val 上选定检查点的,留出得分取自 test。得分是 token F1,即生成答案与书面答案之间不计顺序的词重叠,精确匹配则与该得分一并报告。Token F1 会给词对但位置错的答案记分,因此要把两个指标放在一起看。
模型会为每个 val 和 test 条目贪心地生成一个答案。设置 writeback.include_unlabeled: true 后,模型还会回答没有人标注过的条目。预测的置信度是模型对其所生成 token 的平均概率,模型审核队列按这个置信度排序。把 rewrite 放进 writeback.schemas 后,标注者打开条目时,生成的答案会填入文本框。
自由文本不太适合每个条目由多位标注者回答。aggregation 设置通过逐词比较答案,把多个答案合并成一个,而两个书面答案很少逐词相同。对于 text 方案上的 llm-sft,每个条目只安排一位撰写者,可以避免逐词比较。
用 llm-dpo 做偏好调优
直接偏好优化(DPO)训练 LLM 提高被偏好回复相对于另一条回复的似然,并以起始模型的冻结参考副本为基准。llm-dpo 从每个回答为 A 或 B 的条目构建一个样本。提示是条目的 prompt 字段,或条目所具有的 question、instruction、query、input 和 context 中的第一个。回答为平局选项的条目会被排除,因为平局并不表明哪条回复更好。
选择 llm-dpo 和 preferred 方案,或者发送与上面相同的请求,只是改为 "trainer": "llm-dpo" 和 "schemas": ["preferred"]。使用默认的 LoRA 适配器时,参考模型就是关闭适配器的同一个模型,因此内存里不需要第二份副本。lora: false 训练全部权重,并保留一份冻结副本作为参考,冻结副本会使内存翻倍。
| 参数 | 默认值 | 含义 |
|---|---|---|
model_name | Qwen/Qwen2.5-0.5B-Instruct | 因果语言模型。 |
beta | 0.1 | 模型可以偏离参考多远。取值越低,模型可以偏离得越远。 |
epochs | 2 | |
learning_rate | 使用 LoRA 时 5e-5,不使用时 5e-7 | |
max_length | 1024 | 每条提示和回复的 token 数。 |
instruction | 无 | 放在每个条目提示之前的文字。 |
运行会保留 val 上 DPO 损失最低的检查点,运行日志会报告模型在 val 上有多大比例偏好标注者的选择。留出得分是 test 上的准确率,针对未回答为平局的条目,宏 F1 与准确率并列报告。预测是训练后的模型所偏好的回复,该偏好的概率作为置信度。作为预标签,标注者打开条目时,被偏好回复的卡片处于选中状态。方案设置了 randomize_order 时,选中状态会跟随该回复,出现在标注者看到该回复的位置。保存下来的适配器同样是一个策略,用 PEFT 加载后可以生成文本。关于如何收集偏好数据本身的背景,见收集 RLHF 与偏好数据和成对比较。
用 reward-model 训练奖励模型
奖励模型把一条回复映射为一个数,可用于 RLHF、best-of-n 采样,或为新输出排序。reward-model 训练一个只有一个输出的 transformer,使标注者偏好的回复得分更高。损失是 Bradley–Terry 损失,即 -log sigmoid(r_winner - r_loser),也就是 InstructGPT 的奖励建模损失。上面的 preferred 方案不改动配置就能训练 reward-model。每种比较型方案提供不同的训练信号:
| 方案 | 训练信号 | 留出主指标 |
|---|---|---|
pairwise,binary | 被选中的回复胜过另一条。平局被跳过。 | 准确率 |
pairwise,scale | 滑块偏向的一侧获胜,权重取决于滑块偏离的程度。中点被跳过。 | 方向准确率 |
ranking | 整个顺序,使用 Plackett-Luce 损失,或设置 ranking_loss: pairs 时使用顺序中的每一对。 | Kendall's tau |
bws | 最佳条目胜过元组中的每个其他条目,其他每个条目都胜过最差条目。 | 最佳-最差准确率 |
条目有提示字段时,每个奖励都是针对给定提示的回复。排序的选项是方案的标签,每个选项都在给定条目文本的条件下打分。服务器根据 bws_config 构建 BWS 元组,因此用服务器自己的数据启动的运行自带元组,数据文件不需要再提供元组。
| 参数 | 默认值 | 含义 |
|---|---|---|
model_name | distilbert/distilroberta-base | 编码器,或带 lora 的 LLM。 |
ranking_loss | plackett_luce | 只用于 ranking 方案:plackett_luce 或 pairs。 |
max_length | 512 | 每个被打分文本的 token 数,提示和回复合计。 |
learning_rate | 2e-5,使用 LoRA 时 2e-4 |
预测回答的是方案自己的问题,因此这些预测像其他任何方案的预测一样被打分和回写。二选一的预标签是被选中的卡片,量表的预标签是滑块位置,排序的预标签是列表顺序,BWS 的预标签是被选中的最佳和最差项。每个预测还会存储该预测所依据的 rewards。只有奖励之间的差值才有意义。成对比较与最佳-最差标度比较了收集数据时各种比较型格式。
收集步骤评分和修正的研究
第二个配置处理智能体轨迹。标注者给轨迹的每一步评分,然后修正错误的步骤。步骤评分用于训练 prm-reward,修正用于训练 llm-sft 或 llm-dpo。data/traces.jsonl 的每一行包含任务、智能体的步骤和最终答案:
{"id": "traj_001", "task_description": "Find the current weather in San Francisco and report the temperature.", "steps": [{"thought": "I should look up the current weather.", "action": "web_search(queyr='San Francisco weather')"}, {"thought": "Open the first result.", "action": "open_url(results[0])"}, {"thought": "Read the temperature from the page.", "action": "extract_text('.temp')"}], "final_answer": "It is sunny."}训练器按顺序从条目的 task_description、task 或 text 字段读取任务:
annotation_task_name: "Agent traces: step ratings and corrections"
task_dir: .
data_files:
- data/traces.jsonl
item_properties:
id_key: id
text_key: task_description
output_annotation_dir: annotation_output
user_config:
allow_all_users: true
annotation_schemes:
- annotation_type: process_reward
name: step_quality
description: "Rate each step of the agent's trace"
steps_key: steps
step_text_key: action
mode: per_step
allow_neutral: true
ai_prelabel: true
- annotation_type: trajectory_edit
name: corrected_trace
description: "Fix the wrong steps, then correct the final answer"
steps_key: steps
step_text_key: action
editable_fields: [action]
show_diff: true
edit_final_answer: true
final_answer_key: final_answer
model_training:
enabled: true
writeback:
schemas: [step_quality]
include_unlabeled: truemode: per_step 加 allow_neutral: true 给出 prm-reward 所学习的三种评分。ai_prelabel: true 在方案上放一个“AI pre-label steps”按钮,训练得到的评分通过该按钮出现。writeback.schemas 只指明 step_quality。把 corrected_trace 列在那里会使服务器无法启动,验证器会给出原因:
model_training.writeback.schemas names 'corrected_trace', a trajectory_edit scheme, which has no prelabel display: its predictions are stored and scored but annotators would never see them. Leave it out of writeback.schemas.用 llm-sft 和 llm-dpo 修复轨迹
trajectory_edit 的答案是一对轨迹,即智能体的原始步骤和标注者修正之后的步骤。SFT/DPO 的轨迹编辑介绍编辑器,轨迹编辑博文介绍这些轨迹对如何变成训练数据。两个训练器都会排除没有人编辑过的轨迹。
llm-sft以任务和原始步骤作为提示,以修正后的步骤作为目标,因此模型学会修复轨迹。每一步写成Step N加上该步骤的各字段(action: ...、thought: ...),方案设置了final_answer_key时,最终答案跟在最后一步之后。llm-dpo以任务作为提示,以修正后的步骤作为被偏好的回复,以原始步骤作为另一条回复。预测说明模型偏好修正(A)还是原始版本(B),并且只针对有修正的留出轨迹作出。
两种运行都把 closer_to_correction 作为留出得分报告。对 llm-dpo,该得分是模型偏好修正的留出轨迹所占的比例。对 llm-sft,该得分是按 token F1 衡量,所写步骤比起原始版本更接近修正版本的轨迹所占的比例,针对修正版本的 token_f1 与该得分并列报告。
trajectory_edit 运行的预测会被存储和打分,标注者看不到这些预测。编辑器总是从智能体的原始轨迹开始,所以页面没有地方展示预测的改写。请从运行页面,或从运行目录中的 artifacts/predictions.jsonl 读取这些预测。
用 prm-reward 给步骤评分
过程奖励模型对轨迹的各个步骤打分,而不只是对最终答案打分,做法见 PRM800K。prm-reward 把整条轨迹作为一个输入送入 transformer 编码器,即任务后接 Step 1、Step 2 等。编码器在每个步骤的最后一个 token 处学习三类评分,因此每个评分都是在能看到该步骤之前各步骤的情况下作出的。没有人评分的步骤不计入损失。默认模型 answerdotai/ModernBERT-base 是因其 8,192 个 token 的上下文而选定的。
| 参数 | 默认值 | 含义 |
|---|---|---|
model_name | answerdotai/ModernBERT-base | 带快速分词器的编码器。 |
max_length | 1024 | 每条轨迹的 token 数。 |
epochs | 6 | |
batch_size | 8 | 每步的轨迹数。 |
learning_rate | 5e-5,使用 LoRA 时 3e-4 |
长轨迹会丢失最后的步骤。超过 max_length 个 token 的轨迹从末尾截断,截断点之后的步骤既不参与训练,也不被评分。运行日志会统计丢失的步骤数。当 max_length 超过模型所能容纳的长度时,运行会把 max_length 降到模型的上限并给出警告,大多数 BERT 类编码器的上限是 512 个 token。运行日志报告有步骤丢失时,请调高 max_length,并选择上下文能容纳更长轨迹的模型。
留出得分是 step_macro_f1,即所有已评分步骤上三类评分的宏 F1。大多数轨迹中的大多数步骤是正确的,所以准确率会美化一个从不说“错误”的模型。运行还会报告 step_accuracy 和 first_error_accuracy,后者是模型的第一个错误步骤恰好是标注者的第一个错误步骤的轨迹所占的比例。
预测会为每个能放进 max_length 的步骤评分,每个评分的概率作为该评分的置信度,最不确定的步骤的置信度作为该轨迹的置信度。方案列在 writeback.schemas 中并且设置了 ai_prelabel: true 时,“AI pre-label steps”按钮会提供训练得到的评分供标注者核对。对于已有训练评分的条目,不会调用 ai_support 下配置的 LLM 评判器。过程奖励标注介绍该方案,过程奖励模型指南介绍数据。
用 QLoRA 装下更大的模型
QLoRA 以 4 位加载基础模型的权重,并在其上训练 LoRA 适配器。llm-sft、llm-dpo、hf-text-classification、vlm-sft 和 reward-model 接受 lora: {quantize: 4bit},prm-reward 会在加载模型之前拒绝该设置。请根据每次 transformer 运行在结束时记录的“Peak GPU memory”一行来规划内存。配置参考的 QLoRA 一节说明基础权重如何加载以及 8 位选项。
把下面这个块加进上面的配置,即可把 QLoRA 设为 llm-sft 的默认设置:
model_training:
enabled: true
trainer_params:
llm-sft:
model_name: Qwen/Qwen2.5-7B-Instruct
lora: {quantize: 4bit}
gradient_checkpointing: trueQLoRA 需要 CUDA GPU,以及与该机器的 CUDA 匹配的 bitsandbytes 构建,用 pip install bitsandbytes 安装。没有可用的 GPU 或构建时,运行会在加载模型之前于验证阶段停下。
把运行发布到 Hugging Face Hub
模型位于 Potato 服务器上的成功运行,在运行页面上有 Publish to the Hugging Face Hub。推送会上传模型,以及根据该运行写成的 README.md 模型卡,其中包含训练器、基础模型和适配器、方案和标签、划分大小、留出得分及其衡量对象,以及运行和 bundle 的 id。LoRA 运行只保存了适配器,因此 Hub 仓库里放的是适配器,模型卡会指明要把适配器加载到哪个基础模型上。
令牌不会出现在浏览器中。在 Hugging Face 设置中创建写入令牌,并在启动 Potato 之前把令牌放进服务器的环境:
export HF_TOKEN=hf_your_write_token
potato start config.yaml表单会指明环境变量(默认为 HF_TOKEN),要求输入两次仓库名,并默认勾选 Private。发布到 Hugging Face Hub列出会上传的文件、推送前的检查,以及模型卡上的许可证。通过 API 进行同样的推送:
curl -X POST -H "X-API-Key: $KEY" -H "Content-Type: application/json" \
http://localhost:8000/admin/training/api/runs/RUN_ID/push-to-hub \
-d '{"repo_id": "your-org/support-dpo", "confirm_repo_id": "your-org/support-dpo", "private": true, "licence": "apache-2.0"}'该路由返回 201 和提交信息。留在远程主机上且设置了 fetch_artifacts: false 的模型无法从 Potato 服务器推送,运行页面会说明模型在哪里。要从已发布的模型继续进入主动学习循环,请接着看循环中的模型。
延伸阅读
- 模型训练配置:每个
model_training键、留出得分、回写和路由。 - 训练器:全部 38 个训练器,按任务分组。
- 远程训练:通过 ssh 连接的 GPU 服务器、SLURM 集群和轮询智能体。
- 智能体轨迹标注:在 Potato 中收集轨迹数据。
- 上游参考小节:
llm-sft、llm-dpo、智能体轨迹、prm-reward、reward-model、QLoRA和 Hub 发布。
参考文献
- Dettmers, T., Pagnoni, A., Holtzman, A., and Zettlemoyer, L. (2023). QLoRA: Efficient Finetuning of Quantized LLMs. arXiv:2305.14314. arxiv.org/abs/2305.14314
- Hu, E. J., Shen, Y., Wallis, P., Allen-Zhu, Z., Li, Y., Wang, S., Wang, L., and Chen, W. (2021). LoRA: Low-Rank Adaptation of Large Language Models. arXiv:2106.09685. arxiv.org/abs/2106.09685
- Lightman, H., Kosaraju, V., Burda, Y., Edwards, H., Baker, B., Lee, T., Leike, J., Schulman, J., Sutskever, I., and Cobbe, K. (2023). Let's Verify Step by Step. arXiv:2305.20050. arxiv.org/abs/2305.20050
- Ouyang, L., Wu, J., Jiang, X., Almeida, D., Wainwright, C. L., Mishkin, P., Zhang, C., Agarwal, S., Slama, K., Ray, A., Schulman, J., Hilton, J., Kelton, F., Miller, L., Simens, M., Askell, A., Welinder, P., Christiano, P., Leike, J., and Lowe, R. (2022). Training Language Models to Follow Instructions with Human Feedback. arXiv:2203.02155. arxiv.org/abs/2203.02155
- Rafailov, R., Sharma, A., Mitchell, E., Ermon, S., Manning, C. D., and Finn, C. (2023). Direct Preference Optimization: Your Language Model is Secretly a Reward Model. arXiv:2305.18290. arxiv.org/abs/2305.18290