Skip to content

feat(train): L1–L3 OMR 模型训练 —— 工程格式标准化、技术方案与训练 Framework(新 App) #92

Description

@loootte
## 背景

恩谱识别已走 **结构优先** 路线(`ENPU_PIPELINE_MODE=structure`):

|| 职责(现状) |
|----|----------------|
| L1 | 页面级:标题、调号/拍号区、主谱面 ROI |
| L2 | 主谱面谱行(systems/rows),旋律带与和弦/歌词绑定 |
| L3 | 行内纵向 **splits**(主存)→ 派生 measures |
| L4–L5 | 小节内候选与音高 OCR 等(本 Issue **不做**|

当前 L1–L3 主要依赖 OpenCV / 几何与规则,在真实敬拜谱上仍不稳定。已具备:

- 分层识别与桌面按层编辑(含 L3 拖线等)
- 结构结果可进工程 / API(`structure.items[]``structure.barlines[]`、IR 等)
- 手动框/线作为 GT 做评估与单层调参的方向

**缺口:** 尚无「以恩谱工程/结构标注为标准」的 **L1–L3 监督学习数据规范****独立训练 Framework**,无法系统收集数据并训练可直接输出 L1–L3 布局的 OMR 模型。

本 Issue 目标:打通 **标准训练数据 ← 现有工程格式**,设计 **L1–L3 模型技术方案**,并搭建 **新的训练 App(framework)**(与 `core`/`desktop` 解耦)。

---

## 目标

1. **总结并固化** 现有恩谱工程/结构相关文件格式,形成 **L1–L3 训练数据标准**(含必填字段、坐标约定、与 Score v0.1 的边界)。  
2. **设计技术方案**:任务定义、模型输入输出、损失与指标、数据流、与现有 `structure` 管线的对接方式。  
3. **搭建训练 Framework(新 App)**:数据集管理、训练/验证循环、导出推理权重、与恩谱 core 集成的最小接口(可后置)。  

### 非目标(本 Issue)

- 训练完整 L4–L5 / 端到端音高大模型  
- 替换桌面产品为训练工具  
- 必须一次超过现有几何基线(先跑通数据→训练→推理闭环)  
- 在本 Issue 内完成大规模标注众包  

---

## 任务 1:总结现有工程格式 → 训练数据标准

### 1.1 需要盘点的现有产物

| 来源 | 路径/概念 | 与训练的关系 |
|------|-----------|----------------|
| Score 语义 | `docs/jianpu-schema.md``enpu-score-v0.1` | **不是** L1–L3 几何 GT;仅作页级元数据(title/key/time)可选对齐 |
| 结构 IR | `core/app/pipeline/structure/ir.py`| PageLayout / StaffSystem / SplitLine / Measure… 布局真源候选 |
| API structure | `structure.items[]`(层、label、box)、`structure.barlines[]`(L3 线) | 与桌面叠图、编辑、rerun 一致,优先作为导出标准 |
| 工程文件 | `.enpu.json` 及结构缓存字段(以仓库实际为准) | 人工校正后的 **可版本化样本** |
| 评测集 | `samples/eval`、manual GT | 可迁移为 val 集,需统一到同一 schema |

**交付物:** `docs/train/l1-l3-data-spec.md`(或等价)

内容至少包括:

1. **一张样本的目录/文件约定**(图 + 标注 JSON)  
2. **L1 / L2 / L3 字段表**(名称、类型、必选、坐标系)  
3. **与现有 `structure` / IR 的字段映射表**(工程 → 训练样本)  
4. **坐标约定**:全图像素、原点、预处理后是否回写(与 `architecture-structure-first` 一致)  
5. **L3 语义**:主存 `splits[]`(有序 x),`measures` 仅派生  
6. **负例/忽略区** 约定(页眉、纯歌词行是否标)  
7. **版本号** `layout_schema_version`(与 `score.schema_version` 分离)

### 1.2 建议的训练样本逻辑结构(草案,任务 1 中定稿)

```text
Sample {
  layout_schema_version: "0.1",
  image: { path | hash, width, height },
  meta?: { title, key, time_signature, source },
  l1: {
    title?: BBox,
    key_time?: BBox,
    score_region: BBox
  },
  l2: {
    systems: [{ id, bbox, kind?: "pitch_row" | ... }]
  },
  l3: {
    # 按 system 组织
    rows: [{
      system_id,
      splits: [{ id, x, y1?, y2?, source: "user"|"detect" }]
    }]
  },
  # measures 不强制存盘,可由 L2.bbox + splits 计算;若存盘需可校验一致
}

1.3 从恩谱工程导出

  • 脚本:scripts/export_layout_gt.py(名可改)
    • 输入:工程 / base_structure + 原图
    • 输出:符合 data-spec 的样本
  • 校验:splits 单调、落在 L2 内、派生 measure 数 = splits+1 规则等

验收(任务 1): 文档合并 + 至少 1 个真实工程 导出为标准样本并通过校验器。


任务 2:技术方案设计

2.1 任务定义(L1–L3 only)

子任务 输入 输出 类型建议
L1 全图 score_region(+ 可选 title/key_time) 检测 / 分割
L2 全图或 score ROI 水平谱行 systems[] 行检测 / 多框检测
L3 单行 ROI 或全图+行条件 该行 splits 的 x(或竖线 segment) 线检测 / 关键点回归 / 序列

原则:多任务可同骨干分头,也可分阶段三模型;首版优先 可训通、可导出 ONNX/Torch,精度第二。

2.2 推荐技术路线(可在设计文档中定一种主路径)

主路径 A(务实)

  • Backbone:轻量 CNN(或现成检测骨干)
  • L1/L2:目标检测(类别 = score / system / …)或语义分割再提框
  • L3:在 L2 裁切上做 竖线热力图 / 1D 投影序列标签 或关键点 x 回归
  • 后处理:NMS、最小间距、与 data-spec 一致的 splits 规范化

主路径 B(若数据极少)

  • 先合成布局数据(印刷简谱渲染 → 自动 L1–L3 GT)预训练
  • 再用恩谱工程导出的真实 GT 微调

2.3 损失与指标

  • L1/L2:IoU、mAP@0.5,score_region 召回优先
  • L3:
    • 数量|n_pred - n_gt|、exact rate
    • 位置:匹配后 mean_abs_x_error(与现有 L3 线级评估一致)
  • 禁止只用派生 measure 框 IoU 作为唯一主指标

2.4 与恩谱 core 对接

训练 App 导出 weights
  → core 推理适配层(structure 模式可切换 engine=learned_l1l3)
  → 输出仍转为现有 structure.items / barlines / IR
  → 桌面叠图与编辑不改协议

几何规则管线保留为 fallback;learned 与 rule 可对比评测。

2.5 数据与合规

  • 训练图仅限授权/自有/可公开 samples;商业谱不进公开集
  • 私有 GT 目录约定(如 samples/private/layout/)不入库明文

交付物: docs/train/l1-l3-model-design.md(架构图、头设计、指标、数据流、风险)

验收(任务 2): 设计文档 review 通过;选定 MVP 模型范围(建议:L2 行框 + L3 行内 splits,L1 score_region 可一并或二期)。


任务 3:搭建训练 Framework(新 App)

3.1 定位

  • 新应用/新目录(建议 train/ 或独立 repo EnPu-train),不塞进 Tauri 桌面逻辑。
  • 职责:数据集、训练、验证、导出;不负责完整敬拜编辑产品功能。

3.2 建议目录

train/   # 或独立仓库
  README.md
  configs/           # 数据路径、超参、模型
  enpu_train/
    data/            # Dataset,读 data-spec JSON
    models/          # L1L3 网络定义
    losses/
    metrics/         # IoU、split count、x error
    engine/          # train / eval loop
    export/          # ONNX / state_dict
  scripts/
    export_from_enpu_project.py
    train.py
    eval.py
  tests/

3.3 MVP 功能清单

  • 读取 任务 1 标准样本 的 Dataset + DataLoader
  • 可视化:图 + L1/L2 框 + L3 竖线(训练前抽查)
  • 最小可训模型(可先只训 L2 或只训 L3 热力/回归)
  • train.py:loss 曲线、ckpt、val 指标
  • eval.py:在 hold-out 上输出与恩谱 L3 线级指标同构的报告
  • 导出权重 + 简短「如何在 core 中加载」说明(core 集成可另 Issue)
  • README:环境、数据准备、一条命令跑通 toy 训练

3.4 技术选型建议(可改)

  • Python 3.10+、PyTorch(与后续 ONNX 导出常见路径一致)
  • 配置 YAML;日志 JSON/TensorBoard 任选
  • 不强制上检测大框架;数据少时宁可模型小、管线清

验收(任务 3):

  1. 使用 ≥1 张真实导出样本 + 若干合成/增强 能完成一次 train epoch 不报错。
  2. val 脚本输出 L2 框 IoU 或 L3 x 误差中的至少一类硬指标。
  3. 文档说明与恩谱 structure 字段对应关系。

总任务拆分与顺序

顺序 任务 产出
P0 任务 1 格式总结 + 校验 + 导出脚本 l1-l3-data-spec.md、样例样本
P0 任务 2 技术方案设计定稿 l1-l3-model-design.md
P1 任务 3 Framework 骨架 + toy 训练 train/ App
P2 合成数据 / 真实集扩充、core 推理插件 可另开 Issue

依赖:任务 3 依赖任务 1 的 schema 冻结;任务 2 与任务 1 可并行初稿,但实现以冻结的 data-spec 为准。


验收标准(整 Issue)

  1. 标准:存在正式 data-spec,且从现有恩谱结构/工程 导出 → 校验通过 的路径可复现。
  2. 设计:模型输入输出与 L1–L3 语义一致(L3 为 splits 而非无约束自由矩形主存)。
  3. Framework:独立训练 App 可安装依赖并完成一次最小训练与评估。
  4. 边界清晰:Score v0.1 语义与 layout GT 分离;本阶段不承诺 L4–L5 学习。

风险

风险 缓解
工程里 layout 字段不统一 任务 1 先映射表 + 校验器,再训
真实标注量少 合成预训 + 少样本微调;先 L3 行内问题
与几何管线双轨 统一输出 structure schema;A/B 评测
训练 App 与 core 强耦合 仅通过 data-spec 与权重文件交换

相关

  • docs/architecture-structure-first.md(L1–L5、IR、structure 序列化)
  • docs/jianpu-schema.md(Score v0.1,无布局几何)
  • docs/l3-split-model.md(若存在)
  • L3 分割线模型 / 线级评估(数量 + x 偏差)
  • 单层调优与手动 GT 编辑
  • docs/eval-baseline.md

建议的子 Issue 拆分(可选)

  1. docs(train): L1–L3 layout data-spec 与工程导出
  2. docs(train): L1–L3 学习模型技术方案
  3. feat(train): 训练 Framework 骨架与 toy 训练

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions