三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

1k+ 小数据集 SFT + KTO 微调与评测完整攻略

1k+ 小数据集 SFT + KTO 微调与评测完整攻略

1k+ 小数据集 SFT + KTO 微调与评测完整攻略

基于 Qwen3.5-9B + RTX 4090D (24GB) 实战经验总结

一、项目概述

1.1 目标

使用 1,000+ 条 高质量训练数据,通过 SFT + KTO 两阶段微调,让模型学会从需求描述中生成结构化测试用例(JSON 格式)

1.2 最终成果(测试集评测)

 
指标结果
格式正确率 100%
语义相似度(DeepSeek) 91.1/100
采纳率(≥80分) 86.0%
召回率 86.14%
准确率 85.68%
F1 0.859
隐藏需求覆盖 73.7%

✅ 结论:模型在未训练需求上表现出色,具备直接部署价值。

二、环境准备

2.1 硬件配置

 
组件规格
GPU NVIDIA RTX 4090D (24GB) × 1
CPU 16 vCPU Intel Xeon Platinum 8352S
内存 62GB
系统盘 30GB(⚠️ 仅放系统,模型和数据放数据盘)
数据盘 50GB SSD

2.2 软件版本

 
组件版本
CUDA 12.8
PyTorch 2.10.0
Transformers 5.3.0
ms-swift 4.4.2
vLLM 0.17.1(如兼容性问题可改用 Transformers 直接推理)

2.3 环境安装

# 安装 ms-swift
pip install ms-swift# 评测依赖(本地/云实例)
pip install openai sentence-transformers scikit-learn tqdm

2.4 ⚠️ 磁盘空间管理(关键)

# 模型文件约 18-20GB,务必设置缓存到数据盘
export MODELSCOPE_CACHE=/your_data_disk/.cache/modelscope
export HF_HOME=/your_data_disk/.cache/huggingface
mkdir -p $MODELSCOPE_CACHE $HF_HOME

否则 30GB 系统盘会被模型下载撑爆,导致容器崩溃。

三、数据准备(阶段0)

3.1 数据格式

{"messages": [{"role": "system", "content": "你的任务是帮我生成功能测试用例"},{"role": "user", "content": "模块:XXX,功能点:XXX..."},{"role": "assistant", "content": "[{\"testpoint\": \"...\", \"priority\": \"..\", \"steps\": \"...\", \"expectation\": \"...\"}]"}]
}

3.2 数据拆分(⚠️ 关键)

# 9:1 拆分
训练集: ~900 条 → 用于 SFT + KTO 训练
测试集: ~100 条 → 永久封印,仅用于最终评估

测试集绝不参与任何训练或生成过程,否则泛化评估失效。

四、阶段一:SFT(监督微调)

4.1 核心理念

让模型学会遵循指令、输出 JSON 格式。此阶段模型可能生成质量一般的测试用例,没关系——这正是阶段二(KTO)要解决的。

4.2 参数配置(1k 小数据集专属)

 
参数说明
num_train_epochs 1 ~ 1.5 小数据集跑多轮必过拟合
learning_rate 1e-5 比常规略低
weight_decay 0.1 强正则化防过拟合
per_device_train_batch_size 1 9B模型+24GB显存,显存紧张
gradient_accumulation_steps 8 等效 batch_size = 8
max_length 2048 足够覆盖测试用例长度
max_new_tokens 1536 避免截断
bf16 true 节省显存

4.3 训练命令(ms-swift)

CUDA_VISIBLE_DEVICES=0 \
swift sft \--model /path/to/Qwen3.5-9B \--tuner_type lora \--dataset /path/to/sft_train.json \--torch_dtype bfloat16 \--num_train_epochs 1 \--per_device_train_batch_size 1 \--learning_rate 1e-5 \--weight_decay 0.1 \--warmup_ratio 0.1 \--lora_rank 8 \--lora_alpha 32 \--target_modules all-linear \--gradient_accumulation_steps 8 \--save_steps 100 \--save_total_limit 2 \--logging_steps 10 \--max_length 2048 \--output_dir ./output_sft_v1 \--dataloader_num_workers 4

4.4 检查点选择

  • 训练完成后取 最后一个 checkpoint(如 checkpoint-134)。

  • 使用 swift export 合并 LoRA 权重为完整模型:

swift export \--model /path/to/Qwen3.5-9B \--adapters ./output_sft_v1/checkpoint-134 \--output_dir ./model_merged \--merge_lora true

 

 

