Commit fa7f5f57 fa7f5f576d81902b8b307b47f4452244423b9657 by cnb.bofCdSsphPA

Clarify the real data contract before scaling external datasets

Constraint: Must document code-true behavior for training crops, retrieval windows, GPU support, and FMA reuse before more dataset automation lands
Rejected: Leave docs at high-level abstractions only | Would hide 5s-vs-8s and CPU-vs-GPU operational realities
Confidence: high
Scope-risk: narrow
Directive: Keep future dataset docs aligned with actual code paths and artifact timestamps, not intended architecture alone
Tested: Source review of dataset.py manifest_tools.py external_adapters.py utils/audio.py ecapa_embedder.py train.py; live FMA smoke progress observed through epoch completion
Not-tested: Markdown renderer-specific Mermaid rendering and every relative link target in external viewers
1 parent 713425f5
......@@ -2,6 +2,34 @@
## 2026-06-02
### Stage: 补齐训练数据、重叠窗口、GPU 与 FMA 数据处理文档
完成项:
- 重写并压缩 `dataset-spec.md`,补齐训练切片、检索重叠滑窗、manifest 生成差异
- 扩展 `training-data-and-pgvector-guide.md`,补齐 FMA / MTG / 自有数据接入、目录规范、脚本职责、GPU 加速说明
- 明确记录当前真实代码事实:训练端 5s 随机裁剪、检索端 5s/2.5s 重叠滑窗、外部 manifest 默认 8s query
- 记录当前 smoke 现状:`smoke-local` 仍固定 CPU,真实 FMA smoke 正在运行
- 记录当前实验产物一致性风险:旧的 `fma_reports_smoke/config.json` 与最新 manifests 时间戳不一致,需后续统一配置治理
验证结果:
- 源码复核:
- `src/data/dataset.py`:训练端随机 5s crop
- `src/utils/audio.py` / `src/engines/ecapa_embedder.py`:5s window + 2.5s stride
- `src/data/manifest_tools.py`:每首歌 1 个随机 query,默认 `8.0s`
- `src/data/external_adapters.py``smoke-local` 当前硬编码 `--device cpu`
- `train.py`:支持 `--device auto`,CUDA 路径支持 mixed precision
- 真实运行状态:
- FMA smoke 进程仍在运行
- 最新可见进度约 `82%` epoch 1
- 文档链接验证:主文档仍使用相对路径链接到仓库文件与同组文档
结论:
- 当前项目关于训练数据格式、3 分钟 mp3 切片、是否重叠窗口、GPU 是否可显著加速、FMA 与开放数据如何复用流程,已形成可交接文档
- 后续可继续沿两条线推进:
1.`smoke-local` 支持 GPU
2. 增加 overlap query manifest 生成能力
### Stage: 真实 FMA 本地数据门槛打开并进入 smoke 训练
完成项:
......
# ACR Dataset / 输入输出规范
> 更新:2026-06-02
> 关联文档:[训练数据与 pgvector 指南](./training-data-and-pgvector-guide.md) · [开放数据工作流](./open-dataset-workflow.md) · [数据来源与接入](./dataset-sources-and-licensing.md)
## 一页结论
- 数据规范的核心不是文件格式,而是**分离 catalog 与 query**
- 外部数据集进入系统前必须先转换成统一 manifest
- 当前系统的标准输入是:
- **16k mono audio**
- **128 Mel**
- **window-level retrieval**
- 当前系统的标准输出是:
- top-k candidates
- confidence
- reject/accept
- metadata
当前项目的数据规范,最重要的是 4 件事:
1. **训练输入不是“整首 mp3 文件”本身,而是 manifest 驱动的 reference + query 样本体系**
2. **训练和检索的切窗策略不同**:训练端当前是**随机裁剪 5s**,检索/建索引端当前是**5s 窗口 + 2.5s stride 的 50% 重叠滑窗**
3. **外部开源数据集进入项目时,必须先转换成统一 manifest**,再做训练、评测、索引和 pgvector 入库。
4. **当前音乐任务输入层已切换到 128 维 Mel 频谱**,并开启 band-split 方向;FMA 这类真实数据建议优先使用 GPU。
---
......@@ -22,13 +18,14 @@
```mermaid
flowchart LR
A[External / Synthetic Audio] --> B[Manifest Conversion]
B --> C[Catalog Manifest]
B --> D[Query Manifest]
C --> E[Reference Index Build]
D --> F[Training / Evaluation Queries]
A[Raw Audio\nFMA / MTG / 自有 BGM / 录音] --> B[Manifest Conversion]
B --> C[Catalog Manifest\nreference]
B --> D[Train/Test Manifest\nquery]
C --> E[Reference Index Build\nsliding windows]
D --> F[Training / Evaluation]
E --> G[Hybrid Retrieval]
F --> G
G --> H[pgvector / report / service]
```
---
......@@ -58,6 +55,7 @@ flowchart TD
Q --> Q2[audio_path]
Q --> Q3[duration]
Q --> Q4[type=clean/augmented/confused/humming_like]
Q --> Q5[offset]
```
---
......@@ -66,14 +64,60 @@ flowchart TD
| 环节 | 输入 | 输出 |
|---|---|---|
| 训练 | query segments | embeddings + logits |
| 训练 | query segments + references | embeddings + logits |
| 索引 | catalog references | chromaprint index + embedding index |
| 识别 | query audio | ranked candidates |
| 评测 | query manifest + catalog | top1/top5/hard-case report |
| 入库 | manifest + embedding | pgvector-ready JSON / SQL rows |
---
## 4.1 Hard-case 训练信号图
## 5. 3 分钟 mp3 到 5–8 秒片段:当前到底怎么切
## 5.1 当前代码里有 **3 种不同切法**
```mermaid
flowchart TD
A[3min mp3] --> B[训练 Dataset]
A --> C[检索 / 建索引]
A --> D[外部数据集 manifest 生成]
B --> B1[随机裁 1 个 5s clip]
C --> C1[5s 窗 + 2.5s stride]\n50% overlap
D --> D1[每首歌随机采 1 个 query]\n默认 8s
```
| 场景 | 当前实现 | 是否重叠 | 代码位置 |
|---|---|---:|---|
| 训练 `SongPairDataset` | 每次采样随机取一个 5s clip | 否,**不是固定滑窗** | [acr-engine/src/data/dataset.py](../acr-engine/src/data/dataset.py) |
| 检索 / embedding / 建索引 | `window_sec=5.0`, `stride_sec=2.5` | 是,**50% overlap** | [acr-engine/src/utils/audio.py](../acr-engine/src/utils/audio.py), [acr-engine/src/engines/ecapa_embedder.py](../acr-engine/src/engines/ecapa_embedder.py) |
| `audio-dir-to-splits` | 每首歌只生成 1 个随机 query | 否 | [acr-engine/src/data/manifest_tools.py](../acr-engine/src/data/manifest_tools.py) |
### 直接回答你的问题
- **有重叠窗口,但只在检索/索引链路里有。**
- **当前训练主链路没有对 3 分钟 mp3 预展开成“全量重叠切片集”**,而是每次 batch 动态随机裁一个 5s 片段。
- **当前外部数据集 manifest 生成器也没有自动为每首歌生成多个重叠 query。**
---
## 5.2 为什么这样设计
| 设计点 | 当前好处 | 当前限制 |
|---|---|---|
| 训练随机裁剪 | 节省存储,不必预生成几万切片 | 同一 epoch 暴露到的时间区域有限 |
| 检索重叠滑窗 | 更接近真实 ACR reference coverage | 索引体积更大 |
| 外部数据一首歌一个 query | smoke 更轻、更快验证 | 训练/评测覆盖不充分 |
推荐理解方式:
- **训练端**更像“随机数据增强采样器”
- **检索端**更像“为了召回覆盖做滑窗索引”
---
## 6. 当前训练信号与 hard-case 规则
## 6.1 Hard-case 训练信号图
```mermaid
flowchart LR
......@@ -97,7 +141,7 @@ flowchart LR
---
## 4.2 检索融合参数图
## 6.2 检索融合参数图
```mermaid
flowchart LR
......@@ -112,14 +156,9 @@ flowchart LR
| `ecapa_weight` | 0.50 | 0.55 | 提高 embedding 检索主导 |
| `melody_weight` | 0.25 | 0.25 | 暂时保持不变 |
说明:
- 当前仓库已经支持在 `evaluate.py` 中直接传入融合参数
- 对个人使用场景,推荐把一部分开源数据集固定成 **fusion tuning eval set**
- 这样训练、检索、调参可以分离,而不是每次都重训
---
## 4.3 开源数据集 train/eval 切分图
## 7. 开源数据集 train/eval 切分图
```mermaid
flowchart LR
......@@ -137,7 +176,7 @@ flowchart LR
| [test.json](../acr-engine/data/external_ingested/demo_via_adapter/fma/manifests/test.json) | 评估查询 | query + references |
| [val.json](../acr-engine/data/external_ingested/demo_via_adapter/fma/manifests/val.json) | 预留验证集 | 当前可为空 |
推荐法则(个人使用)
推荐法则:
- FMA / MTG-Jamendo 可优先用于真实 train/eval baseline
- 至少固定一部分曲目只进 [test.json](../acr-engine/data/external_ingested/demo_via_adapter/fma/manifests/test.json),不要同时参与训练
- 小数据集也要保证至少 1 个 train query + 1 个 test query
......@@ -148,38 +187,48 @@ CLI 入口:
- 导入前预检查:[acr-engine/src/data/external_adapters.py](../acr-engine/src/data/external_adapters.py) `inspect-local <dataset> <input_dir>`
- 多目录批量预检查:[acr-engine/src/data/external_adapters.py](../acr-engine/src/data/external_adapters.py) `inspect-batch fma=<dir> mtg_jamendo=<dir> ...`
## 5. 文字说明
---
## 8. 当前项目输入层规范
| 项目 | 当前值/建议 | 说明 |
|---|---|---|
| 采样率 | `16kHz` | 统一音频读取口径 |
| 声道 | `mono` | 当前链路按单声道处理 |
| 频谱 | `128 Mel` | 音乐任务输入层 |
| 训练 clip | `5s` | 当前训练代码事实 |
| 外部 query manifest 默认 | `8s` | 当前 `prepare-local/smoke-local` 默认 |
| Band split | `enabled` | 已纳入当前模型配置 |
### 5.1 为什么必须分离 catalog 和 query
早期原型容易把 train split 直接当搜索库,这会让评测和真实服务语义混乱。工业化系统必须把:
- “可搜索曲库”
- “训练/评测 query”
---
明确分离。
## 9. 文字说明
### 5.2 为什么输入层是 128 Mel
音乐任务需要更丰富的频带表达,128 Mel 更适合 band-split 和音乐 timbre/harmony 建模
### 9.1 为什么必须分离 catalog 和 query
工业化系统里,“可搜索曲库”和“训练/评测 query”必须分离,否则评测会和真实服务语义混在一起
### 5.3 query 类型为什么要显式标注
`clean / augmented / confused / humming_like` 是评测与训练策略的重要条件,不应只放在隐式文件名里
### 9.2 为什么输入层是 128 Mel
音乐任务需要更丰富的频带表达;128 Mel 比 40 维 MFCC 更适合 timbre/harmony/band-split 建模
### 5.4 为什么 hard-case 权重必须做到 sample-level
如果只在 batch 级取平均权重,`confused` 这种少量但高风险样本会被正常样本稀释。当前版本已经改成 **sample-level weighted SupCon + sample-level weighted CE**,从而让单个困难片段在损失中真实“被看见”
### 9.3 为什么 query 类型必须显式标注
`clean / augmented / confused / humming_like` 不只是标签名,而是训练权重、评测 bucket、难例治理的入口
### 5.5 当前经验结论
### 9.4 关于 5s vs 8s 的一个当前注意点
当前仓库有两组时长:
- **训练 Dataset 与默认模型训练:5s**
- **开放数据 manifest/query 默认:8s**
这不是同一层配置,因此当前文档和实验报告里必须明确区分;不要把它们误认为一套统一参数。
### 9.5 当前经验结论
- 简单过采样会导致整体退化
- type-aware weighting 能提升一部分 hard case
- confused 类需要更高权重,但过强偏置会回伤 `humming_like`
- residual confused failure 往往集中在 `intro` 片段,因此 `segment_type` 不只是元数据,还应参与后续难负例设计
- 因此 dataset 规范中必须保留 `type` 字段,后续才能继续做:
- confusion-aware negative mining
- melody-aware reranking
- 双支路 hard-case curriculum
- segment-type-aware hard negatives
---
## 6. 细节附录
## 10. 细节附录
### Reference 示例
```json
......@@ -203,6 +252,5 @@ CLI 入口:
}
```
## Sources
- See [references-and-sources.md](./references-and-sources.md) for the current source map.
- 当前代码事实来自 [acr-engine/src/data/dataset.py](../acr-engine/src/data/dataset.py), [acr-engine/src/data/manifest_tools.py](../acr-engine/src/data/manifest_tools.py), [acr-engine/src/utils/audio.py](../acr-engine/src/utils/audio.py), [acr-engine/src/engines/ecapa_embedder.py](../acr-engine/src/engines/ecapa_embedder.py), [acr-engine/train.py](../acr-engine/train.py)
......
......@@ -5,10 +5,13 @@
## 一页结论
你这次问的两个核心问题,可以先压缩成一句话:
围绕你最新问的几个问题,可以压缩成 5 句话:
1. **当前训练输入的最小单位是“带 `song_id` 标签的音频片段 + reference 全曲/长片段 + manifest”**,不是只扔一堆音频文件进去。
2. **如果后面要接入 `pgvector`,应先把音频转成标准资产和 manifest,再从 manifest 生成 embedding 与结构化元数据,不要直接把原始音频塞进数据库。**
1. **当前训练输入的最小单位是“带 `song_id` 的 query 样本 + reference 资产 + manifest”**,不是直接把 3 分钟 mp3 整批扔进模型。
2. **3 分钟 mp3 当前在训练端通常不是预切全量重叠窗口,而是运行时随机裁 5s;检索端才是重叠滑窗。**
3. **如果有 GPU,FMA 这类真实数据训练会明显加速,当前 `train.py` 已支持 `auto/cuda`,但 `smoke-local` 现在仍硬编码为 CPU。**
4. **FMA、MTG-Jamendo、自有 BGM/录音都应先变成统一 manifest,再做训练、评测和 pgvector 入库。**
5. **后续你们要扩自己的数据集时,最重要的不是文件后缀,而是 `song_id / type / offset / source_dataset / split` 这些结构化字段。**
---
......@@ -16,7 +19,7 @@
```mermaid
flowchart LR
A[原始素材\nBGM / 歌曲 / 录音] --> B[标准化音频资产\n16k / mono / wav优先]
A[原始素材\nBGM / 歌曲 / 录音 / FMA] --> B[标准化音频资产\n16k / mono]
B --> C[Reference 全曲/长片段]
B --> D[Query 短片段\n5s / 8s]
C --> E[Manifest\ncatalog/train/val/test]
......@@ -28,563 +31,310 @@ flowchart LR
---
## 2. 先回答你的问题 1:当前训练数据和输入数据应该是什么格式
## 2. 当前训练数据到底是什么格式
## 2.1 当前项目真正需要的输入,不只是音频文件
当前项目训练/评测链路需要 3 类输入:
## 2.1 不是“一个 mp3 文件”,而是三层对象
| 层 | 现在需要什么 | 作用 |
|---|---|---|
| 音频资产层 | `.wav/.mp3/.flac/.ogg` | 真正被读取和切片的内容 |
| 标注层 | `song_id``type``offset` 等 | 告诉系统“这是谁、是什么角色” |
| 音频资产层 | `.wav/.mp3/.flac/.ogg` | 真正被读取的内容 |
| 标注层 | `song_id``type``offset``source_dataset` | 告诉系统“是谁、是哪种样本” |
| manifest 层 | `catalog.json` / `train.json` / `test.json` / `val.json` | 驱动训练、建库、评测 |
也就是说,**最小可训练单元**不是“一个文件”,而是:
- 一个音频文件路径 `audio_path`
- 一个主标签 `song_id`
- 一个角色标签 `type`
- 一个时长 `duration`
- 一个 `audio_path`
- 一个 `song_id`
- 一个 `type`
- 一个 `duration`
- 如为 query,通常还应有 `offset`
---
## 2.2 当前代码侧的默认音频读取约束
从当前仓库实现看,数据读取是按以下原则处理的:
## 2.2 当前推荐音频约束
| 项目 | 当前推荐值 | 说明 |
|---|---|---|
| 采样率 | `16000 Hz` | 读取时会统一到 16k |
| 声道 | `mono` | 当前管线按单声道处理 |
| query 长度 | `5s``8s` | 训练常用 5s,开放数据 smoke 常用 8s |
| reference 长度 | 尽量完整曲目 | 用于建 reference 索引 |
| 频谱输入 | `128 维 Mel 频谱` | 你要求从 40 维 MFCC 切到音乐任务更合适的 128 Mel |
### 推荐的标准化目标
```text
容器格式:WAV 优先(也可 MP3/FLAC/Ogg)
采样率:16k
声道:mono
响度:建议归一化到稳定区间
切片长度:5s / 8s
```
---
## 2.3 训练数据中的两种核心角色
### A. Reference
Reference 是“曲库真身”,用于建索引、被检索、被匹配。
示例:
```json
{
"song_id": "song_0001",
"audio_path": "audio/song_0001.wav",
"duration": 183.4,
"type": "reference",
"source_dataset": "internal_bgm"
}
```
要求:
- 一首歌至少 1 条 reference
- 最好是完整曲目或较长主版本
- 不建议把手机录音、环境录音直接当主 reference
### B. Query
Query 是“未来线上用户会扔给你的东西”,用于训练和评测识别能力。
示例:
```json
{
"song_id": "song_0001",
"audio_path": "audio/song_0001_query_03.wav",
"duration": 5.0,
"type": "clean",
"offset": 63.2,
"segment_type": "mid",
"source_dataset": "internal_bgm"
}
```
要求:
- 来自对应 `song_id` 的 reference 曲目
- 时长稳定
- offset 可追溯
- query/reference 使用同一个 `song_id`
---
## 2.4 Query 里具体应该是什么内容
### 推荐内容类型
| type | 内容 | 用途 |
|---|---|---|
| `clean` | 原曲直接切片 | 基础训练/评测 |
| `augmented` | 加噪、混响、压缩、EQ 后切片 | 提升鲁棒性 |
| `confused` | 容易与别的歌混淆的难例片段 | 拉开区分度 |
| `humming_like` | 旋律近似、配器弱、手机录音风格片段 | 强化近旋律检索 |
| `reference` | 全曲或长片段 | 建库索引 |
### 不推荐直接混进训练主集的内容
- 完全未知来源、无法映射 `song_id` 的录音
- 严重截断、纯噪声、无有效音乐主体的片段
- 多首歌混在一起、没有主目标标签的片段
这些更适合先放到:
- 待清洗池
- 难例池
- 线上回流池
| 采样率 | `16000 Hz` | 读取时统一到 16k |
| 声道 | `mono` | 当前管线按单声道 |
| 训练片段长度 | `5s` | 训练数据集代码事实 |
| 外部 query 默认长度 | `8s` | `prepare-local/smoke-local` 默认 |
| 频谱输入 | `128 维 Mel` | 当前音乐任务输入层 |
| 模型配置 | `use_band_split=true` | 已集成频带分割模块 |
---
## 2.5 manifest 应该长什么样
### 最低字段要求
## 3. 3 分钟 mp3 怎么进入训练
| 字段 | 必需 | 说明 |
|---|---|---|
| `song_id` | 是 | 同一首歌的统一主标签 |
| `audio_path` | 是 | 相对路径,建议相对 manifest 根 |
| `duration` | 是 | 秒数 |
| `type` | 是 | `reference/clean/augmented/confused/...` |
| `offset` | query 建议有 | query 在 reference 中的起始位置 |
| `segment_type` | 建议 | `intro/mid/outro/external_query` |
| `source_dataset` | 建议 | 数据来源,例如 `fma_small` |
### 当前项目 manifest 文件
| 文件 | 含义 |
|---|---|
| `catalog.json` | 全部样本总表,尤其包含 reference |
| `train.json` | 训练 query 样本 |
| `val.json` | 验证集 query 样本 |
| `test.json` | 测试集 query 样本 |
---
## 3. 如果后面要保存到 pgvector,现在应该怎么处理
## 3.1 正确分层
**不要**
- 原始音频直接进 PostgreSQL 大表
- 训练前再从数据库反向拼装所有资产
**推荐**
| 内容 | 存储位置 |
|---|---|
| 原始音频 / 标准音频 | 文件系统 / NAS / 对象存储 |
| manifest / 结构化元数据 | PostgreSQL 普通表 |
| 向量 embedding | `pgvector` 列 |
| 检索索引参数 | PostgreSQL 索引 / 服务配置 |
---
## 3.2 pgvector 推荐数据模型
## 3.1 当前切片策略图
```mermaid
flowchart TD
A[songs] --> B[references]
A --> C[segments]
B --> D[reference_embeddings]
C --> E[query_embeddings]
```
当前仓库已经有对应模板:
A[3min 原始 mp3] --> B[训练 Dataset]
A --> C[建索引 / 检索]
A --> D[外部数据集 query 生成]
- [acr-engine/sql/pgvector_schema.sql](../acr-engine/sql/pgvector_schema.sql)
- [acr-engine/scripts/export_manifest_to_pgvector_json.py](../acr-engine/scripts/export_manifest_to_pgvector_json.py)
- [acr-engine/scripts/pgvector_bulk_load_template.py](../acr-engine/scripts/pgvector_bulk_load_template.py)
B --> B1[随机 offset]
B1 --> B2[取 5s clip]
### 表职责说明
| 表 | 存什么 |
|---|---|
| `songs` | 歌曲主实体 |
| `references` | reference 音频资产 |
| `segments` | query 片段 |
| `reference_embeddings` | reference 的 embedding |
| `query_embeddings` | query 的 embedding |
---
C --> C1[5s window]
C1 --> C2[2.5s stride]
C2 --> C3[50% overlap windows]
## 3.3 现在就应该为 pgvector 预留的字段
D --> D1[随机取 1 个 8s query]
```
如果你们后面一定要落 PostgreSQL,建议从今天开始在 manifest / 数据处理中保留这些字段:
## 3.2 直接回答“有没有重叠窗口”
| 字段 | 作用 |
| 链路 | 当前答案 |
|---|---|
| `song_id` | 主连接键 |
| `version_id` | 处理多版本/改编/短版 |
| `audio_path` / `audio_uri` | 回溯原始资产 |
| `duration` | 切片合法性校验 |
| `offset` | query 对应 reference 位置 |
| `type` | 训练角色 / 查询角色 |
| `segment_type` | intro/mid/outro/external |
| `source_dataset` | 数据来源治理 |
| `license` | 商业化合规 |
| `split` | train/val/test |
| `model_version` | 向量版本控制 |
| `data_version` | 数据快照版本 |
### 最重要的原则
| 训练 | **没有固定重叠滑窗集**,而是随机裁剪 |
| 检索 / reference index | **有**,默认 50% overlap |
| 开放数据 manifest 生成 | **没有**,默认每首歌只生成 1 个 query |
> `song_id` 要稳定,`version_id` 要可扩展,`audio_uri` 要可回溯,`model_version/data_version` 要可审计。
所以:
- 如果你担心 3 分钟内容只看一小段,担心是合理的;
- 当前训练覆盖靠多次 epoch 的随机采样累积,而不是一次性把整首歌切完;
- 如果后续要提高 recall/鲁棒性,可以继续加“多 query / overlap query manifest”这条增强线。
---
## 3.4 一个推荐的数据库入库流程
## 4. 如果有 BGM、音乐录音,应该怎么转成训练数据
## 4.1 推荐分工图
```mermaid
flowchart LR
A[音频目录] --> B[prepare-local]
B --> C[manifests]
C --> D[导出 pgvector JSON]
D --> E[批量导入 PostgreSQL]
E --> F[计算 embedding]
F --> G[写入 pgvector]
A[自有 BGM / 歌曲母带] --> B[reference]
A --> C[clean query]
A --> D[augmented query]
A --> E[confused / humming_like]
F[手机录音 / 环境录音] --> C
F --> E
```
推荐执行顺序:
## 4.2 转换规则表
1. 音频标准化
2. 生成 manifest
3. 用 manifest 导出结构化 JSON
4. 导入 PostgreSQL 元数据表
5. 批量计算 embedding
6. 写入 `pgvector`
7. 建 ANN 索引
| 原始素材 | 转成什么 | 标记建议 |
|---|---|---|
| 完整 BGM / 完整歌曲 | `reference` | `type=reference` |
| 原曲直接截 5s/8s | `clean` query | `type=clean` |
| 加噪/压缩/混响/EQ 后片段 | `augmented` query | `type=augmented` |
| 容易和别的歌混淆的片段 | 难例 query | `type=confused` |
| 哼唱感、旋律弱、手机录音风格 | 难例 query | `type=humming_like` |
---
## 4. 再回答你的问题 2:BGM、音乐录音怎么转成训练数据
## 4.1 场景 A:你有标准 BGM / 母带 / 完整成品
## 4.3 你们自己扩数据集时的最小规则
这是最适合做训练主集的情况。
1. **一首歌必须有稳定 `song_id`**
2. **完整版本或主版本优先做 `reference`**
3. **query 一定要能回溯到 reference 的时间位置**,因此最好保留 `offset`
4. **不同来源必须保留 `source_dataset`**
5. **训练、验证、测试必须保留 `split` 语义**,不要后面再靠文件夹猜。
### 转化规则
---
| 输入资产 | 转成什么 |
|---|---|
| 完整曲目 | `reference` |
| 从完整曲目切的 5s/8s 片段 | `clean` query |
| 加噪/压缩/混响后的派生片段 | `augmented` query |
| 易混淆段落 | `confused` query |
## 5. FMA / MTG / 自有数据的目录规范
### 最小流程
## 5.1 推荐目录图
```mermaid
flowchart TD
A[完整 BGM] --> B[标准化]
B --> C[reference]
B --> D[切 query 片段]
D --> E[clean]
D --> F[augmented]
D --> G[confused]
C --> H[manifest]
E --> H
F --> H
G --> H
```
### 标注原则
A[acr-engine/data/raw] --> B[fma_small_audio]
A --> C[mtg_jamendo_audio]
A --> D[my_bgm_audio]
- 一首歌一个稳定 `song_id`
- query 与 reference 共用这个 `song_id`
- 不同重编版不要强行共用同一个 `song_id`
- 如果是“同一歌不同版本”,建议:
- `song_id=主作品ID`
- `version_id=具体版本ID`
E[acr-engine/data/external_ingested] --> F[fma/manifests]
E --> G[mtg_jamendo/manifests]
E --> H[my_bgm/manifests]
---
## 4.2 场景 B:你有手机录音、环境录音、直播录屏
这类数据通常更适合作为 **query / hard case**,不适合作为主 reference。
### 推荐映射
| 原始录音类型 | 建议角色 |
|---|---|
| 手机外放录音 | `augmented``external_query` |
| 环境采集 | `augmented` |
| 直播录屏截取 | `external_query` |
| 强失真但可识别旋律 | `humming_like` |
### 转化步骤
1. 先找到它对应哪首 reference
2. 确认主要目标曲目是否单一
3. 裁成 5s / 8s 片段
4. 写入同一个 `song_id`
5.`type=augmented / humming_like / confused`
6.`segment_type=external_query`
示例:
```json
{
"song_id": "song_0001",
"audio_path": "queries/phone/song_0001_live_01.wav",
"duration": 8.0,
"type": "augmented",
"segment_type": "external_query",
"source_dataset": "phone_recording"
}
I[acr-engine/data/external_smoke] --> J[fma_*]
```
---
## 4.3 场景 C:你只有一堆历史文件夹,还没有精标注
这种情况建议先做 **弱监督标准化**,不要卡死在一开始就完美标注。
## 5.2 目录职责表
### 先做 3 步
1. **按文件夹/文件名生成候选 `song_id`**
2. **把完整长音频先当候选 reference**
3. **自动切若干 query 片段,后续再人工抽检修订**
### 推荐策略
| 阶段 | 做法 |
| 目录 | 作用 |
|---|---|
| 第 1 阶段 | 先把数据“可训练化” |
| 第 2 阶段 | 对高价值样本做人工修标 |
| 第 3 阶段 | 根据误识别样本补 hard cases |
| `acr-engine/data/raw/fma_small_audio/` | FMA 原始音频目录 |
| `acr-engine/data/raw/mtg_jamendo_audio/` | MTG-Jamendo 原始音频目录 |
| `acr-engine/data/external_ingested/<dataset>/manifests/` | 统一转换后的 manifest |
| `acr-engine/data/external_smoke/` | smoke 训练/索引/评测产物 |
---
## 5. 标签应该怎么设计
## 6. FMA 的具体说明
## 5.1 最少标签集
## 6.1 当前已验证的 FMA 事实
对于当前项目,建议先保留以下标签层级:
| 项 | 当前状态 |
|---|---|
| 数据源 | 用户指定 ModelScope FMA Small 链接 |
| 本地目录 | `acr-engine/data/raw/fma_small_audio` |
| 音频文件数 | `8000` |
| 可切 query 文件 | `7994` |
| 中位时长 | `29.977s` |
| 真实 smoke | **正在运行 / 已产生中间产物** |
| 维度 | 字段 | 例子 |
|---|---|---|
| 主标签 | `song_id` | `song_0001` |
| 版本标签 | `version_id` | `song_0001_mixA` |
| 角色标签 | `type` | `reference/clean/augmented/confused` |
| 结构标签 | `segment_type` | `intro/mid/outro/external_query` |
| 来源标签 | `source_dataset` | `fma_small` / `internal_bgm` |
| 合规标签 | `license` | `cc-by` / `internal` |
真实检查入口:
- [acr-engine/src/data/external_adapters.py](../acr-engine/src/data/external_adapters.py) `check-local-ready`
- [acr-engine/src/data/external_adapters.py](../acr-engine/src/data/external_adapters.py) `inspect-local`
---
## 5.2 什么情况下要拆 label
## 6.2 FMA cookbook
以下情况建议拆成不同 `song_id``version_id`
```bash
cd /workspace/acr-engine
| 情况 | 建议 |
|---|---|
| 主旋律相同但编曲大改 | 拆 `version_id` |
| 纯伴奏版 vs 演唱版差异极大 | 拆 `version_id` |
| mashup / 混剪 | 不进主训练集,单独 hard-case |
| 两首歌拼接 | 单独标记,避免污染主监督 |
/usr/local/miniconda3/bin/python src/data/external_adapters.py inspect-local \
fma data/raw/fma_small_audio --eval-ratio 0.2 --query-duration 8.0
---
/usr/local/miniconda3/bin/python src/data/external_adapters.py prepare-local \
fma data/raw/fma_small_audio --output-root data/external_ingested \
--eval-ratio 0.2 --query-duration 8.0
## 6. BGM / 录音转训练集的工业化处理建议
## 6.1 推荐目录结构
```text
project/
audio/
reference/
queries/
augmented/
manifests/
catalog.json
train.json
val.json
test.json
/usr/local/miniconda3/bin/python src/data/external_adapters.py validate-local \
fma data/external_ingested/fma/manifests
```
如果走当前仓库现成流程,也可以直接按:
- [acr-engine/data/raw/fma_small_audio/](../acr-engine/data/raw/fma_small_audio/)
- [acr-engine/data/raw/mtg_jamendo_audio/](../acr-engine/data/raw/mtg_jamendo_audio/)
然后通过:
如果只是验证全链路:
- [开放数据工作流](./open-dataset-workflow.md)
生成标准化输出。
```bash
/usr/local/miniconda3/bin/python src/data/external_adapters.py smoke-local \
fma data/raw/fma_small_audio --output-root data/external_smoke \
--eval-ratio 0.2 --query-duration 8.0 --train-epochs 1 --batch-size 2
```
---
## 6.2 推荐的数据处理 checklist
## 7. 当前脚本与职责索引
| 阶段 | 必做项 |
| 脚本/文件 | 作用 |
|---|---|
| 音频清洗 | 去坏文件、去空文件、统一采样率 |
| 资产标准化 | mono、16k、稳定命名 |
| reference 建立 | 每首歌至少 1 条 reference |
| query 生成 | 每首歌切多个位置片段 |
| 标签治理 | `song_id/version_id/type/source_dataset/license` |
| 数据拆分 | train/val/test 按歌或按 query 控制泄漏 |
| 评测 | 看 top1/topk、混淆矩阵、难例集 |
| 入库 | manifest -> JSON -> PostgreSQL/pgvector |
| [acr-engine/src/data/manifest_tools.py](../acr-engine/src/data/manifest_tools.py) | 音频目录 -> manifest |
| [acr-engine/src/data/external_adapters.py](../acr-engine/src/data/external_adapters.py) | inspect / prepare / validate / smoke 统一入口 |
| [acr-engine/src/data/dataset.py](../acr-engine/src/data/dataset.py) | 训练/测试数据集读取与随机裁剪 |
| [acr-engine/src/utils/audio.py](../acr-engine/src/utils/audio.py) | 通用音频处理与滑窗 |
| [acr-engine/src/engines/ecapa_embedder.py](../acr-engine/src/engines/ecapa_embedder.py) | embedding 抽取与 reference 滑窗索引 |
| [acr-engine/train.py](../acr-engine/train.py) | 训练主入口 |
| [acr-engine/evaluate.py](../acr-engine/evaluate.py) | 评测主入口 |
| [acr-engine/run_demo.py](../acr-engine/run_demo.py) | build-index / query demo |
| [acr-engine/scripts/export_manifest_to_pgvector_json.py](../acr-engine/scripts/export_manifest_to_pgvector_json.py) | manifest 导出为 pgvector-ready JSON |
| [acr-engine/scripts/pgvector_bulk_load_template.py](../acr-engine/scripts/pgvector_bulk_load_template.py) | PostgreSQL 批量导入模板 |
| [acr-engine/sql/pgvector_schema.sql](../acr-engine/sql/pgvector_schema.sql) | pgvector 表结构模板 |
---
## 7. 如果将来要把音频内容保存到 pgvector 检索系统,应该怎么转
## 7.1 不要直接存“音频”,要存“音频的表示”
## 8. GPU 是否会快很多
`pgvector` 适合存:
## 8.1 结论先说
- embedding 向量
- 指纹向量
- 结构化 metadata
**会。对于 FMA 这种 8000 首规模的真实数据,GPU 通常会比 CPU 快很多。**
不适合存:
原因:
- Mel 特征后面的 ECAPA 前向/反向传播主要是张量计算;
- 当前 `train.py` 已支持 `--device auto`,且 CUDA 路径已启用 mixed precision;
- 真实 FMA smoke 当前跑在 CPU,上千 batch 训练明显慢。
- 大体积原始 WAV 本体
- 大批量训练中间缓存
## 8.2 当前代码现状
### 建议保存的对象
| 对象 | 是否进 pgvector |
| 链路 | 当前状态 |
|---|---|
| 原始音频文件 | 否 |
| 标准化音频路径 | 是,存 URI/Path |
| reference embedding | 是 |
| query embedding | 可选 |
| song metadata | 是,普通表 |
| 标签/来源/license | 是,普通表 |
| `train.py` | 支持 `--device auto/cuda/cpu` |
| CUDA mixed precision | 已支持 |
| `smoke-local` | **当前硬编码 `--device cpu`** |
| `evaluate.py` | 当前 CLI 默认 `cpu` |
| `run_demo.py build-index` | 当前 smoke 里也走 `cpu` |
---
### 当前要注意的一点
## 7.2 建议的线上检索链路
`smoke-local` 虽然支持真实数据,但它现在为了稳妥把:
- 训练
- 建索引
- 评测
```mermaid
sequenceDiagram
participant U as User Query Audio
participant S as ACR Service
participant E as Embedder
participant P as pgvector
participant M as Metadata DB
U->>S: 上传5s/8s音频
S->>E: 提取128 Mel + embedding
E->>P: 向量检索TopK
P-->>S: 候选 song_id
S->>M: 读取歌曲元数据
M-->>S: title/artist/version/license
S-->>U: 返回识别结果
```
都固定到了 **CPU**。所以如果你想真正在本机上加速真实 FMA 训练,后续应该继续把 `smoke-local` 的 device 变成可配置项。
---
## 8. 你们现在就可以采用的落地规范
## 8.1 训练样本规范(建议定版)
### 输入规范
## 9. 如果后面要保存到 pgvector,现在应该怎么处理
- 单条 query:`5s``8s`
- 音乐主体明确
- 16k mono
- 每条 query 必须映射到一个 `song_id`
## 9.1 正确分层
### reference 规范
- 每首歌至少一个完整 reference
- reference 不用强切成很多碎片保存
- 以全曲或长片段为主
### 标签规范
- `song_id`:稳定主键
- `version_id`:可扩展
- `type`:固定枚举
- `source_dataset`:必保留
- `license`:商业化必须保留
---
## 8.2 面向 pgvector 的规范(建议定版)
| 内容 | 存储位置 |
|---|---|
| 原始音频 / 标准音频 | 文件系统 / NAS / 对象存储 |
| manifest / 元数据 | PostgreSQL 普通表 |
| 向量 embedding | `pgvector` 列 |
| 检索参数与版本 | PostgreSQL / 配置中心 |
- manifest 作为唯一数据交换层
- 音频在文件系统,对象路径写到 `audio_uri`
- embedding 单独表,带 `model_version`
- 每次重训后保留 `data_version`
- 检索结果必须能追溯到原始 reference
原则:
- **不要把原始 mp3 直接塞进 pgvector 表**
- 先标准化音频和 manifest;
- 再从 manifest 产出 embedding 与结构化记录。
---
## 9. 推荐执行路径
## 9.2 pgvector 推荐数据模型
如果你们后面要把 BGM、录音、开放数据一起纳入训练,我建议按这个顺序推进:
```mermaid
flowchart TD
A[songs] --> B[references]
A --> C[segments]
B --> D[reference_embeddings]
C --> E[query_embeddings]
```
1. 先把所有音频资产标准化为 `16k mono`
2. 给每首歌建立稳定 `song_id`
3. 完整曲目作为 reference
4. 自动切 5s/8s query
5. 增加 `augmented/confused/humming_like` 难例
6. 生成 manifests
7. 跑训练 / 评测 / 建索引
8. 从 manifest 导出 pgvector JSON
9. 再接 PostgreSQL + pgvector
当前仓库模板:
- [acr-engine/sql/pgvector_schema.sql](../acr-engine/sql/pgvector_schema.sql)
- [acr-engine/scripts/export_manifest_to_pgvector_json.py](../acr-engine/scripts/export_manifest_to_pgvector_json.py)
- [acr-engine/scripts/pgvector_bulk_load_template.py](../acr-engine/scripts/pgvector_bulk_load_template.py)
---
## 10. 直接给你的结论
## 9.3 从今天开始就该保留的字段
### 问题 1:当前训练数据和输入数据应该是什么样
| 字段 | 作用 |
|---|---|
| `song_id` | 主连接键 |
| `version_id` | 多版本扩展 |
| `audio_path` / `audio_uri` | 回溯音频资产 |
| `duration` | 切片合法性校验 |
| `offset` | query 对应 reference 的时间位置 |
| `type` | 训练/检索角色 |
| `segment_type` | intro/mid/outro/external |
| `source_dataset` | 数据来源治理 |
| `license` | 合规治理 |
| `split` | train/val/test |
| `model_version` | 向量版本控制 |
| `data_version` | 数据快照版本 |
答案:
---
- **输入不是单纯音频文件夹,而是“音频 + `song_id` 标签 + manifest”**
- **reference 是完整曲目或长片段,query 是 5s/8s 片段**
- **当前推荐统一成 16k mono,输入层采用 128 维 Mel 频谱**
- **如果未来要接 pgvector,现在就要保留 `song_id/version_id/audio_uri/source_dataset/license/model_version/data_version` 这些字段**
## 10. 当前一个真实注意点:5s / 8s 配置差异
### 问题 2:BGM、音乐录音怎么转成训练数据
当前仓库里有一个必须写进交接文档的现实问题:
答案:
| 项 | 当前事实 |
|---|---|
| `smoke-local` 命令 | 常用 `--query-duration 8.0` |
| 训练 dataset | 仍按 `segment_dur=5.0` 读取 |
| 现有 FMA smoke 报告 `config.json` | 出现过 `query_duration=5.0` 的旧产物 |
- **完整 BGM/母带 -> reference**
- **从 reference 切 5s/8s -> clean query**
- **加噪/混响/压缩 -> augmented query**
- **手机录音/环境录音/直播录屏 -> external query / hard case**
- **所有派生片段都必须回挂到统一 `song_id`**
解释:
- **manifest query 时长****训练 crop 时长****报告里记录的 query_duration** 当前不是完全同一个配置源;
- 现有 `fma_reports_smoke/config.json` 时间戳早于最新 manifests,属于需要继续治理的实验产物一致性问题;
- 因此后续继续做工业级化时,应该把 “manifest query 时长 / train clip 时长 / eval query 时长 / report metadata” 统一纳入一个显式配置结构。
---
## 11. 相关仓库内工具
## 11. 给你们后续自建数据集的落地建议
### 文档
- [数据规范](./dataset-spec.md)
- [开放数据工作流](./open-dataset-workflow.md)
- [数据来源与接入](./dataset-sources-and-licensing.md)
### 脚本 / SQL
- [acr-engine/scripts/export_manifest_to_pgvector_json.py](../acr-engine/scripts/export_manifest_to_pgvector_json.py)
- [acr-engine/scripts/pgvector_bulk_load_template.py](../acr-engine/scripts/pgvector_bulk_load_template.py)
- [acr-engine/sql/pgvector_schema.sql](../acr-engine/sql/pgvector_schema.sql)
1. **完整曲库先做 reference 池**
2. **从 reference 池切出 clean query 作为第一层训练集**
3. **再做 augmented / confused / humming_like 三类增强 query**
4. **固定一部分永不训练,只做 test set。**
5. **先把 manifest 字段做全,再谈 pgvector 和工业服务。**
## Sources
- This guide is grounded in the current repo’s manifest pipeline and pgvector schema templates:
- [acr-engine/scripts/export_manifest_to_pgvector_json.py](../acr-engine/scripts/export_manifest_to_pgvector_json.py)
- [acr-engine/sql/pgvector_schema.sql](../acr-engine/sql/pgvector_schema.sql)
- [数据规范](./dataset-spec.md)
- 当前代码事实来自 [acr-engine/src/data/dataset.py](../acr-engine/src/data/dataset.py), [acr-engine/src/data/manifest_tools.py](../acr-engine/src/data/manifest_tools.py), [acr-engine/src/data/external_adapters.py](../acr-engine/src/data/external_adapters.py), [acr-engine/src/utils/audio.py](../acr-engine/src/utils/audio.py), [acr-engine/src/engines/ecapa_embedder.py](../acr-engine/src/engines/ecapa_embedder.py), [acr-engine/train.py](../acr-engine/train.py)
......