Qwen3-8B Scene Boundary Detection LoRA
All Novel Can Be Galgame — Agent 2: 场景边界检测
判断段落序列中哪些位置应切换 scene。三 Agent 中最难任务。当前默认 main = v4-590(DeepSeek 重标注, F1 30.5%)。
基座: Qwen3-8B-Novel-Base-SFT | 方法: LoRA r=64 α=128 | 硬件: A800 80GB
训练代码仓库:https://github.com/lin1753/novel-agent
项目地址;https://github.com/lin1753/novel2galgame
任务
- 输入: 编号段落
[P1]...[P2]... - 输出:
{"boundaries": [N]}— N 为切分位置 - 测试集: 49 条 (v4 标准)
示例
输入:
[P1] 下课铃响,教室里热闹起来。
[P2] 她低头收拾书包。
[P3] 我犹豫了一下,还是叫住了她。
[P4] 十分钟后,我们并肩走在校门外的街道上。
输出:
{"boundaries": [3]} ← P3后切scene(教室→校门外)
加载
from transformers import AutoModelForCausalLM
from peft import PeftModel
base = AutoModelForCausalLM.from_pretrained(
"mikuhhn1239/qwen3-8b-novel-base-sft",
torch_dtype="auto", device_map="auto",
)
model = PeftModel.from_pretrained(
base, "mikuhhn1239/qwen3-8b-scene-segmentation-lora"
)
训练配置
基座: Qwen3-8B-Novel-Base-SFT (Stage1 全参 SFT, 72K)
方法: LoRA (r=64, α=128, dropout=0.05)
框架: transformers Trainer + PEFT
优化器: AdamW (adamw_torch_fused), cosine schedule, warmup=5%
epoch: 5 | LR: 1e-4 | batch: 1×16(accum) | bf16 | max_length: 4096
分支映射
| 分支 | 版本 | F1 | 说明 |
|---|---|---|---|
main |
v4-590 | 30.5% | DeepSeek 重标注,当前最佳 |
v4 |
v4-590 | 30.5% | 同 main |
v3.1 |
v3.1 | 28.6% | 人类 Clean 标注最佳(旧默认) |
v3 |
v3 | 19.6% | 3ep 欠拟合 |
testing |
v3.2 | 20.0% | reasons + 扩标,反退步 |
test-best |
v2 | 53.3% | 史上最高但标注标准不同 |
完整版本历史
v1–v2:早期探索
| 版本 | train | 格式 | P | R | F1 | 说明 |
|---|---|---|---|---|---|---|
| v1 | 65 | 端到端 + reasons | 33.3 | 33.3 | 33.3% | 句子级粒度过细,不可比 |
| v2 | 280 | 纯边界 + reasons | 57.1 | 50.0 | 53.3% | test-best 分支,标注标准不同 |
v3 系列:人类 Clean 标注
| 版本 | train | prompt | 格式 | F1 | 说明 |
|---|---|---|---|---|---|
| v3 | 280 | 95 字 | 纯边界 | 19.6% | 3ep 欠拟合 |
| v3.1 | 280 | 95 字 | 纯边界 | 28.6% | 5ep,v3 标注最佳 |
| v3.2 | 384 | 735 字 | reasons | 20.0% | 长 prompt + reasons 退步 |
| v3.6 | 384 | 95 字 | 纯边界 | 28.2% | 追平 v3.1,验证短 prompt 是关键 |
三次格式实验(均失败)
| 版本 | 方法 | F1 | eval_loss | 退化策略 |
|---|---|---|---|---|
| v3.2 | 只列正样本 | 20.0% | ↗ | 猜位置 1,10,14 |
| v3.3 | 每对都判断 | 15.4% | → | 全 false + 1 true |
| v3.4 | 独立 pairwise | 12.0% | ↗↗ | 全 false |
| v3.5 | Best-of-N | 21.4% | — | FP 未抑制 |
v4 系列:DeepSeek 重标注 — 唯一突破
| 版本 | train | 标注 | eval_loss | F1 | 亮点 |
|---|---|---|---|---|---|
| v4-296 | 296 | DeepSeek 初版 | 1.85→1.79 ↓ | 26.7% | 首次 eval_loss 下降 |
| v4-590 ⭐⭐ | 590 | DeepSeek 重标注 | 1.92→1.51 ↓ | 30.5% | 最稳健,跨密度泛化最好 |
| v4.1-1804 | 1804 | DeepSeek 扩标 | 1.74→1.32 ↓ | 29.9% | 三倍数据未超 v4-590,低质量标注稀释信号 |
| v4.1-582 | 582 | DeepSeek 精炼 | — | 30.2% | ≥2 边界占 76%,高密度泛化差(低密度仅 25.9%) |
v4.1 扩标实验详情
v4.1-1804:快速扩标到 1804 条。边界比 8.5%(太保守),31% 零边界。eval_loss 创全系列新低(1.74→1.32),但 F1=29.9% 未超 v4-590。大量低质量标注稀释了信号。
v4.1-582 精炼:筛选 ≥2 边界 + 非 P1 起切 + 8-18 段。边界比 15.6%,零边界仅 8%,≥2 边界占 76%。F1=30.2%(接近 v4-590),但依赖训练密度 — 在低密度测试集上仅 25.9%。
结论:数据密度影响泛化。模型学会训练集的边界密度,密度不匹配时 F1 崩盘。扩标+精炼均未超越 v4-590 的 30.5%。
全系列最终排名
| 版本 | train | prompt | 标注 | F1 | 亮点 |
|---|---|---|---|---|---|
| v2 | 280 | 95 字 | 人类(v2标准) | 53.3% | 标注标准不同 |
| v4-590 ⭐⭐ | 590 | 95 字 | DeepSeek | 30.5% | 最稳健,跨密度泛化最好 |
| v4.1-582 | 582 | 95 字 | DeepSeek 精炼 | 30.2% | 高密度特化 |
| v4.1-1804 | 1804 | 95 字 | DeepSeek 扩标 | 29.9% | eval_loss 最低但未转化 F1 |
| v3.1 | 310 | 95 字 | 人类(v3Clean) | 28.6% | |
| v3.6 | 384 | 95 字 | 人类(v3Clean) | 28.2% |
v3.1验证集指标如下
v4与4.1指标对比
关键结论
三大根因
- LM loss ≠ F1 最大化:边界仅占 ~10% 样本,"全 false" 即最低 loss
- 全局篇章理解需求:不同于 narrative-type / attribution 的局部判断,scene-boundary 需要 10-20 段落的全局结构 — 8B 容量可能不够
- 数据不平衡:训练/验证集边界密度不匹配,模型学会训练密度后泛化差
经验
- 短 prompt 是必要条件(95 字 vs 735 字 → +8pp)
- 标注质量 > 数据量 > 训练技巧:DeepSeek 重标注是唯一突破 30% 的路径
- FP 是最终瓶颈:所有版本精度 27-29%,模型始终预测 2-3× 太多边界
- 8B + SFT 天花板 ≈ 30% F1:格式改进、数据扩标、精炼过滤均未突破
- 简单 = 好:不加 reasons、不加推理链、不加复杂格式
继续突破方向
- GRPO/DPO 用 F1 做 reward 信号
- 换 32B/72B 基座
- 增大训练集正样本比例(当前 ~10%)
其他 Agent
| Agent | 模型 | 指标 |
|---|---|---|
| Agent 1: 叙事分类 | narrative-parsing-lora |
acc 72.8% (v4) |
| Agent 3: 角色归因 | attribution-assist-lora |
acc 86.7% (v3.2) |