第19题:微调数据集如何构造,效果如何评估?

1. 核心回答
微调数据集的构造可以分成四个步骤:
先定义微调目标 → 构造高质量样本 → 严格划分训练集、验证集和测试集 → 用独立测试集比较微调前后的真实任务效果。
如果做的是监督微调(Supervised Fine-Tuning, SFT),一条数据通常可以抽象为:
(xi,yi) (x_i,y_i) (xi,yi)
其中 xix_ixi 是实际任务输入,yiy_iyi 是期望模型生成的高质量答案。
对于聊天模型,可以进一步表示为:
system → user → assistant
数据设计的核心要求是:训练样本应尽可能接近模型最终部署时真正会遇到的输入分布和期望输出形式。
2. 先明确为什么要微调
构造数据之前,我会先定义微调到底要改变模型的什么能力。
常见目标包括:
- 学习特定任务,例如分类、信息抽取、代码生成;
- 学习稳定的输出格式,例如固定 JSON Schema;
- 学习领域任务的处理流程;
- 学习特定回答规范;
- 提高某类输入上的指令遵循能力。
例如,如果目标是“漏洞报告结构化抽取”,训练样本应该直接对应:
漏洞报告 → 结构化字段
而不能主要使用普通安全问答数据。
因此需要先定义:
Task Input→Expected Output \text{Task Input} \rightarrow \text{Expected Output} Task Input→Expected Output
这个映射随后决定数据来源、标签方式和评估指标。
3. 微调数据集怎么构造
我会从真实任务分布开始收集数据。
优先级通常是:
- 真实生产或历史任务数据;
- 经过专家标注的数据;
- 高质量公开数据;
- 人工设计的边界样本和困难样本;
- 合成数据,经过规则或人工复核后加入。
每条数据至少需要记录:
- 输入内容;
- 标准答案;
- 数据来源;
- 任务类别;
- 时间;
- 数据版本;
- 标签来源或标注者;
- 数据许可和隐私状态。
如果涉及用户数据、代码、日志或企业内部数据,还需要先完成脱敏和权限检查。
对于 SFT,我通常会覆盖几类样本:
| 样本类型 | 作用 |
|---|---|
| 正常样本 | 学习主要任务 |
| 边界样本 | 学习决策边界 |
| 困难样本 | 避免只依赖简单表面特征 |
| 拒答样本 | 学习信息不足或越界时的行为 |
| 长输入样本 | 测试长上下文能力 |
| 少数类别样本 | 防止数据分布严重失衡 |
数据量本身不能单独决定微调质量。大量重复、错误或低质量样本可能进一步强化错误模式。
4. 数据清洗和去重怎么做
首先进行基础清洗,例如:
- 删除明显错误标签;
- 清理乱码和无效文本;
- 统一字段格式;
- 删除无法解析的数据;
- 修正异常长度样本;
- 删除敏感信息;
- 检查答案是否真正对应输入。
随后进行 Exact Deduplication 和 Near-Deduplication。
例如下面两条:
如何使用 PyTorch 实现多头注意力?
和:
请问 PyTorch 里面怎么实现 multi-head attention?
语义上可能高度接近。
如果其中一条进入训练集,另一条进入测试集,测试结果可能高估模型的泛化能力。
研究已经发现,语言模型训练语料中的重复数据会增加记忆现象,同时训练集与验证集之间的重复会影响评测可信度。
因此我会先识别:
- 完全重复;
- 模板重复;
- 高度相似文本;
- 同一原始样本的不同改写;
- 同一个问题生成的多个近似版本。
然后让同一组高度相关样本进入同一个数据划分。
5. 训练集、验证集和测试集如何划分
三个集合承担不同功能:
- Training Set:更新模型参数;
- Validation Set:选择超参数、checkpoint 和训练策略;
- Test Set:最终评估模型泛化能力。
测试集不能用于调整模型、选择 Prompt 或选择超参数。
简单情况下可以采用例如:
80% Train / 10% Validation / 10% Test
但实际项目中,怎么切分通常比具体比例更重要。
例如同一个用户产生了 100 条高度相关数据。
如果随机切分:
80条 → Train
10条 → Validation
10条 → Test
模型可能已经在训练阶段学习到这个用户高度固定的输入模式。
因此实际项目中,我会根据数据生成机制选择 Group Split,例如:
- 按用户切分;
- 按项目切分;
- 按代码仓库切分;
- 按漏洞切分;
- 按文档切分;
- 按攻击活动切分。
如果系统面向未来数据,还应该进行 Time Split:
过去数据→Train \text{过去数据} \rightarrow \text{Train} 过去数据→Train
较新的数据→Validation \text{较新的数据} \rightarrow \text{Validation} 较新的数据→Validation
未来时间段→Test \text{未来时间段} \rightarrow \text{Test} 未来时间段→Test
这样更接近真实部署场景。
此外,所有需要从数据中“学习”的预处理操作都只能在训练集上拟合,再应用到验证集和测试集,避免 Data Leakage。
6. 怎么判断微调有没有效果
训练 Loss 只能用于观察优化过程。
例如:
Ltrain↓ L_{\text{train}}\downarrow Ltrain↓
说明模型越来越能够拟合训练样本。
这个现象不能单独证明真实任务能力提高。
我会首先建立 Base Model Baseline。
也就是在微调之前,用完全相同的测试集测一次原始模型:
Mbase M_{\text{base}} Mbase
微调完成后,再测试:
Mft M_{\text{ft}} Mft
然后比较:
$$
\Delta
Metric(M_{\text{ft}})
Metric(M_{\text{base}})
$$
这样才能直接回答:
微调究竟带来了多少增量。
比较时需要尽量固定:
- 测试数据;
- Prompt;
- 解码参数;
- 最大输出长度;
- 工具权限;
- 评测程序。
7. 不同任务应该使用什么指标
评估指标必须与任务目标一致。
7.1 分类任务
可以使用:
Precision=TPTP+FP Precision=\frac{TP}{TP+FP} Precision=TP+FPTP
Recall=TPTP+FN Recall=\frac{TP}{TP+FN} Recall=TP+FNTP
F1=2Precision⋅RecallPrecision+Recall F1= 2\frac{Precision\cdot Recall} {Precision+Recall} F1=2Precision+RecallPrecision⋅Recall
类别不平衡时还应考虑 PR-AUC、Macro-F1 等指标。
7.2 信息抽取任务
可以使用:
- Exact Match;
- Precision;
- Recall;
- F1;
- 字段级准确率。
7.3 代码生成任务
优先使用可以执行的验证方式,例如:
- Unit Test Pass Rate;
- Compilation Rate;
- Pass@k;
- 功能正确率。
7.4 开放式生成任务
ROUGE、BLEU 等字符串相似度通常只能覆盖部分质量。
可以进一步设计明确的评分 Rubric,例如:
- 正确性;
- 完整性;
- 指令遵循;
- 格式正确性;
- 事实一致性;
- 是否出现幻觉。
然后使用:
- 人工专家评分;
- 规则评分器;
- 模型评分器;
进行评估。
如果使用 LLM-as-a-Judge,也需要先用人工标注样本检查评分器与人工判断的一致性,避免直接把 Judge 的输出当成真值。
8. 还需要评估哪些泛化能力
平均分提高仍然可能掩盖局部退化。
因此我会进一步做 Slice Evaluation。
例如分别统计:
- 简单样本;
- 困难样本;
- 长输入;
- 短输入;
- 常见类别;
- 少数类别;
- 不同领域;
- 不同用户;
- 不同时间段。
假设整体 F1 从:
0.82→0.87 0.82\rightarrow0.87 0.82→0.87
但少数类别从:
0.71→0.55 0.71\rightarrow0.55 0.71→0.55
那么这个微调结果仍然存在明显问题。
同时还需要检查:
- 原模型已有能力是否下降;
- 幻觉率是否增加;
- 拒答能力是否变化;
- 安全能力是否退化;
- 推理延迟是否变化;
- 输出 Token 数是否显著增长。
这相当于检查微调产生的收益和副作用。
9. 一个完整的实验流程
如果让我实际做一次微调,我会按照下面的顺序:
定义任务和成功指标
↓
收集真实任务数据
↓
清洗、脱敏、去重和质量审核
↓
根据用户/项目/时间等自然边界划分 Train / Validation / Test
↓
在 Test Set 上记录 Base Model 基线
↓
只使用 Train Set 训练
↓
使用 Validation Set 选择超参数和 Checkpoint
↓
冻结模型设计
↓
在独立 Test Set 上比较 Base Model 和 Fine-tuned Model
↓
进行困难样本、长尾类别和域外数据切片分析
↓
分析失败案例
最终需要证明三件事:
- 主任务指标确实提高;
- 提高能够泛化到未见数据;
- 没有产生不可接受的能力退化、安全风险或成本增加。
只有这三点同时成立,我才会认为这次微调真正有效。
10. 面试时可以压缩成下面这段
微调数据首先要从任务目标出发。如果做 SFT,我会把真实任务整理成 input → expected output 的高质量样本,同时保留数据来源、任务类别和时间等元信息。
数据处理阶段重点做清洗、去重、脱敏和标签审核。切分时我会特别防止数据泄漏。对于同一用户、项目、代码仓库或高度相似样本,我会按 group 隔离;如果模型最终处理未来数据,还会做时间切分。训练集用于更新参数,验证集用于调参,测试集只用于最终评估。
效果评估时,我会先记录原始模型 baseline,再在完全相同的测试集和推理条件下比较微调后的模型。具体指标根据任务选择,例如分类看 Precision、Recall、F1,代码生成看 Unit Test Pass Rate,开放式生成使用明确 rubric 的人工或模型评分。
最后还会做长输入、困难样本、少数类别和域外数据的切片评测,并检查幻觉、安全、延迟和原有能力退化。这样才能确认微调提升来自真正的任务泛化能力。
11. 来源
- Hugging Face Documentation, Splits and subsets:说明 Train、Validation 和 Test 的不同职责。
- Hugging Face Evaluate, Considerations for model evaluation:说明独立数据划分和任务评估的基本原则。
- scikit-learn Documentation, Common pitfalls and recommended practices — Data leakage:说明测试数据进入模型训练或预处理会造成过度乐观的评估。
- scikit-learn Documentation, GroupShuffleSplit:说明可以按照用户、年份或其他领域实体进行分组隔离。
- Lee et al., Deduplicating Training Data Makes Language Models Better, ACL 2022:研究训练数据去重、模型记忆以及训练—验证数据重叠问题。
- OpenAI API Documentation, Fine-tuning:说明微调数据需要按照具体训练方式组织,并支持独立 Validation Data。
- OpenAI API Documentation, Evals / Graders:说明可以使用字符串、文本相似度、程序和模型评分器等不同方式构造任务评测。

4105

被折叠的 条评论
为什么被折叠?



