Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -123,3 +123,9 @@ logs/
# local process state for start/stop scripts
scripts/.run/


# Train framework local runs (#95)
train/runs/
train/data_cache/
train/.venv/

2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ L5 音符节点 音高数字 OCR(+几何兜底)+ 时值线 / 高低音点
桌面在结构模式下可叠图查看 L1–L5,L3 以分割线编辑为主。
完整说明:[architecture-structure-first.md](./docs/architecture-structure-first.md) · [l3-split-model.md](./docs/l3-split-model.md) · [architecture.md](./docs/architecture.md)。

L1–L3 **布局训练**(#92–#95):数据规范 [docs/train/l1-l3-data-spec.md](./docs/train/l1-l3-data-spec.md) · 模型方案 [l1-l3-model-design.md](./docs/train/l1-l3-model-design.md) · Framework [`train/`](./train/)。

---

## 仓库结构
Expand Down
26 changes: 14 additions & 12 deletions docs/train/l1-l3-model-design.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

> 状态:设计定稿 v0.1(#94 / 父任务 #92)
> 数据契约:[`l1-l3-data-spec.md`](./l1-l3-data-spec.md)(`layout_schema_version` **0.1**)
> 实现骨架:训练 Framework **#95**;core 推理插件为 **P2**(另开 Issue)
> 实现骨架:训练 Framework **#95** 见仓库 [`train/`](../../train/);core 推理插件为 **P2**

---

Expand Down Expand Up @@ -264,21 +264,23 @@ learned_l1l3:

---

## 8. 训练 Framework 接口预期(给 #95)
## 8. 训练 Framework#95 已落地

最小可实现切片(与 #95 验收对齐):
目录:`train/`(说明见 [`train/README.md`](../../train/README.md))。

| 模块 | 职责 |
|------|------|
| `data/` | 读 data-spec;collate;可视化图+框+竖线 |
| `models/` | L2 det ± L3 heat(L1 可选) |
| `metrics/` | L2 IoU/mAP;L3 count + mean_abs_x |
| `engine/` | train/eval loop、ckpt |
| `export/` | state_dict / ONNX + README「core 如何加载」段落 |
| `configs/mvp_l2_l3.yaml` | 任务开关、路径、超参 |

一条命令:`python scripts/train.py --config configs/mvp_l2_l3.yaml`
数据:≥1 真实样本 + 合成/增强;至少 1 个 epoch 不报错。
| `enpu_train/data/` | data-spec Dataset + 合成样本 + 可视化 |
| `enpu_train/models/` | L2 page **y-heat** + L3 row **x-heat**(轻量 CNN) |
| `enpu_train/metrics/` | L2 条带 IoU;L3 count + mean_abs_x |
| `enpu_train/engine/` | train/eval、ckpt |
| `enpu_train/export/` | state_dict(+ 可选 ONNX) |
| `configs/mvp_l2_l3.yaml` | 任务与超参 |

```powershell
cd train
python scripts/train.py --config configs/mvp_l2_l3.yaml
```

---

Expand Down
121 changes: 121 additions & 0 deletions train/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
# EnPu Train — L1–L3 布局训练 Framework(#95)

独立于 `desktop/` 的训练应用:读 **layout data-spec** 样本,训练轻量 **L2 + L3** 模型(#94 MVP-1),导出权重。

| 文档 | 链接 |
|------|------|
| 数据规范 #93 | [docs/train/l1-l3-data-spec.md](../docs/train/l1-l3-data-spec.md) |
| 模型方案 #94 | [docs/train/l1-l3-model-design.md](../docs/train/l1-l3-model-design.md) |
| 样例数据 | [samples/layout/](../samples/layout/) |

## 目录

```text
train/
README.md
requirements.txt
configs/mvp_l2_l3.yaml
enpu_train/
data/ # Dataset + 合成样本
models/ # L2 page y-heat + L3 row x-heat
losses/
metrics/ # L2 IoU + L3 split count / mean_abs_x
engine/ # train / eval
export/ # state_dict + ONNX
viz.py
scripts/
train.py
eval.py
viz_sample.py
export_from_enpu_project.py
tests/
```

## 环境

```powershell
cd train
python -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -r requirements.txt
```

需要 **Python 3.10+**、**PyTorch**。有 GPU 时可在配置里设 `train.device: cuda`。

## 数据准备

1. **真实工程** → layout 样本(#93):

```powershell
# 仓库根
$env:PYTHONPATH = ".\core"
python scripts\export_layout_gt.py --project path\to\song.enpu.json --out samples\layout\L00x

# 或在 train/ 下
python scripts\export_from_enpu_project.py -p path\to\song.enpu.json -o ..\samples\layout\L00x
```

2. **仓库已有**:`samples/layout/L001_zuozai_baozuo/`
3. **合成**:`train.py` 会按配置自动生成 `data_cache/synth/S00*`(默认 8 张)

抽查可视化:

```powershell
cd train
python scripts\viz_sample.py ..\samples\layout\L001_zuozai_baozuo
```

## 一条命令 toy 训练

```powershell
cd train
python scripts\train.py --config configs\mvp_l2_l3.yaml
```

默认:CPU、3 epoch、真实 layout + 合成数据、写出:

- `runs/mvp_l2_l3/last.pt` / `best.pt`
- `runs/mvp_l2_l3/history.json`
- `runs/mvp_l2_l3/export/layout_net.pt`
- `runs/mvp_l2_l3/export/onnx/*.onnx`(若 ONNX 导出可用)

评估:

```powershell
python scripts\eval.py --ckpt runs\mvp_l2_l3\best.pt --data ..\samples\layout
```

指标:`l2_mean_iou`、`l3_mean_abs_x_error`、`l3_split_count_mae` / `exact`(与 #86 线级语义同构)。

## 模型与 structure 对应

| 模型输出 | 恩谱 structure / IR |
|----------|---------------------|
| L2 1D y 热力峰值 → 水平条带框 | `items[]` layer=L2 `kind=system`;`StaffSystem.rect` |
| L3 行 crop 上 x 热力峰值 | `barlines[]` / `StaffSystem.splits`(interior x) |
| 后处理 `normalize_splits` + `splits_to_measures` | L3 `measure_derived` 框(派生,非主学) |

**core 如何加载(P2 草图,本仓库尚未接插件):**

1. 读 `export/layout_net.pt` 或 ONNX
2. 全图 → L2 峰值 → systems
3. 每行 crop → L3 峰值 → splits(全图 x)
4. 填入 `StructureDebug` / `PageLayout`,再跑现有 L4–L5 或仅叠图
5. 配置预留:`ENPU_STRUCTURE_ENGINE=learned_l1l3`(实现见后续 Issue)

规则几何管线保持 fallback。

## 测试

```powershell
cd train
python -m pytest tests -q
```

## 非目标

- 大规模真实集 / 完整合成流水线
- core 内完整 `learned_l1l3` 推理插件
- 精度超过几何基线的承诺

父任务:[Issue #92](https://github.com/loootte/EnPu/issues/92) · 本任务 [#95](https://github.com/loootte/EnPu/issues/95)
32 changes: 32 additions & 0 deletions train/configs/mvp_l2_l3.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# MVP-1: L2 systems (page y-heat) + L3 splits (row x-heat) — #95 / #94
tasks: [l2, l3]

data:
# real data-spec samples (#93)
roots:
- ../samples/layout
# synthetic pages generated under train/data_cache/synth
synth_count: 8
synth_dir: data_cache/synth
page_size: [384, 512] # H, W
row_size: [64, 256]
l2_heat_len: 128
l3_heat_len: 128
augment: true
val_ratio: 0.25

train:
epochs: 3
batch_size: 2
lr: 0.001
weight_decay: 0.0001
l2_loss_weight: 1.0
l3_loss_weight: 1.5
device: cpu # set cuda if available
num_workers: 0
out_dir: runs/mvp_l2_l3
log_every: 1

export:
state_dict: runs/mvp_l2_l3/export/layout_net.pt
onnx_dir: runs/mvp_l2_l3/export/onnx
3 changes: 3 additions & 0 deletions train/enpu_train/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
"""EnPu L1–L3 layout training framework (#95 / #92)."""

__version__ = "0.1.0"
4 changes: 4 additions & 0 deletions train/enpu_train/data/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from enpu_train.data.dataset import LayoutDataset, collate_layout
from enpu_train.data.synthetic import make_synthetic_layout_sample

__all__ = ["LayoutDataset", "collate_layout", "make_synthetic_layout_sample"]
Loading
Loading