指标

开始

结束

结论

Loss

1.297

0.946

稳步下降,没有过拟合

Token Acc

71.0%

77.3%

持续提升

显存占用

22.58 GB

23.07 GB

稳定,未超24GB上限

训练步数

134步

134步

跑满1个Epoch

 

五、阶段二:KTO 数据准备(动态打标)

5.1 核心理念

用 SFT 模型对训练集重新生成回答,对比生成结果与标准答案的相似度,自动打上 label: true/false 标签——这就是 KTO 所需的“好/坏”样本。

5.2 ⚠️ 关键原则

必须用 SFT 模型自己生成,不能用更强的 API 模型替换!

5.3 生成参数(高温制造差异)

 
参数说明
temperature 0.9 强制模型产生变异,暴露弱点
max_new_tokens 1536 完整生成
top_p 0.9 适度多样化

5.4 评分与打标

  • 使用deepseek推理模型对原回答和SFT模型回答进行打分设置分数阈值,打标签false

    首先筛选json格式,若非json格式,打标签flase
    若为json格式,进行语义相似度打分,设置阈值筛选flase评分标准:
    - 90-100 分:测试用例覆盖的核心功能点几乎完全一致,测试场景设计合理且相似
    - 80-89 分:核心功能点覆盖完整,测试场景设计基本一致
    - 70-79 分:主要功能点有覆盖,但测试场景设计有差异
    - 60-69 分:部分功能点有覆盖,测试场景设计差异较大
    - 50-59 分:仅有少量功能点重叠
    - 0-49 分:测试用例差异很大,几乎没有重叠

5.5 数据输出格式

{"messages": [...],"label": true   // 或 false
}

六、阶段三:KTO

6.1 核心理念

用二元标签(好/坏)让模型更倾向于生成 true 样本的风格,同时厌恶 false 样本中的错误模式

6.2 参数配置(1k 小数据集专属)

 
参数说明
num_train_epochs 2 KTO 收敛快
learning_rate 5e-5 比 SFT 低一个数量级
undesirable_weight
1.2 ⚠️ 小数据集需加大奖惩力度!
per_device_train_batch_size 2 根据显存调整

6.3 训练命令(ms-swift)

CUDA_VISIBLE_DEVICES=0 \
swift rlhf \--rlhf_type kto \--model /root/autodl-tmp/model_merged \--template qwen \--tuner_type lora \--dataset '/root/autodl-tmp/data/kto-train.json' \--load_from_cache_file true \--split_dataset_ratio 0.07 \--num_train_epochs 2 \--per_device_train_batch_size 1 \--per_device_eval_batch_size 1 \--learning_rate 5e-5 \--lora_rank 8 \--lora_alpha 32 \--target_modules all-linear \--gradient_accumulation_steps 16 \--eval_steps 100 \--save_steps 100 \--save_total_limit 2 \--logging_steps 5 \--output_dir output \--warmup_ratio 0.05 \--dataloader_num_workers 4 \--dataset_num_proc 4 \--beta 0.1 \--undesirable_weight 1.2 

6.4 合并最终模型

指标

数值

总步数

184 steps(2 epochs)

训练时长

1小时37分45秒

训练集大小

1469 条

验证集大小

110 条

平均训练 Loss

0.242(良好)

最佳验证 Loss

0.291(在 step 100)

可训练参数量

21.64M(占全量 0.39%)

使用 checkpoint-100 进行模型导出和推理

swift export \--model /root/autodl-tmp/model_merged \--adapters /root/autodl-tmp/output/v5-20260813-202529/checkpoint-100 \--output_dir /root/autodl-tmp/model_kto_final \--merge_lora true

七、模型推理

7.1 方案选择

 
方案速度稳定性推荐场景
Transformers 直接推理 慢(~2-3小时/1000条) ✅ 高 小批量、稳定性优先
vLLM API 服务 快(~10-20分钟) ⚠️ 需环境兼容 大批量、生产环境

7.2 Transformers 推理命令

使用之前准备好的未经训练的数据集进行推理,便于后续评测

查看官方推荐,设置参数 官方推荐使用以下采样参数组合进行生成: 
  通用任务的思考模式:temperature=1.0, top_p=0.95, top_k=20, min_p=0.0, presence_penalty=1.5, repetition_penalty=1.0
  精确编码任务(如 WebDev)的思考模式:temperature=0.6, top_p=0.95, top_k=20, min_p=0.0, presence_penalty=0.0, repetition_penalty=1.0
  通用任务的指令(或非思考)模式:temperature=0.7, top_p=0.8, top_k=20, min_p=0.0, presence_penalty=1.5, repetition_penalty=1.0
  推理任务的指令(或非思考)模式:temperature=1.0, top_p=0.95, top_k=20, min_p=0.0, presence_penalty=1.5, repetition_penalty=1.0
请注意,不同推理框架对采样参数的支持情况可能有所不同。任务定位:属于“精确编码任务” 让模型从提问的需求中提取功能点并生成结构化的JSON数组,这本质上是信息提取 + 结构化输出 因此,参数设置如下: temperature=0.1 top_p=0.95 top_k=20 min_p=0.0 presence_penalty=1.5 repetition_penalty=1.0

7.3 vLLM 推理(如果兼容)

CUDA_VISIBLE_DEVICES=0 python -m vllm.entrypoints.openai.api_server \--model ./model_kto_final \--served-model-name testcase-generator \--dtype bfloat16 \--port 6006

八、评测体系

8.1 评测框架

使用 eval_results.jsonl(每条包含 expectedactual 数组),通过 DeepSeek API 进行语义评分。

8.2 核心指标

数据规模与格式

 
指标计算方式
格式正确率 有效解析数 / 总样本数
平均测试点数 总测试点数 / 总样本数
生成/标准比例 生成总数 / 标准总数

语义质量(样本级)

 
指标计算方式阈值
平均相似度 所有样本 DeepSeek 评分的均值
采纳率 得分 ≥ 80 的样本数 / 总样本数 80分

召回率与准确率(测试点级)

 
指标计算方式含义
召回率 匹配成功数 / 标准测试点总数 标准测试点被覆盖的比例
准确率 匹配成功数 / 生成测试点总数 生成测试点中有效的比例
F1 2 × P × R / (P + R) 综合平衡指标

隐藏需求检测

通过关键词匹配检测模型是否识别隐含约束:

关键词: 权限、安全、兼容、性能、异常、边界、并发、超时、加密、解密、日志、缓存、隔离、容错

8.3 综合评级标准

# 针对测试用例生成任务(低温度,高精度)
if precision > 0.9 and recall > 0.65 and adoption_rate > 0.8:⭐⭐⭐ 优秀:可直接部署
elif precision > 0.8 and recall > 0.5 and adoption_rate > 0.7:⭐⭐ 良好:基本可用,可优化
elif precision > 0.7 and recall > 0.35:⭐ 一般:需要改进
else:❌ 需改进:重新评估策略
以上评级标准基于本项目业务场景(测试用例生成)设定,供参考。

、常见问题与避坑指南

9.1 vLLM 启动失败

现象ValueError: Model architectures [...] are not supported

原因:vLLM 版本与 Transformers 版本不兼容。

解决:改用 Transformers 直接推理(稳定,虽然慢但兼容性好)。

9.2 磁盘空间不足

现象:系统盘 100%,容器异常。

解决

  • MODELSCOPE_CACHEHF_HOME 指向数据盘。

  • 定期清理 ~/.cache

9.3 显存不足(OOM)

解决

  • 降低 per_device_train_batch_size(从 4 降到 2 或 1)

  • 降低 max_length(从 2048 降到 1024)

  • 启用 bf16fp16

9.4 所有测试点都被标为 false

原因:生成内容与标准答案格式差异巨大(如自然语言 vs JSON)。

解决

  1. 在 Prompt 中强制要求 JSON 格式输出

  2. 关闭思考模式

  3. 增加上下文长度

十、总结

 
阶段核心动作关键产出
阶段0(数据准备) 9:1 拆分,格式化为 messages sft_train.json + dev.json
阶段1(SFT) 1 轮 LoRA 微调 SFT 模型(checkpoint-134)
阶段2(动态打标) 高温生成 + 评分打标 KTO 数据(含 label)
阶段3(KTO)
undesirable_weight=1.2+
2 轮训练
KTO 最终模型
阶段4(推理) Transformers/vLLM 生成 generated.jsonl
阶段5(评测) DeepSeek 语义评分 + 贪心匹配 评测报告(召回率/准确率/F1)

核心心法:小数据集 = 防过拟合 + 强制挖负样本 + 加大奖惩。跑通全流程后,86% 的采纳率证明这套方案完全可行!🚀

 
← 返回列表