Commit 6d4f8c1c 6d4f8c1c1ded3ba035a550151beac07f6d087304 by cnb.bofCdSsphPA

Reduce ACR handoff time with a single doc chain

Constraint: Preserve the current Phase-1 runner, PostgreSQL v2 contract, and live validation narrative while removing duplicate doc entrypoints.
Rejected: Keep multiple parallel handoff docs | They force new contributors to diff stale narratives before they can act.
Confidence: high
Scope-risk: narrow
Directive: Treat README -> start-here -> session-handoff as the only first-read path unless a newer handoff chain fully replaces it.
Tested: git diff --check on touched docs/script; rg for deleted-doc residual refs outside CHANGELOG; reran scripts/run_planner_validation_commands_live.py with executed_count=4 and all_passed=true
Not-tested: Markdown link rendering in external viewers
1 parent 8d6e4b29
1 #!/usr/bin/env bash
2 set -euo pipefail
3
4 ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
5 PYTHON_BIN="${PYTHON_BIN:-/usr/local/miniconda3/bin/python}"
6 DSN="${1:-${PG_DSN:-}}"
7 OUTPUT="${2:-$ROOT_DIR/data/pgvector_eval/music20/planner_validation_commands_runner_report.json}"
8
9 if [[ -z "$DSN" ]]; then
10 echo "usage: $0 <postgres-dsn> [output-json]" >&2
11 echo "or set PG_DSN before running this script" >&2
12 exit 1
13 fi
14
15 cd "$ROOT_DIR"
16 "$PYTHON_BIN" scripts/run_planner_validation_commands_live.py \
17 --dsn "$DSN" \
18 --output "$OUTPUT"
1 ## 2026-06-04 1 ## 2026-06-04
2 2
3 - 收敛文档入口链路,新增 `docs/start-here.md`,统一新同学接手路径为:`README -> start-here -> session-handoff`
4 - 重写 `docs/README.md`,按“接手 / 方案 / 实施 / 运行 / 角色”重组导航,降低首次阅读成本。
5 - 重构 `docs/session-handoff.md`,把最新 Phase-1 runner、稳定结论、blocker 与下一步动作收口到单页文档。
6 - 清理重复或过期文档:删除 `docs/acr-design.md``docs/open-dataset-plan.md``docs/external-manifest-template.md``docs/roadmap.md``docs/changelist-2026-06-02.md``docs/delivery-handoff-2026-06-02.md`
7 - 历史记录仍保留在 `docs/CHANGELOG.md`,当前有效入口以上述主链为准。
8
9 ## 2026-06-04
10
3 - 更新 `docs/README.md` 顶部为与 `session-handoff` 一致的“最短启动路径”,并再次用该入口命令重跑 `run_planner_validation_commands_live.py`,确认 fresh 结果仍为 `executed_count=4``all_passed=true` 11 - 更新 `docs/README.md` 顶部为与 `session-handoff` 一致的“最短启动路径”,并再次用该入口命令重跑 `run_planner_validation_commands_live.py`,确认 fresh 结果仍为 `executed_count=4``all_passed=true`
4 - 重构 `docs/session-handoff.md` 顶部为“首选启动流程(最短路径)”,直接给出 `run_planner_validation_commands_live.py` 的一条启动命令,以及基于 fresh runner 报告(`executed_count=4`, `all_passed=true`)的结果判断逻辑,减少下次 session 的恢复成本。 12 - 重构 `docs/session-handoff.md` 顶部为“首选启动流程(最短路径)”,直接给出 `run_planner_validation_commands_live.py` 的一条启动命令,以及基于 fresh runner 报告(`executed_count=4`, `all_passed=true`)的结果判断逻辑,减少下次 session 的恢复成本。
5 - 新增 `scripts/run_planner_validation_commands_live.py``planner_validation_commands_runner_report.json`,可直接读取 `phase1_extraction_plan_report.json` 中的 `validation_commands` 并批量执行;当前 4 条 entrypoints 已全部执行成功,`executed_count=4``all_passed=true` 13 - 新增 `scripts/run_planner_validation_commands_live.py``planner_validation_commands_runner_report.json`,可直接读取 `phase1_extraction_plan_report.json` 中的 `validation_commands` 并批量执行;当前 4 条 entrypoints 已全部执行成功,`executed_count=4``all_passed=true`
......
1 # ACR Docs Overview 1 # ACR Docs Overview
2 2
3 > 面向“版权保护 / 听歌识曲 / 版本归属”的音乐 ACR 文档入口。默认先看主路径,历史细节文档作为补充材料保留 3 > 面向“版权保护 / 听歌识曲 / 版本归属”的音乐 ACR 文档总入口
4 4
5 ## 最短启动路径(推荐) 5 ---
6
7 ## 0. 新同学先做什么
6 8
7 如果下次启动的目标是:**先判断当前 host 能不能继续推进 Phase-1**,不要先手工翻很多文档,先直接跑: 9 ### 先跑,不要先读一堆文档
8 10
9 ```bash 11 ```bash
10 cd /workspace/acr-engine 12 cd /workspace/acr-engine
11 /usr/local/miniconda3/bin/python scripts/run_planner_validation_commands_live.py --dsn 'postgres://d2:d2pass@127.0.0.1:5432/d2' --output data/pgvector_eval/music20/planner_validation_commands_runner_report.json 13 /usr/local/miniconda3/bin/python scripts/run_planner_validation_commands_live.py \
14 --dsn 'postgres://d2:d2pass@127.0.0.1:5432/d2' \
15 --output data/pgvector_eval/music20/planner_validation_commands_runner_report.json
12 ``` 16 ```
13 17
14 当前这条命令的 fresh evidence 已有: 18 也可以用包装脚本:`acr-engine/scripts/start_phase1_shortest_path.sh 'postgres://d2:d2pass@127.0.0.1:5432/d2'`
15 19
20 当前 fresh evidence:
16 - `executed_count = 4` 21 - `executed_count = 4`
17 - `all_passed = true` 22 - `all_passed = true`
18 23
19 它会一次性执行: 24 ### 再按这条阅读链路走
20 25 1. [start-here.md](./start-here.md)
21 1. `prereq_audit` 26 2. [session-handoff.md](./session-handoff.md)
22 2. `worker_contract_smoke` 27 3. [acr-architecture.md](./acr-architecture.md)
23 3. `semantic_vector_negative_matrix` 28 4. [postgresql-data-model.md](./postgresql-data-model.md)
24 4. `asset_level_upsert_validation` 29 5. [phase1-implementation-checklist.md](./phase1-implementation-checklist.md)
25
26 如果结果仍是:
27 - `downloads_root_exists = false`
28 - `ready_jobs = 0`
29 - exact = `failed/unreadable_audio_assets`
30 - semantic = `4/4 failed`
31 30
32 那么说明当前优先级应该是: 31 ---
33 32
34 1. 解决 `/workspace/downloads` 挂载 33 ## 1. 文档总导航
35 2. 安装语义模型 runtime 依赖
36 34
37 而不是继续怀疑 PostgreSQL contract。 35 ### A. 接手项目 / 恢复上下文
36 - [start-here.md](./start-here.md) — 新同学 10 分钟接手入口
37 - [session-handoff.md](./session-handoff.md) — 当前状态、阻塞、下一步
38 - [CHANGELOG.md](./CHANGELOG.md) — 变更记录
38 39
39 ## 一页结论 40 ### B. 系统方案 / 设计主线
41 - [acr-architecture.md](./acr-architecture.md) — 总体架构与分层
42 - [sota-evolution-guide.md](./sota-evolution-guide.md) — SOTA 演进路径
43 - [postgresql-data-model.md](./postgresql-data-model.md) — PostgreSQL 主数据/特征模型
44 - [production-encoder-freeze-and-embedding-strategy.md](./production-encoder-freeze-and-embedding-strategy.md) — encoder-only 冻结策略
40 45
41 当前项目已经从“原型是否能跑通”转向“**如何把 100w 音频 / 30w 歌曲做成可演进的版权检索系统**”。 46 ### C. 第一个阶段怎么落地
42 默认阅读顺序不再按“训练脚本 -> demo”,而按: 47 - [phase1-implementation-checklist.md](./phase1-implementation-checklist.md) — Phase-1 执行清单
48 - [model-feature-registry-bootstrap.md](./model-feature-registry-bootstrap.md) — model/feature/reference set 初始化
49 - [phase1-worker-contract.md](./phase1-worker-contract.md) — worker、job、失败语义合同
50 - [postgres_db_schema_samples.md](./postgres_db_schema_samples.md) — PostgreSQL 存储样例
43 51
44 1. **系统蓝图**:当前系统是什么、未来要演进成什么 52 ### D. 运行 / 服务 / 数据治理
45 2. **SOTA 演进**:Phase-1 不微调底座时怎么做,后面如何升级 53 - [runbook.md](./runbook.md) — 运维/运行手册
46 3. **PostgreSQL 数据模型**:资产、窗口、特征、索引、匹配结果如何落盘 54 - [service-api.md](./service-api.md) — 服务 API
47 4. **现有实现对照**:当前仓库代码和文档分别在哪 55 - [training-data-and-pgvector-guide.md](./training-data-and-pgvector-guide.md) — 训练/向量检索说明
56 - [open-dataset-workflow.md](./open-dataset-workflow.md) — 开源数据接入流程
48 57
49 --- 58 ---
50 59
51 ## 主阅读路径(推荐) 60 ## 2. 按角色阅读
52 61
53 ### 1. 管理 / 架构 / 跨团队负责人 62 ### 产品 / 业务 / 版权策略
54 1. [acr-architecture.md](./acr-architecture.md) 63 1. [start-here.md](./start-here.md)
55 2. [sota-evolution-guide.md](./sota-evolution-guide.md) 64 2. [acr-architecture.md](./acr-architecture.md)
56 3. [postgresql-data-model.md](./postgresql-data-model.md) 65 3. [project-responsibility-map.md](./project-responsibility-map.md)
57 4. [phase1-implementation-checklist.md](./phase1-implementation-checklist.md) 66 4. [business-export-cookbook.md](./business-export-cookbook.md)
58 5. [session-handoff.md](./session-handoff.md)
59 67
60 ### 2. 开发 / 数据 / 检索工程师 68 ### 数据 / 平台 / PostgreSQL
61 1. [postgresql-data-model.md](./postgresql-data-model.md) 69 1. [postgresql-data-model.md](./postgresql-data-model.md)
62 2. [phase1-implementation-checklist.md](./phase1-implementation-checklist.md) 70 2. [postgres_db_schema_samples.md](./postgres_db_schema_samples.md)
63 3. [model-feature-registry-bootstrap.md](./model-feature-registry-bootstrap.md)
64 4. [training-data-and-pgvector-guide.md](./training-data-and-pgvector-guide.md)
65 5. [acr-architecture.md](./acr-architecture.md)
66 6. [runbook.md](./runbook.md)
67
68 ### 3. 运维 / 平台 / 服务工程师
69 1. [acr-architecture.md](./acr-architecture.md)
70 2. [postgresql-data-model.md](./postgresql-data-model.md)
71 3. [phase1-implementation-checklist.md](./phase1-implementation-checklist.md)
72 4. [service-api.md](./service-api.md)
73 5. [runbook.md](./runbook.md)
74
75 ### 4. 模型 / 底座 / 研究工程师
76 1. [sota-research-2026.md](./sota-research-2026.md)
77 2. [sota-evolution-guide.md](./sota-evolution-guide.md)
78 3. [model-feature-registry-bootstrap.md](./model-feature-registry-bootstrap.md) 71 3. [model-feature-registry-bootstrap.md](./model-feature-registry-bootstrap.md)
79 4. [production-encoder-freeze-and-embedding-strategy.md](./production-encoder-freeze-and-embedding-strategy.md) 72 4. [runbook.md](./runbook.md)
80 5. [training-data-and-pgvector-guide.md](./training-data-and-pgvector-guide.md)
81
82 ---
83 73
84 ## 新的核心文档分工 74 ### 算法 / 检索 / 模型
75 1. [sota-evolution-guide.md](./sota-evolution-guide.md)
76 2. [production-encoder-freeze-and-embedding-strategy.md](./production-encoder-freeze-and-embedding-strategy.md)
77 3. [phase1-worker-contract.md](./phase1-worker-contract.md)
78 4. [sota-research-2026.md](./sota-research-2026.md)
85 79
86 | 文档 | 作用 | 适合谁先读 | 80 ### 开发 / 实施 / 交付
87 |---|---|---| 81 1. [phase1-implementation-checklist.md](./phase1-implementation-checklist.md)
88 | [acr-architecture.md](./acr-architecture.md) | 当前系统蓝图、角色分工、在线/离线链路 | 架构、开发、运维 | 82 2. [session-handoff.md](./session-handoff.md)
89 | [sota-evolution-guide.md](./sota-evolution-guide.md) | SOTA 演进路径、Phase-1 encoder-only 方案、后续升级路线 | 架构、模型、检索 | 83 3. [CHANGELOG.md](./CHANGELOG.md)
90 | [postgresql-data-model.md](./postgresql-data-model.md) | PostgreSQL 数据字典、DDL 设计意图、流程图、查询路径 | 数据、后端、检索、平台 | 84 4. [release-checklist.md](./release-checklist.md)
91 | [postgres_db_schema_samples.md](./postgres_db_schema_samples.md) | PostgreSQL 实际落库样例、live pgvector 测试链路、召回/混淆结果 | 数据、后端、检索、平台 |
92 | [phase1-implementation-checklist.md](./phase1-implementation-checklist.md) | Phase-1 落地 checklist,按阶段拆执行项 | 架构、开发、平台 |
93 | [model-feature-registry-bootstrap.md](./model-feature-registry-bootstrap.md) | 模型、feature set、reference set 初始化手册 | 模型、检索、数据 |
94 | [training-data-and-pgvector-guide.md](./training-data-and-pgvector-guide.md) | 当前训练/manifest/pgvector 原型链说明 | 开发、数据 |
95 | [session-handoff.md](./session-handoff.md) | 最新状态与续跑上下文 | 新 session 接手人 |
96 85
97 --- 86 ---
98 87
99 ## 当前实现与未来目标的关系 88 ## 3. 当前最重要的稳定结论
100 89
101 ```mermaid 90 - 目标场景不是普通歌曲推荐,而是 **版权保护 / 听歌识曲 / 版本归属**
102 flowchart LR 91 - Phase-1 先走 **encoder-only** 路线,不先微调底座。
103 A[当前实现\nChromaprint + ECAPA + Melody Rerank] --> B[Phase-1\nEncoder-only Foundation Backbone] 92 - exact lane:`Chromaprint`
104 B --> C[Phase-2\nVersion/Cover Lane + Better Aggregation] 93 - semantic baseline:`MERT-v1-95M`
105 C --> D[Phase-3\nIndustrial Retrieval + Reranker + Governance] 94 - semantic challenger:`MuQ`
95 - `ECAPA` 保留为 historical baseline,不再作为长期主底座。
96 - PostgreSQL 主链固定为:
97
98 ```text
99 canonical_song -> work -> recording -> recording_asset -> audio_window
106 ``` 100 ```
107 101
108 - **当前实现** 已验证基础链路可运行。 102 - 模型/特征主链固定为:
109 - **Phase-1** 目标是:不微调底座,直接上更强开源 encoder,并把 PostgreSQL 数据规范先落稳。 103
110 - **Phase-2** 目标是:增强 version / cover / hard-case 归属能力。 104 ```text
111 - **Phase-3** 目标是:多索引、多角色协作、数据治理、服务化上线。 105 model_registry -> feature_set_registry -> audio_embedding / audio_fingerprint -> retrieval_index_registry
106 ```
112 107
113 --- 108 ---
114 109
115 ## 现有实现入口 110 ## 4. 当前不要浪费时间的方向
116 111
117 ### 代码入口 112 - 不要回退到只用一个 `song_id` 的扁平结构。
118 - `acr-engine/src/engines/chromaprint_matcher.py` 113 - 不要把 embedding 存成固定列(如 `mert_embedding` / `muq_embedding`)。
119 - `acr-engine/src/engines/ecapa_embedder.py` 114 - 不要在 Phase-1 先讨论重新训练底座。
120 - `acr-engine/src/engines/hybrid_engine.py` 115 - 不要把当前阻塞误判成 PostgreSQL schema 问题;当前主要 blocker 是音频挂载与 runtime 依赖。
121 - `acr-engine/src/service/app.py`
122 - `acr-engine/sql/pgvector_schema.sql`(原型版)
123 - `acr-engine/sql/acr_pg_schema_v2.sql`(本轮新增的推荐版)
124
125 ### 历史/补充文档
126 - [sota-research-2026.md](./sota-research-2026.md)
127 - [production-encoder-freeze-and-embedding-strategy.md](./production-encoder-freeze-and-embedding-strategy.md)
128 - [project-responsibility-map.md](./project-responsibility-map.md)
129 - [industrialization-roadmap.md](./industrialization-roadmap.md)
130 116
131 --- 117 ---
132 118
133 ## 如何理解当前文档体系 119 ## 5. 补充但不建议作为第一入口
134
135 - **主文档**:优先保证“读完就知道怎么推进”
136 - **历史文档**:保留实验上下文、旧方案与补充解释
137 - **SQL 文件**:保证可以直接落地数据库原型
138 120
139 如果你只读 3 份: 121 以下文档保留用于专题补充,不建议新同学第一轮就读:
140 1. [acr-architecture.md](./acr-architecture.md) 122 - [dataset-spec.md](./dataset-spec.md)
141 2. [sota-evolution-guide.md](./sota-evolution-guide.md) 123 - [dataset-sources-and-licensing.md](./dataset-sources-and-licensing.md)
142 3. [postgresql-data-model.md](./postgresql-data-model.md) 124 - [references-and-sources.md](./references-and-sources.md)
125 - [current-capability-map.md](./current-capability-map.md)
126 - [industrialization-roadmap.md](./industrialization-roadmap.md)
127 - [industrial-benchmark-spec.md](./industrial-benchmark-spec.md)
128 - [benchmark-report-template.md](./benchmark-report-template.md)
129 - [model-card-template.md](./model-card-template.md)
130 - [report-layout.md](./report-layout.md)
......
1 # Audio Content Recognition (ACR) System — 听歌识曲引擎设计文档
2
3 > 版本: v1.0 | 更新: 2026-06-02 | 状态: Draft
4
5 ---
6
7 ## 目录
8
9 1. [概述与背景](#1-概述与背景)
10 2. [解决的问题](#2-解决的问题)
11 3. [技术原理](#3-技术原理)
12 4. [系统架构设计](#4-系统架构设计)
13 5. [数据准备与增强](#5-数据准备与增强)
14 6. [模型设计](#6-模型设计)
15 7. [训练细节](#7-训练细节)
16 8. [推理与匹配策略](#8-推理与匹配策略)
17 9. [使用方法](#9-使用方法)
18 10. [SOTA 调研与对比](#10-sota-调研与对比)
19 11. [Roadmap](#11-roadmap)
20 12. [Checklist](#12-checklist)
21 13. [Changelog](#13-changelog)
22 14. [Handoff 交付清单](#14-handoff-交付清单)
23 15. [参考与引用](#15-参考与引用)
24
25 ---
26
27 ## 1. 概述与背景
28
29 ### 1.1 项目目标
30
31 构建一个**音频内容识别(Audio Content Recognition, ACR)引擎**,能够根据一段**BGM(背景音乐)****哼唱(Humming)****录音片段**等音频输入,在歌曲库中快速准确地识别出对应的歌曲。核心能力对标 Shazam、SoundHound、网易云音乐"听歌识曲"等工业级产品。
32
33 ### 1.2 核心能力
34
35 | 能力 | 说明 |
36 |------|------|
37 | **BGM 识别** | 输入一段背景音乐,识别原曲 |
38 | **哼唱识别** (Query-by-Humming) | 输入用户哼唱的旋律,识别匹配的歌曲 |
39 | **录音片段识别** | 输入现场录音(含环境噪声),匹配库中歌曲 |
40 | **抗噪鲁棒性** | 在嘈杂环境、低码率、压缩失真下保持准确率 |
41 | **快速检索** | 亿级曲库下毫秒级响应 |
42 | **增量扩展** | 歌曲库可动态增加,无需全量重训练 |
43
44 ### 1.3 命名规范
45
46 | 术语 | 含义 |
47 |------|------|
48 | **Song / Track** | 库中原始歌曲 |
49 | **Reference** | 歌曲在库中的指纹/特征表示 |
50 | **Query** | 用户输入的待识别音频片段 |
51 | **Fingerprint** | 音频指纹(特征向量或哈希序列) |
52 | **Landmark** | 频谱图中的峰值点,用于构建指纹 |
53 | **Candidate** | 匹配候选歌曲列表 |
54 | **Segment** | 一个Query对应的录音片段或BGM片段 |
55
56 ---
57
58 ## 2. 解决的问题
59
60 ### 2.1 核心问题域
61
62 | 问题 | 描述 | 技术挑战 |
63 |------|------|---------|
64 | **音频退化** | Query 可能经过压缩(MP3/AAC)、降采样、远场录制 | 特征需对退化具有不变性 |
65 | **时间截断** | Query 仅为歌曲的中间某一小段(3-15s) | 指纹需支持局部匹配 |
66 | **哼唱偏差** | 用户哼唱的音高、节奏、音色与原曲不同 | 需旋律归一化与音高轮廓匹配 |
67 | **环境噪声** | 录音含背景人声、街道噪声、混响 | 特征提取需有一定抗噪性 |
68 | **速度变化** | Query 播放速度可能快于或慢于原曲(±15%) | 指纹对时间伸缩不敏感 |
69 | **键位偏移** | Query 的调性可能不同于原曲(哼唱场景常见) | 需相对旋律表示而非绝对音高 |
70 | **曲库规模** | 曲库可能达到百万至亿级 | 检索必须依赖哈希/近似最近邻索引 |
71
72 ### 2.2 与现有方案对比
73
74 | 维度 | 传统指纹法 (Shazam-like) | 深度学习 embedding 法 (本方案) | 混合方案 |
75 |------|------------------------|-------------------------------|---------|
76 | 哼唱识别 | 不支持 | 支持(训练时加入哼唱数据) | 支持 |
77 | 抗噪性 | 中等 | 高(数据增强可大幅提升) | 高 |
78 | 检索速度 | 极快(哈希表) | 快(ANN 索引) | 极快 |
79 | 曲库扩展 | 容易 | 容易(增量索引) | 容易 |
80 | 硬件要求 | 低 | 中等(需 GPU 训练) | 中等 |
81 | 调音适应性 | 差 | 好(对比学习可学到不变性) | 好 |
82 | 时间碎片适应性 | 好 | 好(滑窗机制) | 好 |
83
84 ---
85
86 ## 3. 技术原理
87
88 ### 3.1 音频信号处理基础
89
90 #### 3.1.1 短时傅里叶变换 (STFT)
91
92 音频信号经 STFT 转化为时频表示:
93
94 ```
95 X(t, f) = Σₙ x[n]·w[n-t]·e^{-j2πfn/N}
96 ```
97
98 其中 `w[n]` 为窗函数(Hamming/Hann),典型窗长 1024-4096 samples,步长 256-512 samples。
99
100 #### 3.1.2 Mel 频谱
101
102 将 STFT 的线性频率通过 Mel 滤波器组映射到 Mel 刻度:
103
104 ```
105 Mel(f) = 2595 · log₁₀(1 + f/700)
106 ```
107
108 得到 Mel 频谱图作为模型的 2D 输入特征。Mel 频谱更符合人耳听觉感知,且对高频噪声有一定抑制作用。
109
110 #### 3.1.3 色谱图 (Chroma Feature)
111
112 色谱图将频谱能量投影到 12 个半音(C, C#, D, ..., B),对音色和音高变化具有不变性,特别适合哼唱识别。
113
114 ```
115 Chroma(t, p) = Σ_{f ∈ pitches_in_class_p} |X(t, f)|²
116 ```
117
118 #### 3.1.4 谱峰提取 (Spectral Peaks)
119
120 在频谱图中提取能量峰值点(landmarks),每个 landmark 定义为 `(t, f, energy)`。Shazam 算法基于这些 landmark 构建哈希指纹。
121
122 #### 3.1.5 哼唱旋律轮廓 (Melody Contour)
123
124 对于哼唱输入,使用基频(F0)估计提取旋律轮廓线。常用算法:
125
126 - **PYIN** (Probabilistic YIN):基于 YIN 算法的概率改进版
127 - **CREPE**:基于深度学习的基频估计
128 - **TorchCREPE**:CREPE 的 PyTorch 实现
129
130 旋律轮廓经归一化后得到相对音高序列:`ΔP(t) = P(t) - P(t-1)`
131
132 ### 3.2 音频指纹技术
133
134 #### 3.2.1 传统指纹法 (Shazam Algorithm)
135
136 1. 对音频做 STFT 得到频谱图
137 2. 在时频平面提取能量峰值(landmarks)
138 3. 对每对 landmark `(f₁, t₁)``(f₂, t₂)` 构建哈希对:
139 ```
140 hash = (f₁, f₂, Δt) → (t₁, song_id)
141 ```
142 4. 查询时计算 Query 的 landmarks 和 hashes
143 5. 在哈希表中找到匹配的歌曲候选
144 6. 对候选做时间偏移直方图投票,选出最高票歌曲
145
146 **优点**:极快、曲库可极大、无需训练
147 **缺点**:对哼唱、速度变化、调性变化不适应
148
149 #### 3.2.2 深度嵌入法 (Deep Embedding) —— 本方案核心
150
151 将音频片段映射到一个固定维度的嵌入向量(如 256 维),在嵌入空间中相似歌曲的 Query 和 Reference 距离接近。
152
153 **对比学习目标 (Contrastive Learning)**:
154
155 ```
156 Loss = -log( exp(sim(q, p)/τ) / Σ_{n=1}^{N} exp(sim(q, n)/τ) )
157 ```
158
159 其中 `sim(q, p)` 是 Query 与正样本 Reference 的余弦相似度,`τ` 是温度系数。
160
161 **核心优势**:
162
163 - 通过对比学习,嵌入对音色、噪声、速度变化、调性变化具有不变性
164 - 哼唱 Query 可与原曲 Reference 在嵌入空间中对齐
165 - 支持增量曲库(新歌只需过一次模型生成嵌入)
166
167 ### 3.3 检索策略
168
169 #### 3.3.1 精确检索 (Brute Force)
170
171 当库规模 < 10K 时,直接计算 Query 嵌入与所有 Reference 嵌入的余弦相似度。
172
173 ```
174 score_i = cosine(query_emb, ref_emb_i)
175 result = argmax(score_i)
176 ```
177
178 #### 3.3.2 近似最近邻检索 (ANN)
179
180 当库规模 > 10K 时,使用近似最近邻索引:
181
182 | 算法 | 特点 | 适用场景 |
183 |------|------|---------|
184 | **IVF** | 倒排文件索引,训练聚类中心 | 百万级 |
185 | **IVF + PQ** | 乘积量化压缩向量 | 千万级 |
186 | **HNSW** | 分层导航小世界图 | 亿级,高精度 |
187 | **DiskANN** | 基于 SSD 的图索引 | 十亿级 |
188
189 推荐使用 **Faiss** 库实现 ANN 检索。
190
191 #### 3.3.3 级联检索策略
192
193 ```
194 Query → 粗筛 (ANN, top-K) → 精排 (余弦相似度) → 时间对齐验证 → Top-1
195 ```
196
197 - 粗筛:ANN 检索 Top-50/100 候选
198 - 精排:计算精确余弦相似度,取 Top-10
199 - 时间对齐验证:对 Top-10 候选做频谱图谱峰对齐验证,确认时序一致性
200
201 ---
202
203 ## 4. 系统架构设计
204
205 ### 4.1 整体架构
206
207 ```
208 ┌─────────────────────────────────────────────────────────────┐
209 │ API Gateway │
210 └─────────────────────┬───────────────────────────────────────┘
211
212 ┌─────────────┼─────────────┐
213 ▼ ▼ ▼
214 ┌───────────────┐ ┌───────┐ ┌───────────────┐
215 │ Audio Ingest │ │ Search│ │ Admin Service │
216 │ (Ingestion) │ │ (QPS) │ │ (管理) │
217 └───────┬───────┘ └───┬───┘ └───────┬───────┘
218 │ │ │
219 ▼ ▼ ▼
220 ┌─────────────────────────────────────────────────────────────┐
221 │ Core Engine Layer │
222 │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌───────────────┐ │
223 │ │ Pre- │ │ Feature │ │ Embedder│ │ Matcher │ │
224 │ │ processor│ │ Extractor│ │ (Model) │ │ (Searcher) │ │
225 │ └──────────┘ └──────────┘ └──────────┘ └───────────────┘ │
226 └─────────────────────────────────────────────────────────────┘
227 │ │ │
228 ▼ ▼ ▼
229 ┌─────────────────────────────────────────────────────────────┐
230 │ Storage Layer │
231 │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌───────────────┐ │
232 │ │ Raw Audio│ │ Finger- │ │ Embedding│ │ Song Metadata │ │
233 │ │ (S3/OSS) │ │ print DB │ │ Index │ │ (PostgreSQL) │ │
234 │ └──────────┘ └──────────┘ └──────────┘ └───────────────┘ │
235 └─────────────────────────────────────────────────────────────┘
236 ```
237
238 ### 4.2 模块详细设计
239
240 #### 4.2.1 Audio Preprocessor
241
242 ```
243 输入: raw_audio_bytes / file_path / stream
244 功能:
245 1. 格式解码 (MP3, WAV, FLAC, AAC, OGG, M4A)
246 2. 重采样到统一采样率 (16kHz 或 22.05kHz)
247 3. 通道合并 (多声道 → 单声道)
248 4. 归一化 (RMS 归一化到目标响度)
249 5. 分帧/滑窗 (非重叠或非重叠滑窗,每帧 3-15s)
250 输出: numpy.ndarray, shape=(samples,)
251 ```
252
253 #### 4.2.2 Feature Extractor
254
255 ```
256 支持多种特征提取策略,可通过配置切换:
257
258 模式 A: Spectrogram + Log-Mel
259 - STFT: window=2048, hop=512, window_fn=hann
260 - Mel filters: 64/128 bins, fmin=0, fmax=8000
261 - Log(spectrogram + 1e-6)
262
263 模式 B: Chroma CQT
264 - Constant Q Transform, 12 bins/octave
265 - 适用于哼唱场景
266
267 模式 C: Landmark + Hash (Shazam 兼容)
268 - Peak extraction (2D local maxima)
269 - Target zone pairing for hash construction
270
271 模式 D: Raw Waveform (可选)
272 - 直接输入原始波形给 1D CNN
273 ```
274
275 #### 4.2.3 Embedder (深度模型)
276
277 参见第 [6 节](#6-模型设计)。
278
279 #### 4.2.4 Matcher / Searcher
280
281 ```
282 输入: query_embedding (dim=256)
283 流程:
284 1. ANN 检索: Faiss IVF+HNSW, top_k=100
285 2. 精排: 计算精确余弦相似度, top_k=10
286 3. 时间对齐验证 (可选):
287 - 对 Top-10 候选提取谱峰
288 - 计算 Query 与候选的时间偏移直方图
289 - 确认存在一致性偏移峰值
290 4. 置信度校准: 计算相似度分布 z-score
291 5. 输出: sorted_results[ {song_id, score, match_type} ]
292 ```
293
294 ### 4.3 API 设计
295
296 ```protobuf
297 // Recognize — 识别音频
298 service ACRService {
299 // 输入音频返回 Top-N 匹配歌曲
300 rpc Recognize(RecognizeRequest) returns (RecognizeResponse);
301
302 // 批量入库
303 rpc IngestSong(IngestSongRequest) returns (IngestSongResponse);
304
305 // 删除歌曲
306 rpc DeleteSong(DeleteSongRequest) returns (DeleteSongResponse);
307
308 // 健康检查
309 rpc HealthCheck(Empty) returns (HealthCheckResponse);
310 }
311
312 message RecognizeRequest {
313 bytes audio_data = 1; // 音频数据
314 string audio_format = 2; // wav, mp3, ogg
315 float duration_sec = 3; // 实际有效时长 (若未知留空)
316 RecognizeMode mode = 4; // AUTO, BGM, HUMMING, RECORDING
317 int32 top_n = 5; // 返回 Top-N (默认 5)
318 }
319
320 enum RecognizeMode {
321 AUTO = 0; // 自动检测模式
322 BGM = 1; // 纯 BGM 片段
323 HUMMING = 2; // 哼唱
324 RECORDING = 3; // 现场录音
325 }
326
327 message RecognizeResponse {
328 repeated Candidate candidates = 1;
329 float processing_time_ms = 2;
330 }
331
332 message Candidate {
333 string song_id = 1;
334 string title = 2;
335 string artist = 3;
336 float confidence = 4;
337 float matched_begin_sec = 5; // 匹配起始时间
338 float matched_end_sec = 6; // 匹配结束时间
339 string match_type = 7; // bgm / humming / recording
340 }
341 ```
342
343 ### 4.4 存储设计
344
345 | 数据 | 存储引擎 | 说明 |
346 |------|---------|------|
347 | 原始音频 | S3/MinIO/OSS | 对象存储,按 song_id 组织 |
348 | 歌曲元数据 | PostgreSQL | 标题、歌手、专辑、时长、标签 |
349 | 嵌入向量 | Faiss Index (IVF+HNSW) | 256 维浮点向量 |
350 | 指纹哈希 | Redis / LevelDB | Shazam 兼容指纹键值对 |
351 | 频谱缓存 | Redis / S3 | 预处理后的频谱图缓存 |
352 | 操作日志 | ClickHouse / ELK | 查询日志、性能监控 |
353
354 ### 4.5 部署架构
355
356 ```
357 ┌──────────┐
358 │ LB/Nginx│
359 └────┬─────┘
360
361 ┌──────────┼──────────┐
362 ▼ ▼ ▼
363 ┌──────────┐ ┌──────────┐ ┌──────────┐
364 │ API │ │ API │ │ API │
365 │ Server 1 │ │ Server 2 │ │ Server N │
366 └────┬─────┘ └────┬─────┘ └────┬─────┘
367 │ │ │
368 ▼ ▼ ▼
369 ┌─────────────────────────────────────┐
370 │ Faiss Index (Sharded) │
371 │ GPU/CPU Hybrid │
372 ├─────────────────────────────────────┤
373 │ PostgreSQL (RDS) │
374 ├─────────────────────────────────────┤
375 │ S3-compatible Object Store │
376 └─────────────────────────────────────┘
377 ```
378
379 ---
380
381 ## 5. 数据准备与增强
382
383 ### 5.1 数据来源
384
385 #### 5.1.1 歌曲原始数据
386
387 | 来源 | 类型 | 规模目标 | 许可注意 |
388 |------|------|---------|---------|
389 | FMA (Free Music Archive) | 开源音乐 | 100K+ 曲 | CC 授权 |
390 | MUSDB18 | 多轨分离数据集 | 150 曲 | 研究用途 |
391 | GTZAN | 流派分类 | 1000 曲 | 研究用途 |
392 | 自行爬取/合作 | 商业音乐 | 1M+ 曲 | 需版权授权 |
393 | 自建录制 | 哼唱/翻唱 | 10K+ 段 | 内部数据 |
394
395 #### 5.1.2 训练数据构造
396
397 每个歌曲在库中作为 **Reference**,需为每个 Reference 构造多样化的 **Query** 用于训练。
398
399 **基础构造逻辑**:
400 ```
401 song.mp3 → 随机裁剪片段 (3-15s) → 数据增强 → Query
402 song.mp3 → 全曲 → Reference
403 ```
404
405 #### 5.1.3 哼唱数据
406
407 哼唱数据可通过以下方式获取:
408
409 1. **MIR-QBSH Corpus**:专业哼唱数据集
410 2. **自建哼唱数据集**:组织用户录制哼唱旋律
411 3. **MIDI 转音频模拟**:将 MIDI 文件通过合成器转为模拟哼唱
412 4. **M-Humming**:自行标注的哼唱数据集
413
414 哼唱数据格式要求:
415 ```
416 {
417 "song_id": "song_001",
418 "humming_id": "hum_001",
419 "audio_path": "/data/humming/song_001_hum_001.wav",
420 "original_song_path": "/data/songs/song_001.mp3",
421 "humming_duration_sec": 8.5,
422 "relative_pitch_shift": -2, // 相对原曲的半音偏移
423 "tempo_ratio": 1.1 // 相对原曲的速度倍率
424 }
425 ```
426
427 ### 5.2 数据增强策略
428
429 增强的目的是**使模型学到对真实世界干扰的不变性**。
430
431 #### 5.2.1 基础增强
432
433 | 增强操作 | 参数范围 | 目标 |
434 |---------|---------|------|
435 | Additive White Gaussian Noise (AWGN) | SNR: 5-30dB | 环境噪声 |
436 | Pink Noise / Brown Noise | SNR: 10-25dB | 自然噪声 |
437 | Band-stop Filtering | 随机 0.5-2kHz 陷波 | 频率缺失 |
438 | Low-pass / High-pass | 截止频率 1-8kHz | 频带限制 |
439 | Time Stretch | 0.85-1.15x | 速度变化 |
440 | Pitch Shift | -6 ~ +6 semitones | 调性变化(哼唱) |
441 | Equalizer Randomization | 随机增益 ±6dB | 音色变化 |
442 | Resampling | 8-44.1kHz | 采样率退化 |
443 | MP3 Compression | 32-128kbps | 压缩失真 |
444 | Reverb | 房间混响模拟 | 远场录音 |
445 | Volume Jitter | -12 ~ 0 dB | 响度变化 |
446 | Time Masking (SpecAug) | 遮罩 10-50 帧 | 局部缺失 |
447 | Frequency Masking (SpecAug) | 遮罩 8-16 bins | 局部频率缺失 |
448
449 #### 5.2.2 哼唱专用增强
450
451 | 增强操作 | 说明 |
452 |---------|------|
453 | F0 抖动 | 基频随机扰动 ±5% |
454 | 节奏抖动 | 节拍随机扰动 ±10% |
455 | 添加呼吸声 | 插入随机位置的呼吸音 |
456 | 音色变异 | 使用不同的合成器/人声 |
457 | 单音偏差 | 部分音符替换为邻音(模拟跑调) |
458
459 #### 5.2.3 数据增强管线
460
461 ```
462 原始音频 (16kHz mono)
463
464 ├─→ [随机裁剪] 3-15s 随机片段
465 ├─→ [重采样] 8kHz / 16kHz / 22.05kHz / 44.1kHz 随机选择
466 ├─→ [响度归一化] RMS = target_loudness
467 ├─→ [噪声叠加] AWGN / Pink / 背景音 按概率叠加
468 ├─→ [滤波器] 低通/高通/带阻/均衡器 随机选择
469 ├─→ [时域变化] Time Stretch ±15%
470 ├─→ [频域变化] Pitch Shift ±6 semitones
471 ├─→ [压缩模拟] MP3 编码再解码 (64-128kpbs)
472 ├─→ [混响] 小型/中型/大型房间混响
473 ├─→ [SpecAug] Time & Frequency Masking
474 └─→ [特征提取] Mel Spectrogram / Chroma / Raw
475 └─→ [输出] 增强后的特征张量
476 ```
477
478 实现:`torchaudio` / `audiomentations` / `librosa` 组合管线。
479
480 ### 5.3 数据格式与存储
481
482 **训练数据格式**:
483
484 ```
485 /data/
486 ├── songs/ # 原始歌曲
487 │ ├── song_001.mp3
488 │ └── ...
489 ├── references/ # 参考指纹/嵌入
490 │ ├── ref_001.npy # 歌曲全曲或多段嵌入
491 │ └── ...
492 ├── queries/ # 查询片段 (训练数据)
493 │ ├── train/
494 │ │ ├── song_001_seg_001.wav
495 │ │ └── ...
496 │ └── val/
497 │ └── ...
498 ├── metadata.csv # 歌曲元数据
499 └── train_pairs.csv # (query_path, song_id, type)
500 ```
501
502 **metadata.csv 格式**:
503 ```csv
504 song_id,title,artist,album,duration_sec,genre,language
505 song_001,Song Title,Artist Name,Album Name,240.5,Pop,en
506 ```
507
508 **train_pairs.csv 格式**:
509 ```csv
510 query_path,song_id,query_type,augmentation_params
511 queries/train/song_001_seg_001.wav,song_001,bgm,"{snr:15, pitch_shift:0}"
512 queries/train/song_001_hum_001.wav,song_001,humming,"{pitch_shift:-2, tempo:1.1}"
513 ```
514
515 ### 5.4 数据流水线性能要求
516
517 | 指标 | 目标 |
518 |------|------|
519 | 增强吞吐 | ≥ 200 样本/秒/GPU |
520 | 预处理缓存 | 频谱图存入 LMDB/RecordIO |
521 | 训练样本总量 | ≥ 5M Query-Reference 对 |
522 | 参考曲库 | ≥ 100K 歌曲(测试阶段) |
523
524 ---
525
526 ## 6. 模型设计
527
528 ### 6.1 模型架构选型
529
530 本方案采用 **双塔结构 (Two-Tower / Siamese Network)**,两塔共享权重。
531
532 ```
533 ┌─────────────────────────────────────┐
534 │ Similarity Score │
535 │ cosine(q_emb, r_emb) │
536 └──────────────────┬──────────────────┘
537
538 ┌────────────────────┴────────────────────┐
539 ▼ ▼
540 ┌───────────────┐ ┌───────────────┐
541 │ Query │ │ Reference │
542 │ Encoder │ │ Encoder │
543 │ (shared) │ │ (shared) │
544 └───────┬───────┘ └───────┬───────┘
545 │ │
546 ┌───────┴───────┐ ┌───────┴───────┐
547 │ Input 1 │ │ Input 2 │
548 │ (Mel Spec) │ │ (Mel Spec) │
549 └───────────────┘ └───────────────┘
550 ```
551
552 ### 6.2 候选骨干网络
553
554 #### 方案 A: CNN-Transformer (推荐)
555
556 ```
557 Input: Mel-Spectrogram (1, 128, T) — 单通道, 128 Mel bins, 变长时间
558
559 ├─ Conv2D(1→32, 3×3, stride=1) + BN + ReLU
560 ├─ Conv2D(32→64, 3×3, stride=2) + BN + ReLU
561 ├─ Conv2D(64→128, 3×3, stride=2) + BN + ReLU
562 ├─ Conv2D(128→256, 3×3, stride=2) + BN + ReLU
563
564 ├─ Reshape: (batch, T', 256)
565 ├─ Transformer Encoder × 4 (d_model=256, nhead=8, dim_feedforward=1024)
566 ├─ [CLS] Token Pooling / Global Average Pooling
567 ├─ Projection: 256 → 256 (Linear + LayerNorm)
568 └─ L2 Normalize → Embedding (256-dim)
569 ```
570
571 **总参数量**: ~8-12M | **MACs**: ~2-5G per 5s audio
572
573 #### 方案 B: EfficientNet-ish (轻量级)
574
575 ```
576 Input: Mel-Spectrogram (3, 128, T) — 拼接近邻帧伪 RGB
577
578 ├─ MBConv blocks (EfficientNet-B0 like)
579 │ - Stem: Conv 3×3, 32ch
580 │ - Stage 1-7: MBConv with SE
581 │ - Head: Conv 1×1, 1280ch
582 ├─ Global Average Pooling
583 ├─ Dropout 0.2
584 ├─ Projection: 1280 → 256
585 └─ L2 Normalize → Embedding (256-dim)
586 ```
587
588 **总参数量**: ~5-8M | **MACs**: ~1-3G per 5s audio
589
590 #### 方案 C: 纯 Attention (AST-like)
591
592 ```
593 Input: Mel-Spectrogram (1, 128, T)
594
595 ├─ Patch Embedding (16×16 patches) + Position Embedding
596 ├─ Transformer Encoder × 12 (d_model=768, nhead=12)
597 ├─ [CLS] Token
598 ├─ Projection: 768 → 256
599 └─ L2 Normalize → Embedding (256-dim)
600 ```
601
602 **总参数量**: ~80-90M | **MACs**: ~5-15G per 5s audio
603 **优势**: 准确率最高 | **劣势**: 推理速度较慢
604
605 #### 推荐: 方案 A (CNN-Transformer) 作为主选,方案 B 作为备选轻量级。
606
607 ### 6.3 训练损失函数
608
609 #### 6.3.1 主损失: SupConLoss (Supervised Contrastive Loss)
610
611 ```
612 对于 batch 中每个 anchor a,
613 正样本集 P(a) = 所有与 a 同歌曲的样本
614 负样本集 N(a) = 与 a 不同歌曲的样本
615
616 L_supcon = Σ_a [ -1/|P(a)| · Σ_{p∈P(a)} log( exp(sim(z_a, z_p)/τ) / Σ_{n∈N(a)∪P(a)} exp(sim(z_a, z_n)/τ) ) ]
617 ```
618
619 #### 6.3.2 辅助损失: ArcFace / CosFace (可选)
620
621 当曲库有固定类别标签时,可附加分类损失:
622
623 ```
624 L_arcface = -log( exp(s·cos(θ_y + m)) / (exp(s·cos(θ_y + m)) + Σ_j≠y exp(s·cos θ_j)) )
625 ```
626
627 #### 6.3.3 总损失
628
629 ```
630 L_total = λ₁ · L_supcon + λ₂ · L_arcface + λ₃ · L_triplet
631 ```
632
633 推荐 `λ₁=1.0, λ₂=0.3, λ₃=0.1`。
634
635 ### 6.4 哼唱识别专用模块
636
637 对于哼唱输入,在主干网络外增加一个**旋律编码分支**:
638
639 ```
640 哼唱音频
641
642 ├─ F0 估计 (CREPE / PYIN) → F0 轮廓 (hourglass-shaped)
643 ├─ Chroma CQT → 12-bin 色谱图
644
645 ├─ 可选融合策略:
646 │ A) 早融合 (Early Fusion): Mel + Chroma 通道拼接 → 同一网络
647 │ B) 晚融合 (Late Fusion): Mel 分支 + Chroma 分支分别编码 → 拼接嵌入
648 │ C) 分叉网络 (Forked): 共享底层特征层,高层分支出 Mel 和 Chroma 特征
649
650 └─ → 256-dim Embedding
651 ```
652
653 推荐使用 **晚融合** 方案,在训练时将 Mel 特征和 Chroma 特征分别经过共享底层后拼接,再投影到 256 维。
654
655 ### 6.5 多尺度匹配策略
656
657 由于 Query 长度可变(3-15s),使用多尺度滑窗:
658
659 ```
660 Reference (全曲 3min):
661 [───── Window 1 (5s) ─────]
662 [───── Window 2 (5s) ─────]
663 [───── Window 3 (5s) ─────]
664 ... (stride = 2.5s)
665
666 每个窗口 → Reference Embedding Matrix: (num_windows, 256)
667
668 Query (5s) → Query Embedding: (1, 256)
669
670 匹配: max_sim = max(sim(query_emb, ref_window_emb_i) for i in windows)
671 ```
672
673 ---
674
675 ## 7. 训练细节
676
677 ### 7.1 实验环境
678
679 | 配置 | 规格 |
680 |------|------|
681 | GPU | NVIDIA A100 (80GB) × 4 |
682 | CPU | AMD EPYC 64C / Intel Xeon 48C |
683 | RAM | 512 GB |
684 | 存储 | NVMe SSD 4TB |
685 | 框架 | PyTorch 2.x + Lightning / FSDP |
686 | 加速 | Flash Attention, torch.compile |
687 | 监控 | W&B / MLflow |
688
689 ### 7.2 超参数
690
691 | 参数 | 值 | 备注 |
692 |------|-----|------|
693 | Audio SR | 16000 Hz | 统一采样率 |
694 | Frame Size | 1024 (~64ms) | STFT 窗长 |
695 | Hop Size | 512 (~32ms) | STFT 步长 |
696 | Mel Bins | 128 | 梅尔滤波器数量 |
697 | Max Duration | 10s | 训练时音频截断长度 |
698 | Embedding Dim | 256 | 嵌入向量维度 |
699 | Batch Size | 512-1024 | 分布式训练 |
700 | Optimizer | AdamW | β=(0.9, 0.999) |
701 | Learning Rate | 3e-4 | Cosine Annealing |
702 | Weight Decay | 0.01 | L2 正则化 |
703 | Warmup Steps | 5000 | Linear Warmup |
704 | Epochs | 100-200 | Early Stopping |
705 | Temperature τ | 0.07 | 对比学习温度 |
706 | Label Smoothing | 0.1 | 防止过拟合 |
707 | Gradient Clipping | 1.0 | Max norm |
708 | Mixed Precision | bfloat16 | 加速训练 |
709 | Scheduler | Cosine Decay | Warm restarts |
710
711 ### 7.3 训练流程
712
713 ```
714 Step 1: 数据准备
715 1. 收集原始歌曲 → 16kHz mono → 存储为 WAV
716 2. 随机裁剪 + 数据增强 → 生成 Query/Reference 对
717 3. 提取 Mel 频谱 → 存储为 .npy (可选在线提取)
718 4. 分割 train/val/test (80/10/10)
719
720 Step 2: 预训练 (可选)
721 1. 在大规模无标签数据上使用 SimCLR / BYOL 做自监督预训练
722 2. 或使用公开预训练权重 (AudioMAE, CLAIR, CLAP)
723
724 Step 3: 有监督对比学习训练
725 1. 加载预训练权重或从头初始化
726 2. 每个 batch: 从 B 个歌曲各取 K 个片段 → B×K 样本
727 3. 计算 SupConLoss + 辅助损失
728 4. 每 N 步验证集评估 Recall@1, Recall@5
729 5. 最佳模型保存 checkpoint
730
731 Step 4: 哼唱微调 (可选阶段)
732 1. 使用哼唱数据 + 数据增强对模型做有监督微调
733 2. 固定部分底层参数,微调顶层和高层 Transformer
734 3. Learning rate: 1e-5 (较小)
735
736 Step 5: 索引构建
737 1. 对所有歌曲提取 Reference Embeddings
738 2. 使用 Faiss 构建 IVF+HNSW 索引
739 3. 评估索引准确率与检索速度
740 ```
741
742 ### 7.4 评估指标
743
744 | 指标 | 说明 | 目标值 |
745 |------|------|--------|
746 | **Recall@1** | Top-1 准确率 | ≥ 90% (BGM), ≥ 80% (哼唱) |
747 | **Recall@5** | Top-5 召回率 | ≥ 95% (BGM), ≥ 90% (哼唱) |
748 | **MRR** | Mean Reciprocal Rank | ≥ 0.9 |
749 | **mAP** | Mean Average Precision | ≥ 0.88 |
750 | **QPS** | Queries Per Second (单 GPU) | ≥ 500 |
751 | **P50 Latency** | 中位数响应时间 | ≤ 100ms |
752 | **P99 Latency** | 99% 响应时间 | ≤ 500ms |
753 | **Index Build** | 10万曲库索引构建时间 | ≤ 30min |
754 | **Index Size** | 索引占用内存 | ≤ 2GB (100K 曲) |
755
756 ### 7.5 消融实验设计
757
758 | 实验 | 变量 | 预期验证目标 |
759 |------|------|------------|
760 | 特征对比 | Mel vs Chroma vs CQT vs Raw | 最优输入特征 |
761 | 骨干对比 | CNN vs CNN-Tfm vs AST vs EffNet | 最优架构 |
762 | 嵌入维度 | 64 vs 128 vs 256 vs 512 | 性能-容量平衡 |
763 | 对比损失 | SupCon vs Triplet vs NT-Xent vs ArcFace | 最优损失函数 |
764 | 温度系数 | τ=0.05, 0.07, 0.1, 0.2 | 最优温度 |
765 | 数据增强 | 无增强 vs 基础 vs 全部 | 增强贡献度 |
766 | 哼唱策略 | 早融合 vs 晚融合 vs 分叉 | 最优融合方式 |
767 | 曲库抗噪 | 添加噪声曲库干扰 | 抗干扰能力 |
768
769 ### 7.6 分布式训练策略
770
771 ```bash
772 # 使用 PyTorch DDP / FSDP
773 torchrun --nproc_per_node=8 train.py \
774 --batch_size 64 \
775 --model cnn_transformer \
776 --embed_dim 256 \
777 --max_duration 10 \
778 --lr 3e-4 \
779 --epochs 200 \
780 --warmup 5000 \
781 --fp16 \
782 --dataset_path /data/acr \
783 --save_interval 10
784 ```
785
786 ---
787
788 ## 8. 推理与匹配策略
789
790 ### 8.1 推理流程
791
792 ```
793 用户输入 Query (任意时长)
794
795 ├─ 1. 音频预处理 (重采样+通道合并+归一化)
796 ├─ 2. 滑窗切片 (5s 窗口, 2.5s 步长)
797 │ 如果 Query < 3s: 补充静音到 3s → 拒绝/低置信度
798 │ 如果 3s ≤ Query ≤ 15s: 单窗口或最多 2 窗口
799 │ 如果 Query > 15s: 多窗口 5s 滑窗
800
801 ├─ 3. 特征提取 (Mel Spectrogram)
802
803 ├─ 4. 嵌入推理 (模型 forward) → query_embs: (num_windows, 256)
804
805 ├─ 5. 候选检索
806 │ a) 对每个窗口嵌入做 ANN 检索 → Top-50 × num_windows
807 │ b) 合并候选并去重 → Top-100
808 │ c) 精排: 精确相似度计算 → Top-10
809
810 ├─ 6. (Optional) 时间对齐验证
811 │ - 对 Top-10 候选提取频谱图峰值
812 │ - 计算与 Query 的时间偏移直方图
813 │ - 一致性验证 → 更新置信度
814
815 ├─ 7. 置信度校准
816 │ - 计算 query_embs 与各候选嵌入的最大相似度
817 │ - Z-score 标准化: score_z = (score - μ_candidates) / σ_candidates
818 │ - 应用阈值 (score_z > 2.0 或直接阈值 > 0.7)
819
820 └─ 8. 输出结果
821 ```
822
823 ### 8.2 流式推理 (Streaming)
824
825 对于长音频流 (如直播、电台监听),支持流式识别:
826
827 ```
828 音频流输入 (16kHz, 实时)
829
830 ├─ 环形缓冲区 (Ring Buffer, 15s 容量)
831 ├─ 每积累 2.5s 新音频 → 触发一次识别
832 ├─ 取: 缓冲区末尾 5s 作为当前 Query
833 ├─ 嵌入 → ANN 检索 (使用缓存减少重复计算)
834 ├─ 结果缓存与平滑: 连续 N 次命中同一歌曲 → 确认输出
835 └─ 重复
836 ```
837
838 ### 8.3 拒绝策略 (Rejection)
839
840 当 Query 不在库中时,应可靠地拒绝(低误报率):
841
842 | 策略 | 实现 |
843 |------|------|
844 | 绝对阈值 | max_score < 0.5 → 拒绝 |
845 | 相对阈值 | max_score - second_score < 0.15 → 拒绝 |
846 | 分布阈值 | max_score < μ_candidates + 2·σ_candidates → 拒绝 |
847 | 混合策略 | 三者加权组合 |
848 | 验证分支 | 增加"非歌分类"头,判断输入是否为有效音乐 |
849
850 ### 8.4 缓存策略
851
852 ```
853 Query → 特征 Cache (LRU):
854 - Key: audio_hash (MD5 of first 2s)
855 - Value: (query_embedding, timestamp)
856 - TTL: 30 分钟
857 - Max size: 10K entries
858
859 热门歌曲 Cache:
860 - 频繁命中的歌曲嵌入常驻内存
861 - 使用 LFU eviction
862 ```
863
864 ---
865
866 ## 9. 使用方法
867
868 ### 9.1 安装
869
870 ```bash
871 # 克隆仓库
872 git clone <repo-url> && cd acr-engine
873
874 # 创建环境
875 conda create -n acr python=3.11 && conda activate acr
876
877 # 安装依赖
878 pip install -r requirements.txt
879
880 # 可选: GPU 版 Faiss
881 pip install faiss-gpu
882
883 # 安装 torchaudio (含 CUDA)
884 pip install torch torchaudio --index-url https://download.pytorch.org/whl/cu121
885 ```
886
887 ### 9.2 数据导入
888
889 ```bash
890 # 批量导入歌曲到曲库
891 python scripts/ingest.py \
892 --input /data/music_library/ \
893 --format mp3 \
894 --recursive \
895 --metadata metadata.csv
896
897 # 导入单曲
898 python scripts/ingest.py --input song.mp3 --song-id "song_001"
899 ```
900
901 ### 9.3 训练
902
903 ```bash
904 # 完整训练流程
905 python train.py \
906 --config configs/default.yaml \
907 --data /data/acr/ \
908 --output /models/acr/ \
909 --epochs 200 \
910 --gpus 4
911
912 # 继续训练 (从 checkpoint)
913 python train.py --resume /models/acr/checkpoint_epoch_100.ckpt
914
915 # 哼唱微调
916 python train.py \
917 --config configs/humming_finetune.yaml \
918 --resume /models/acr/pretrained.ckpt \
919 --data /data/humming/
920 ```
921
922 ### 9.4 索引构建
923
924 ```bash
925 # 构建 Faiss 索引
926 python scripts/build_index.py \
927 --model /models/acr/best.ckpt \
928 --songs /data/songs/ \
929 --output /index/acr_index.faiss \
930 --index-type "IVF4096,PQ16" \
931 --gpu
932 ```
933
934 ### 9.5 API 服务启动
935
936 ```bash
937 # 启动 REST API (HTTP)
938 python serve.py \
939 --model /models/acr/best.ckpt \
940 --index /index/acr_index.faiss \
941 --port 8088 \
942 --workers 4
943
944 # 启动 gRPC 服务 (推荐生产使用)
945 python serve.py --mode grpc --port 50051
946
947 # 使用 Docker Compose
948 docker-compose up -d
949 ```
950
951 ### 9.6 客户端调用
952
953 **Python 客户端**:
954 ```python
955 import requests
956
957 url = "http://localhost:8088/v1/recognize"
958 files = {"audio": open("query.wav", "rb")}
959 params = {"top_n": 5, "mode": "auto"}
960
961 resp = requests.post(url, files=files, params=params)
962 print(resp.json())
963 # {
964 # "candidates": [
965 # {"song_id": "...", "title": "...", "artist": "...",
966 # "confidence": 0.92, "match_type": "bgm"}
967 # ],
968 # "processing_time_ms": 45.2
969 # }
970 ```
971
972 **命令行**:
973 ```bash
974 # 识别本地音频文件
975 python cli.py recognize --audio query.mp3 --top-n 5
976
977 # 录音识别 (麦克风)
978 python cli.py recognize --mic --duration 5
979
980 # 流式识别 (文件)
981 python cli.py stream --input live_audio.wav --interval 2.5
982 ```
983
984 ### 9.7 SDK 集成
985
986 ```
987 Python: pip install acr-sdk
988 Go: go get github.com/xxx/acr-go
989 Rust: cargo add acr-rs
990 Java: Maven: com.xxx:acr-client:1.0
991 ```
992
993 **Python SDK 使用示例**:
994 ```python
995 from acr_sdk import ACRClient
996
997 client = ACRClient(endpoint="localhost:50051", mode="grpc")
998
999 # 识别
1000 result = client.recognize("query.wav", mode="humming")
1001 print(f"Song: {result.title}, Confidence: {result.confidence:.2f}")
1002
1003 # 批量入库
1004 client.ingest("/data/new_songs/")
1005
1006 # 删除
1007 client.delete_song("song_001")
1008 ```
1009
1010 ---
1011
1012 ## 10. SOTA 调研与对比
1013
1014 ### 10.1 学术界 SOTA
1015
1016 | 方法 | 年份 | 核心思想 | 哼唱支持 | Recall@1 (BGM) | Recall@1 (Humming) |
1017 |------|------|---------|---------|---------------|-------------------|
1018 | **Shazam** (Wang) | 2003 | 谱峰哈希指纹 | ❌ | ~85%* | N/A |
1019 | **SoundHound** | 2006 | 旋律轮廓+指纹 | ✅ | ~88%* | ~75%* |
1020 | **Dejavu** | 2015 | Shazam 开源实现 | ❌ | ~82% | N/A |
1021 | **MatchNet** | 2018 | Siamese CNN + Triplet | ❌ | ~90% | N/A |
1022 | **CLAP** (LAION) | 2023 | 对比语言-音频预训练 | ❌ | ~87% | N/A |
1023 | **AudioMAE** | 2023 | 掩码自编码器预训练 | ❌ | ~85% | N/A |
1024 | **Contrastive Audio** (Oord) | 2018 | CPC + 对比学习 | ❌ | ~86% | N/A |
1025 | **HummingBird** | 2024 | Chroma + 对比学习 | ✅ | ~91% | ~82% |
1026 | **Singer** (ByteDance) | 2024 | 多任务对比学习 | ✅ | ~93% | ~85% |
1027 | **Ours** | 2026 | CNN-Tfm + SupCon + 哼唱融合 | ✅ | ≥92% | ≥83% |
1028
1029 *\* 为公开披露的估计值,非学术基准*
1030
1031 ### 10.2 工业界产品对比
1032
1033 | 产品 | 识别速度 | BGM 准确率 | 哼唱准确率 | 曲库规模 | 延迟 |
1034 |------|---------|-----------|-----------|---------|------|
1035 | **Shazam (Apple)** | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ❌ | 亿级 | ~2s |
1036 | **SoundHound** | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | 千万级 | ~3s |
1037 | **网易云音乐** | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | 千万级 | ~2s |
1038 | **QQ音乐** | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ | 千万级 | ~2s |
1039 | **Google Sound Search** | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ | 亿级 | ~3s |
1040 | **Ours** | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | 百万级(初期) | ≤0.5s |
1041
1042 ### 10.3 本方案的边际优势 (vs 现有方案)
1043
1044 1. **哼唱融合训练**:通过专用的哼唱增强和对比学习策略,哼唱识别准确率显著优于纯指纹方案
1045 2. **混合架构**:CNN-Transformer 比纯 CNN 有更好的序列建模能力,比纯 Transformer 更高效
1046 3. **级联检索**:ANN 粗筛 + 精确重排 + 时间对齐验证,兼顾速度与精度
1047 4. **数据增强系统**:全面的增强策略涵盖 BGM、哼唱、录音三大场景
1048 5. **可扩展性**:增量索引支持动态歌库,无需重训练
1049
1050 ---
1051
1052 ## 11. Roadmap
1053
1054 ### 11.1 阶段规划
1055
1056 ```
1057 Phase 0: 基础建设 (Week 1-2)
1058 ├── 环境搭建与依赖配置
1059 ├── 数据探索与预处理 pipeline
1060 ├── 基础特征提取模块 (Mel, Chroma, CQT)
1061 ├── 数据增强模块 (audiomentations pipeline)
1062 └── 基线模型: Shazam 式指纹法 (Dejavu fork)
1063
1064 Phase 1: V1 MVP (Week 3-6)
1065 ├── CNN-Transformer 模型实现
1066 ├── SupConLoss 训练管线
1067 ├── 基础数据收集 (FMA + MUSDB18 + GTZAN)
1068 ├── 训练 100K Query-Reference 对的模型
1069 ├── Faiss 索引构建 Pipeline
1070 ├── REST API + gRPC 服务
1071 └── 本地 CLI 工具
1072
1073 Phase 2: 哼唱支持 (Week 7-10)
1074 ├── 哼唱数据收集 (内部录制 + MIR-QBSH)
1075 ├── 哼唱增强 Pipeline
1076 ├── Chroma 分支 + 旋律轮廓编码
1077 ├── 哼唱-原曲对比学习微调
1078 ├── 哼唱专用评估集构建
1079 └── 哼唱模式 API 支持
1080
1081 Phase 3: 生产优化 (Week 11-14)
1082 ├── 模型量化 (INT8 / FP16)
1083 ├── ONNX Runtime / TensorRT 部署
1084 ├── 级联检索策略优化
1085 ├── 缓存系统实现 (LRU + LFU)
1086 ├── 流式识别支持
1087 ├── 负载测试与性能调优
1088 ├── Docker + K8s 部署配置
1089 └── CI/CD Pipeline
1090
1091 Phase 4: 进阶能力 (Week 15-20)
1092 ├── 分布式曲库 (Index Sharding)
1093 ├── 多语言歌曲支持
1094 ├── 歌曲翻唱/Remix 识别
1095 ├── 歌曲定位 (识别到歌曲中具体位置)
1096 ├── 歌词时间轴对齐
1097 ├── Web dashboard (曲库管理 + 监控)
1098 ├── 增量学习 (在线模型更新)
1099 └── 边缘端部署 (移动端/嵌入式)
1100
1101 Phase 5: 持续迭代 (Week 21+)
1102 ├── 用户反馈环路
1103 ├── A/B 测试框架
1104 ├── 模型持续训练 (CT)
1105 ├── 数据处理自动化
1106 ├── 新 SOTA 方法集成
1107 ├── 商业合作接入
1108 └── 合规与版权管理
1109 ```
1110
1111 ### 11.2 里程碑
1112
1113 | 里程碑 | 时间 | 交付物 | 验收标准 |
1114 |--------|------|--------|---------|
1115 | M0: 基础准备 | Week 2 | 开发环境、数据管线 | 增强管线吞吐 ≥ 200/秒 |
1116 | M1: V1 MVP | Week 6 | 可运行的识别引擎 | Recall@1 ≥ 85% (BGM) |
1117 | M2: 哼唱上线 | Week 10 | 哼唱识别能力 | Recall@1 ≥ 75% (Humming) |
1118 | M3: 生产就绪 | Week 14 | 高性能服务 | P50 ≤ 100ms, QPS ≥ 500 |
1119 | M4: 进阶能力 | Week 20 | 企业级平台 | 多场景覆盖, 曲库 100 万+ |
1120
1121 ---
1122
1123 ## 12. Checklist
1124
1125 ### 12.1 数据准备
1126
1127 - [ ] 确定数据来源并获取授权
1128 - [ ] 下载并组织原始歌曲库 (≥ 100K songs)
1129 - [ ] 统一转为 16kHz mono WAV 格式
1130 - [ ] 实现数据增强管线 (全部增强策略)
1131 - [ ] 生成训练 Query-Reference 对 (≥ 5M pairs)
1132 - [ ] 构建哼唱数据集 (≥ 10K 段)
1133 - [ ] 分割 train/val/test (80/10/10)
1134 - [ ] 验证数据分布多样性 (流派、语言、年代)
1135 - [ ] 实现数据加载器 (支持在线增强)
1136 - [ ] 数据版本控制 (DVC / HuggingFace Datasets)
1137
1138 ### 12.2 模型开发
1139
1140 - [ ] 实现基础 CNN-Transformer 骨干
1141 - [ ] 实现训练循环 (SupConLoss + 辅助损失)
1142 - [ ] 实现哼唱分支 (Chroma + F0 融合)
1143 - [ ] 实现多尺度滑窗匹配
1144 - [ ] 实现基准模型 (Shazam + Dejavu)
1145 - [ ] 实现对比实验框架
1146 - [ ] 超参数搜索 (学习率、温度、嵌入维度等)
1147 - [ ] 训练收敛验证
1148
1149 ### 12.3 索引与检索
1150
1151 - [ ] 实现 Faiss 索引构建管线
1152 - [ ] 实现 ANN + 精确重排的级联检索
1153 - [ ] 实现时间对齐验证
1154 - [ ] 实现置信度校准与拒绝策略
1155 - [ ] 索引增量更新 (增删歌曲)
1156 - [ ] 索引持久化与加载优化
1157
1158 ### 12.4 服务部署
1159
1160 - [ ] 实现 REST API (FastAPI / Flask)
1161 - [ ] 实现 gRPC API
1162 - [ ] 模型导出 (ONNX / TorchScript)
1163 - [ ] 模型量化 (INT8 / FP16)
1164 - [ ] 实现流式识别
1165 - [ ] 实现缓存系统
1166 - [ ] 负载测试 & 性能调优
1167 - [ ] Docker 镜像构建
1168 - [ ] Docker Compose / K8s 配置文件
1169 - [ ] 监控与告警 (Prometheus + Grafana)
1170 - [ ] 日志系统 (结构化日志)
1171 - [ ] CI/CD Pipeline
1172
1173 ### 12.5 质量保障
1174
1175 - [ ] 单元测试 (核心模块覆盖率 ≥ 80%)
1176 - [ ] 集成测试 (端到端识别流程)
1177 - [ ] 性能基准测试 (延迟、吞吐、内存)
1178 - [ ] 鲁棒性测试 (噪声、压缩、哼唱变化)
1179 - [ ] 回归测试 (每次模型更新)
1180 - [ ] 评估集标注与维护
1181 - [ ] 安全审计 (注入、权限、数据泄露)
1182
1183 ### 12.6 文档与交付
1184
1185 - [x] 设计文档 (本文件)
1186 - [ ] API 文档 (Swagger / OpenAPI)
1187 - [ ] 部署文档 (Docker, K8s, 环境要求)
1188 - [ ] 用户手册 (SDK 使用指南)
1189 - [ ] 训练文档 (数据、超参数、实验记录)
1190 - [ ] 运维手册 (监控、日志、故障排查)
1191 - [ ] 演示 / demos
1192
1193 ---
1194
1195 ## 13. Changelog
1196
1197 ### [v1.0] — 2026-06-02
1198
1199 #### Added
1200 - 初始设计文档创建
1201 - 完整架构设计 (双塔对比学习 + Faiss 检索)
1202 - 数据增强策略 (12+ 种操作)
1203 - 哼唱识别模块设计
1204 - SOTA 调研对比表
1205 - Roadmap (Phase 0-5)
1206 - Checklist (6 大模块)
1207
1208 ### [Planned] — v1.1
1209
1210 #### Planned
1211 - 实验基准数据
1212 - 训练收敛曲线与指标
1213 - 模型参数量与推理延迟详细报告
1214 - 消融实验结果
1215 - 用户反馈收集结果
1216
1217 ### [Planned] — v2.0
1218
1219 #### Planned
1220 - 分布式曲库方案
1221 - 边缘端部署方案
1222 - 在线学习模块
1223 - 歌词时间轴识别
1224
1225 ---
1226
1227 ## 14. Handoff 交付清单
1228
1229 ### 14.1 交付物概要
1230
1231 | 类别 | 交付物 | 责任人 | 验收人 |
1232 |------|--------|-------|--------|
1233 | 设计 | ACR 设计文档 (本文) | 架构师 | 技术负责人 |
1234 | 数据 | 训练数据集 & 评估集 | 数据工程师 | 算法工程师 |
1235 | 代码 | 模型训练代码 | 算法工程师 | 架构师 |
1236 | 代码 | API 服务 & CLI 工具 | 后端工程师 | 架构师 |
1237 | 部署 | Docker / K8s 配置 | DevOps | 运维 |
1238 | 文档 | API 文档 & 用户手册 | 技术写作 | 产品经理 |
1239 | 测试 | 测试报告 & 性能基准 | QA | 技术负责人 |
1240
1241 ### 14.2 验收标准
1242
1243 ```
1244 [ ] 端到端识别流程通过: 输入音频 → 输出正确歌曲
1245 [ ] Recall@1 ≥ 90% (BGM 场景, 干净音频)
1246 [ ] Recall@1 ≥ 80% (哼唱场景)
1247 [ ] P50 延迟 ≤ 100ms (单机器, 百万曲库)
1248 [ ] P99 延迟 ≤ 500ms
1249 [ ] 并发 QPS ≥ 100 (单机器, 4 CPU cores)
1250 [ ] 曲库增量更新 ≤ 1s/曲
1251 [ ] 所有单元测试通过 (覆盖率 ≥ 80%)
1252 [ ] 安全审计无高危漏洞
1253 [ ] 文档完整性审查通过
1254 ```
1255
1256 ### 14.3 风险与缓解
1257
1258 | 风险 | 概率 | 影响 | 缓解措施 |
1259 |------|------|-----|---------|
1260 | 版权音乐数据获取困难 | 高 | 高 | 优先使用开源数据集; 探索合成数据 |
1261 | 哼唱数据不足 | 中 | 高 | 合成哼唱 + Mid-to-Audio 生成 |
1262 | 噪声下准确率不达标 | 中 | 中 | 更激进的数据增强; 模型集成 |
1263 | 大曲库检索延迟 | 低 | 中 | 多级索引; GPU 加速检索 |
1264 | 模型过拟合 | 低 | 中 | 强正则化; 大规模数据; Dropout |
1265 | 哼唱与 BGM 模式冲突 | 中 | 中 | 双模式 / 级联识别 |
1266
1267 ### 14.4 移交步骤
1268
1269 1. **代码移交**:所有代码推送到主仓库,PR 审核通过,CI 绿色
1270 2. **模型移交**:最佳模型 checkpoint + 导出 ONNX/TorchScript
1271 3. **数据移交**:训练数据、评估数据、数据管线代码
1272 4. **索引移交**:Faiss 索引文件 + 元数据
1273 5. **部署移交**:Docker 镜像推送到 Registry,K8s 配置文件就绪
1274 6. **文档移交**:所有文档整理到 `/docs/` 目录
1275 7. **演示移交**:运行 demo 脚本,展示端到端识别流程
1276 8. **培训移交**:对运维/开发人员进行 2 小时技术培训
1277
1278 ---
1279
1280 ## 15. 参考与引用
1281
1282 ### 15.1 学术论文
1283
1284 | 主题 | 论文 | 年份 |
1285 |------|------|------|
1286 | 音频指纹 (Shazam) | Wang, A. "An Industrial-Strength Audio Search Algorithm" | 2003 |
1287 | 对比学习 (SimCLR) | Chen et al. "A Simple Framework for Contrastive Learning" | 2020 |
1288 | 监督对比学习 | Khosla et al. "Supervised Contrastive Learning" | 2020 |
1289 | 频谱图增强 (SpecAug) | Park et al. "SpecAugment: A Simple Augmentation Method" | 2019 |
1290 | 语音谱图 Transformer | Gong et al. "AST: Audio Spectrogram Transformer" | 2021 |
1291 | CLAP | Wu et al. "Large-scale Contrastive Language-Audio Pretraining" | 2023 |
1292 | AudioMAE | Huang et al. "Masked Autoencoders that Listen" | 2023 |
1293 | CPC for Audio | Oord et al. "Representation Learning with Contrastive Predictive Coding" | 2018 |
1294 | 哼唱识别综述 | Sharma et al. "Query-by-Humming: A Survey" | 2023 |
1295 | CREPE | Kim et al. "CREPE: A Convolutional Representation for Pitch Estimation" | 2018 |
1296
1297 ### 15.2 开源项目
1298
1299 | 项目 | 说明 | 链接 |
1300 |------|------|------|
1301 | **Dejavu** | Shazam 指纹法 Python 实现 | https://github.com/worldveil/dejavu |
1302 | **Faiss** | 向量相似度搜索库 (Meta) | https://github.com/facebookresearch/faiss |
1303 | **CLAP** | 对比语言-音频预训练 (LAION) | https://github.com/LAION-AI/CLAP |
1304 | **torchaudio** | PyTorch 音频工具包 | https://github.com/pytorch/audio |
1305 | **audiomentations** | 音频数据增强库 | https://github.com/iver56/audiomentations |
1306 | **librosa** | 音频分析库 | https://github.com/librosa/librosa |
1307 | **marsyas** | 音频处理框架 | https://github.com/marsyas/marsyas |
1308 | **Essentia** | 音频分析库 (UPF) | https://github.com/MTG/essentia |
1309
1310 ### 15.3 数据集
1311
1312 | 数据集 | 规模 | 用途 | 许可 |
1313 |--------|------|------|------|
1314 | FMA (Free Music Archive) | 106,574 曲 | 基础歌曲库 | CC |
1315 | MUSDB18 | 150 曲 (多轨) | 音源分离 | 研究 |
1316 | GTZAN | 1,000 曲 | 流派分类 (基线) | 研究 |
1317 | MIR-QBSH | ~4,800 哼唱 | 哼唱识别 | 研究 |
1318 | Medley-solos-DB | 21,574 片段 | 音色分析 | CC |
1319 | AudioSet (Google) | 2M+ 片段 | 预训练/多任务 | YouTube |
1320
1321 ---
1322
1323 ## 附录 A: 快速开始 Demo
1324
1325 ```python
1326 #!/usr/bin/env python
1327 """ACR Engine Quick Demo"""
1328
1329 from acr_engine import ACRPipeline
1330
1331 # 初始化
1332 pipeline = ACRPipeline(
1333 model_path="models/acr/best.ckpt",
1334 index_path="index/acr_index.faiss",
1335 mode="auto"
1336 )
1337
1338 # 批量导入
1339 pipeline.ingest_directory("data/samples/")
1340
1341 # 识别
1342 for query_path in ["query_bgm.wav", "query_hum.wav", "query_noisy.wav"]:
1343 result = pipeline.recognize(query_path)
1344 print(f"{query_path}: {result.title} ({result.confidence:.2%})")
1345 ```
1346
1347 ## 附录 B: 配置模板 (configs/default.yaml)
1348
1349 ```yaml
1350 model:
1351 name: cnn_transformer
1352 embed_dim: 256
1353 backbone:
1354 cnn_channels: [32, 64, 128, 256]
1355 transformer_layers: 4
1356 nhead: 8
1357 dim_feedforward: 1024
1358 humming_branch:
1359 enabled: true
1360 fusion: late
1361 chroma_bins: 12
1362 f0_embed_dim: 64
1363
1364 data:
1365 sample_rate: 16000
1366 n_mels: 128
1367 n_fft: 1024
1368 hop_length: 512
1369 max_duration: 10.0
1370 min_duration: 3.0
1371 window_size: 5.0
1372 window_stride: 2.5
1373
1374 augmentation:
1375 noise:
1376 enable: true
1377 snr_range: [5, 30]
1378 pitch_shift:
1379 enable: true
1380 semitones_range: [-6, 6]
1381 time_stretch:
1382 enable: true
1383 rate_range: [0.85, 1.15]
1384 mp3_compression:
1385 enable: true
1386 bitrate_range: [32, 128]
1387 spec_augment:
1388 enable: true
1389 time_mask_max: 50
1390 freq_mask_max: 16
1391
1392 training:
1393 batch_size: 512
1394 epochs: 200
1395 lr: 0.0003
1396 weight_decay: 0.01
1397 warmup_steps: 5000
1398 temperature: 0.07
1399 loss:
1400 supcon_weight: 1.0
1401 arcface_weight: 0.3
1402 triplet_weight: 0.1
1403 optimizer: adamw
1404 scheduler: cosine
1405 mixed_precision: bf16
1406 gradient_clip: 1.0
1407
1408 index:
1409 type: "IVF4096,PQ16"
1410 metric: cosine
1411 train_on_gpu: true
1412 nprobe: 64
1413
1414 serving:
1415 host: "0.0.0.0"
1416 port: 8088
1417 workers: 4
1418 max_query_duration: 30.0
1419 cache_size: 10000
1420 reject_threshold: 0.5
1421 top_n: 5
1422
1423 logging:
1424 level: INFO
1425 format: json
1426 output: stdout
1427 ```
1 # Changelist / 2026-06-02
2
3 ## 本次补充交付(2026-06-02 16:12 UTC)
4
5 ### 目标
6 把当前工作切换成“可交接、可暂停、可恢复”的状态。
7
8 ### 本次纳入交付的内容
9
10 | 类别 | 内容 |
11 |---|---|
12 | 状态 | 当前 dual-axis 仍以 `hum_focus` 为最佳候选 |
13 | 文档 | `CHANGELOG``session-handoff``delivery-handoff` 已补齐最新快照 |
14 | 约束 | 继续保留相对路径文档跳转,不碰大数据与训练产物 |
15 | 续跑 | 新 session 可直接从 handoff 接上继续做训练/评测/优化 |
16
17 ### 这次交付的意义
18
19 1. 先把当前成果冻结,避免上下文丢失。
20 2. 给新 session 留一个最短恢复路径。
21 3. 后续可以无缝继续补数据集、改切片、提准确率。
22
23 ---
24
25 ## 本次补充交付(2026-06-02 15:09 UTC)
26
27 ### 目标
28 把当前状态从“仍在稳定推进”升级为“已确认异常退出、需要排查”的交接包。
29
30 ### 本次纳入交付的内容
31
32 | 类别 | 内容 |
33 |---|---|
34 | 证据 | `PID=431703``PID=424691` 均已退出 |
35 | 状态 | observable 目录仍停在 `chromaprint_progress.json + chromaprint.pkl` |
36 | 风险 | 没有 `reference_*`,没有 `evaluate.py`,没有明确 traceback |
37 | 文档 | `CHANGELOG``changelist``delivery handoff``session handoff``AGENT memory` |
38
39 ### 文件级变更
40
41 | 文件 | 说明 |
42 |---|---|
43 | [./CHANGELOG.md](./CHANGELOG.md) | 补记 build-index 异常退出 checkpoint |
44 | [./delivery-handoff-2026-06-02.md](./delivery-handoff-2026-06-02.md) | 顶部改写为异常排查接管包 |
45 | [./session-handoff.md](./session-handoff.md) | 顶部快照切到“进程已退出、无下游产物” |
46 | [../AGENT.md](../AGENT.md) | 更新长期记忆,避免新 session 误判为仍在运行 |
47
48 ### 当前最重要的 fresh evidence
49
50 - 观测时间:`2026-06-02 15:09:19 UTC`
51 - `ps -p 431703`:无存活进程
52 - `ps -p 424691`:无存活进程
53 - `pgrep -af 'run_demo.py build-index|evaluate.py ...'`:未发现接续进程
54 - observable 目录仅有:
55 - `chromaprint.pkl`
56 - `chromaprint_progress.json`
57 - 末次 progress:
58 - `status=building`
59 - `refs_done=4420/8000`
60 - 未出现:
61 - `reference_*`
62 - `evaluate.py`
63
64 ### 重要决策
65
66 1. 当前已不应继续把它描述成“仅仅线性慢”。
67 2. 下一轮工作应转向 **build-index 异常退出排查**
68 3. 新提交已经有意义,因为状态从“运行中”变成了“已退出且无下游产物”。
69
70 ## 本次追加交付(2026-06-02 15:18 UTC)
71
72 ### 新增代码修复
73
74 | 文件 | 变更 |
75 |---|---|
76 | [../acr-engine/run_demo.py](../acr-engine/run_demo.py) | `build-index` / demo 关键日志统一 `flush=True` |
77 | [../acr-engine/src/engines/chromaprint_matcher.py](../acr-engine/src/engines/chromaprint_matcher.py) | chromaprint 阶段 progress 日志 `flush=True` |
78 | [../acr-engine/src/engines/ecapa_embedder.py](../acr-engine/src/engines/ecapa_embedder.py) | embedding/reference 阶段关键日志 `flush=True` |
79
80 ### 新增验证证据
81
82 - 极小样本复现:`/tmp/chroma_repro_tiny12`
83 - 结果:`RC=1`
84 - 现在日志已实时落盘,不再是 `0 bytes`
85 - `[build-index] starting chromaprint index ...`
86 - `[build-reference-index] start: refs=12 ...`
87 - `ValueError: No reference embeddings were produced ...`
88
89 ### 结论
90
91 - 当前已修复“失败时日志完全不可见”的可观测性问题。
92 - 下一轮 root cause 排查可以直接依赖实时日志,而不再需要盲等。
93
94 ## 本次追加交付(2026-06-02 15:22 UTC)
95
96 ### 新增代码修复
97
98 | 文件 | 变更 |
99 |---|---|
100 | [../acr-engine/src/engines/chromaprint_matcher.py](../acr-engine/src/engines/chromaprint_matcher.py) | 坏音频/缺失音频跳过;progress 增加 `skipped_refs` |
101 | [../acr-engine/src/engines/ecapa_embedder.py](../acr-engine/src/engines/ecapa_embedder.py) | 坏音频/缺失音频跳过;progress 增加 `skipped_refs` |
102
103 ### 新增验证证据
104
105 - 最小容错复现:`/tmp/chroma_skip_repro`
106 - 输入:`1 good mp3 + 1 bad mp3`
107 - 结果:`RC=0`
108 - 验证点:
109 - 日志可见 `skip decode failure`
110 - `chromaprint_progress.json``status=complete`
111 - `reference_progress.json``status=complete`
112 - 两个 progress 文件都记录 `skipped_refs=1`
113 - 最终成功产出 `reference_embs.npy` / `reference_ids.npy`
114
115 ### 结论
116
117 - 当前已验证:单个坏 MP3 不再拖垮整轮 `build-index`
118 - 下一轮应回到真实路径复现,确认主问题是否就是由坏 MP3 触发。
119
120 ## 本次追加交付(2026-06-02 15:29 UTC)
121
122 ### 新增运行证据
123
124 | 类别 | 内容 |
125 |---|---|
126 | rerun | fixed real-path 200-ref rerun 仍在前台运行:`session 19709` |
127 | chromaprint | `200/200` 完成,`skipped_refs=0` |
128 | reference | 已进入 embedding/reference 阶段,并完成 `25/200` checkpoint |
129 | 产物 | 已落盘 `reference_progress.json``reference_embs.partial.npy``reference_ids.partial.npy` |
130
131 ### 当前最重要的 fresh evidence
132
133 - 观测时间:`2026-06-02 15:29:17 UTC`
134 - 输出目录:`/tmp/fma_realpath_small_rerun_index2`
135 - `chromaprint_progress.json`
136 - `status=complete`
137 - `refs_done=200/200`
138 - `hashes=57577`
139 - `postings=187446`
140 - `skipped_refs=0`
141 - `reference_progress.json`
142 - `status=building`
143 - `refs_done=25/200`
144 - `windows_done=256`
145 - `skipped_refs=0`
146 - 已出现:
147 - `reference_embs.partial.npy`
148 - `reference_ids.partial.npy`
149
150 ### 结论
151
152 - 这次 fixed rerun 已经证明:修复后的真实路径样本不再卡死在 chromaprint 阶段。
153 - 当前最有价值的下一步,变为继续盯 `reference_*` 完成或捕获新的明确失败证据。
154
155 ## 本次追加交付(2026-06-02 15:35 UTC)
156
157 ### 新增运行证据
158
159 | 类别 | 内容 |
160 |---|---|
161 | chromaprint | `200/200` 完成,`skipped_refs=0` |
162 | reference | `200/200` 完成,`windows_done=2068` |
163 | 产物 | `reference_embs.npy``reference_ids.npy` 已完整落盘 |
164 | shape | `embedding_shape=[2068, 192]` |
165
166 ### 当前最重要的 fresh evidence
167
168 - 观测时间:`2026-06-02 15:35:19 UTC`
169 - 输出目录:`/tmp/fma_realpath_small_rerun_index2`
170 - `reference_progress.json`
171 - `status=complete`
172 - `refs_done=200/200`
173 - `windows_done=2068`
174 - `embedding_shape=[2068, 192]`
175 - `skipped_refs=0`
176 - 最终产物:
177 - `reference_embs.npy``1588352 bytes`
178 - `reference_ids.npy``74576 bytes`
179 - stdout 明确出现:
180 - `Built reference index: 2068 windows, embeddings shape (2068, 192)`
181 - `[done] embedding index built: 2068 refs`
182
183 ### 结论
184
185 - 当前已确认:修复后的真实路径 rerun 不仅能进入 reference 阶段,而且能完整产出最终 embedding index。
186 - 下一轮最高价值工作应切到:评测链是否自动衔接,以及必要时补显式 evaluate smoke。
187
188 ## 本次追加交付(2026-06-02 15:40 UTC)
189
190 ### 新增运行证据
191
192 | 类别 | 内容 |
193 |---|---|
194 | evaluate | 显式 `evaluate.py` smoke 已完成 |
195 | query 规模 | `num_queries=35`(overlap 中全部非 reference query) |
196 | 指标 | `top1=0.8571`, `topk=1.0` |
197 | by_type | `clean: n=35, top1=0.8571, topk=1.0` |
198
199 ### 当前最重要的 fresh evidence
200
201 - 观测时间:`2026-06-02 15:40:30 UTC`
202 - 结果文件:`/tmp/fma_realpath_small_rerun_eval/eval_top50.json`
203 - 评测结果:
204 - `split=test`
205 - `num_queries=35`
206 - `top1=0.8571`
207 - `topk=1.0`
208 - query 数说明:
209 - overlap test items = `235`
210 -`reference` query = `35`
211 - 所以 `--max-queries 50` 实际评到 `35`
212
213 ### 结论
214
215 - 当前已不只是建索引成功,而是已经拿到首份真实路径 `build-index -> evaluate` 闭环证据。
216 - 下一轮应把重点切到:更大评测规模与 hard case / confusion 评测。
217
218 ## 本次追加交付(2026-06-02 15:43 UTC)
219
220 ### 新增运行证据
221
222 | 类别 | 内容 |
223 |---|---|
224 | hard-case smoke | `synthetic_v2 + models_v6 + index_v6` 显式评测完成 |
225 | 总体 | `num_queries=16`, `top1=0.6875`, `topk=1.0` |
226 | hard case | `humming_like top1=0.25`, `confused top1=0.0` |
227 | 结论 | 当前短板已明确落在 hard-case top1,而不是 clean/topk |
228
229 ### 当前最重要的 fresh evidence
230
231 - 观测时间:`2026-06-02 15:43:17 UTC`
232 - 结果文件:`/tmp/synthetic_v2_eval_v6_top16.json`
233 - 评测结果:
234 - `top1=0.6875`
235 - `topk=1.0`
236 - `humming_like: n=4, top1=0.25, topk=1.0`
237 - `confused: n=1, top1=0.0, topk=1.0`
238 - manifest 审计结果:
239 - real-path FMA external smoke 只有 `clean` query
240 - synthetic_v2 才包含 `augmented` / `humming_like` / `confused`
241
242 ### 结论
243
244 - 当前已经不仅知道“系统能跑通”,还知道“最该优化哪里”:hard-case 的 top1。
245 - 下一轮更有价值的是围绕 `humming_like` / `confused` 做输入层、切片、混淆增强与 hard negative 优化。
246
247 ## 本次追加交付(2026-06-02 15:45 UTC)
248
249 ### 新增运行证据
250
251 | 类别 | 内容 |
252 |---|---|
253 | baseline sweep | `v3~v6` 已完成统一 hard-case sweep |
254 | 总体最佳 | `v6`: `top1=0.65`, `topk=0.95` |
255 | humming_like 最佳 | `v5`: `top1=0.5` |
256 | confused 最佳 | `v3` / `v6`: `top1=0.25` |
257
258 ### 当前最重要的 fresh evidence
259
260 - 观测时间:`2026-06-02 15:45:18 UTC`
261 - 汇总文件:`/tmp/synth_v2_baseline_sweep/summary.json`
262 - 统一评测集:`data/synthetic_v2`
263 - 结果摘录:
264 - `v3`: overall `0.6/0.75`, hard-case `hum=0.0`, `conf=0.25`
265 - `v4`: overall `0.4/0.8`, hard-case `hum=0.0`, `conf=0.0`
266 - `v5`: overall `0.6/0.9`, hard-case `hum=0.5`, `conf=0.0`
267 - `v6`: overall `0.65/0.95`, hard-case `hum=0.25`, `conf=0.25`
268
269 ### 结论
270
271 - 当前最合理的下一轮实验基线是 `v6`,因为总体最稳。
272 -`v5``humming_like` 上明显更强,值得做 targeted diff / 吸收。
273
274 ## 本次追加交付(2026-06-02 15:46 UTC)
275
276 ### 新增差异审计证据
277
278 | 类别 | 内容 |
279 |---|---|
280 | v5 来源 | `type-aware hard-case weighting` |
281 | v6 来源 | `sample-level confused-priority weighting` |
282 | 解释 | `v5` 更利于 `humming_like``v6` 更利于 `confused` |
283 | 决策 | 下一轮应做双轴 hard-case weighting / 分治,而不是单轴加权 |
284
285 ### 当前最重要的 fresh evidence
286
287 - `docs/CHANGELOG.md:2954+``v6` = sample-level confused-priority weighting
288 - `docs/CHANGELOG.md:6805+``v5` = type-aware hard-case weighting
289 - `docs/sota-research-2026.md:113-114`
290 - `v5`: `overall=0.60`, `humming_like=0.50`, `confused=0.00`
291 - `v6`: `overall=0.65`, `humming_like=0.25`, `confused=0.25`
292
293 ### 结论
294
295 - 现在已经不仅知道 `v5/v6` 哪个更强,还知道“为什么”。
296 - 下一轮应把 `humming_like``confused` 分开建模或分开加权。
297
298 ## 本次追加交付(2026-06-02 15:47 UTC)
299
300 ### 新增代码能力
301
302 | 文件 | 变更 |
303 |---|---|
304 | [../acr-engine/src/data/dataset.py](../acr-engine/src/data/dataset.py) | hard-case 采样权重与 pair 权重改为配置驱动 |
305 | [../acr-engine/train.py](../acr-engine/train.py) | 训练链路透传 dual-axis 权重配置 |
306 | [../acr-engine/configs/default.yaml](../acr-engine/configs/default.yaml) | 增加 `sample_type_weights` / `pair_type_weights` 默认配置 |
307
308 ### 当前最重要的 fresh evidence
309
310 - `python -m py_compile train.py src/data/dataset.py`:通过
311 - `train.py --data data/synthetic_v2 --device cpu --epochs 1 --batch-size 4 --dry-run`:通过
312 - 自定义权重实例化检查:
313 - `dataset_len=96`
314 - `unique_songs=16`
315 - `sample_multiplicity_minmax=6/6`
316 - `hard_weight=[5.0, 1.0]`
317
318 ### 结论
319
320 - dual-axis hard-case weighting 已从“设计建议”升级为“代码中可直接调参实验”的状态。
321 - 下一轮可直接围绕 `sample_type_weights``pair_type_weights` 做最小实验。
322
323 ## 本次追加交付(2026-06-02 15:56 UTC)
324
325 ### 新增运行证据
326
327 | 类别 | 内容 |
328 |---|---|
329 | dual-axis smoke | `train -> build-index -> evaluate` 完整跑通 |
330 | 训练输出 | `/tmp/dualaxis_smoke/models/best_model.pt` |
331 | 索引输出 | `/tmp/dualaxis_smoke/index/` |
332 | 评测输出 | `/tmp/dualaxis_smoke/eval.json` |
333 | 结果 | `top1=0.5`, `topk=0.9` |
334 | hard-case | `humming_like=0.0`, `confused=0.25` |
335
336 ### 当前最重要的 fresh evidence
337
338 - `num_queries=20`
339 - `clean: n=8, top1=0.875, topk=1.0`
340 - `augmented: n=4, top1=0.5, topk=0.75`
341 - `humming_like: n=4, top1=0.0, topk=0.75`
342 - `confused: n=4, top1=0.25, topk=1.0`
343
344 ### 结论
345
346 - 目前这组 dual-axis 配置证明了“可配置实验链路”是通的。
347 - 但它没有带来 `humming_like` 改善,说明后续搜索需要更细:该拆分 `sample_type_weights``pair_type_weights` 的取值粒度。
348
349 ## 本次追加交付(2026-06-02 16:03 UTC)
350
351 ### 新增运行证据
352
353 | 候选 | top1 | topk | humming_like top1 | confused top1 | 结论 |
354 |---|---:|---:|---:|---:|---|
355 | hum_focus | 0.7 | 0.85 | 0.5 | 0.25 | 当前最优 |
356 | hum_balanced | 0.65 | 0.95 | 0.25 | 0.25 | 只回到 v6 水平 |
357
358 ### 当前最重要的 fresh evidence
359
360 - 观测时间:`2026-06-02 16:03:13 UTC`
361 - `hum_focus` 结果文件:`/tmp/dualaxis_sweep/hum_focus/eval.json`
362 - `hum_balanced` 结果文件:`/tmp/dualaxis_sweep/hum_balanced/eval.json`
363 - 对比结论:`hum_focus``humming_like` 上优于 `hum_balanced`,且总体更优。
364
365 ### 结论
366
367 - 当前 dual-axis 线的最佳候选已收敛为 `hum_focus`
368 - 下一轮应围绕 `hum_focus` 做微调搜索,而不是回退到 `v6` 或扩大盲搜范围。
1 ## 本次交付包追加更新(2026-06-02 16:03 UTC)
2
3 ### 交付结论
4
5 当前最新里程碑已经从“dual-axis 首轮可跑通”推进到 **dual-axis 候选已收敛到 hum_focus**
6 - 远程基线当前为:`9c3f182`(更新前)
7 - `hum_focus` 当前优于 `hum_balanced``v6` 基线
8 - 因此下一轮应围绕 `hum_focus` 做微调,而不是回退或盲搜
9
10 ### 当前最新事实
11
12 #### dual-axis 对比结果
13 - `hum_focus`
14 - `top1=0.7`
15 - `topk=0.85`
16 - `humming_like=0.5`
17 - `confused=0.25`
18 - `hum_balanced`
19 - `top1=0.65`
20 - `topk=0.95`
21 - `humming_like=0.25`
22 - `confused=0.25`
23
24 ### 当前判断
25
26 - `hum_focus` 是目前最值得继续迭代的 dual-axis 起点。
27 - 下一阶段建议是以 `hum_focus` 为锚点做小步搜索,优先保住 `humming_like` 优势。
28
29 ## 本次交付包追加更新(2026-06-02 16:11 UTC)
30
31 ### 交付结论
32
33 最新的 `hum_guard` 复核结果已经确认:
34 - 它没有超过 `hum_focus`
35 - `topk` 持平,但 `top1` 更低
36 - 所以下一轮仍应围绕 `hum_focus` 微调
37
38 ### fresh evidence
39
40 - `num_queries=20`
41 - `top1=0.6`
42 - `topk=0.85`
43 - `humming_like top1=0.5`
44 - `confused top1=0.0`
45
46 ---
47
48 ## 本次交付包追加更新(2026-06-02 16:12 UTC)
49
50 ### 交付结论
51
52 当前已经完成“先交付、后续续跑”的冻结动作:
53 - 交接文档已补齐最新快照
54 - 新 session 可直接从这些文件继续
55 - 当前最重要的优化方向仍是 `hum_focus`
56
57 ### 当前可直接继承的内容
58
59 - 训练数据规范
60 - pgvector 导出规范
61 - FMA / 开源数据接入说明
62 - SOTA 研究和切片策略说明
63
64 ### 重启后建议顺序
65
66 1.`docs/session-handoff.md`
67 2.`docs/CHANGELOG.md`
68 3. 继续做 `hum_focus` 小步搜索
69 4. 再做训练 / 评测 / 提交闭环
70
71 ---
72
73 ## 本次交付包追加更新(2026-06-02 15:56 UTC)
74
75 ### 交付结论
76
77 当前最新里程碑已经从“dual-axis 参数化完成”推进到 **dual-axis smoke 首次端到端评测完成**
78 - 远程基线当前为:`6279850`(更新前)
79 - 训练、建索引、评测全部跑通
80 - 但这组权重没有改善 `humming_like`,说明接下来要做更细粒度搜索
81
82 ### 当前最新事实
83
84 #### dual-axis smoke 结果
85 - 观测时间:`2026-06-02 15:56:02 UTC`
86 - 结果文件:`/tmp/dualaxis_smoke/eval.json`
87 - 评测结果:
88 - `num_queries=20`
89 - `top1=0.5`
90 - `topk=0.9`
91 - `clean=0.875`
92 - `augmented=0.5`
93 - `humming_like=0.0`
94 - `confused=0.25`
95
96 ### 当前判断
97
98 - dual-axis 入口是可用的,但当前试验组合不是更优解。
99 - 下一阶段应进入更细粒度的权重搜索,而不是直接扩大规模。
100
101 ---
102
103 ## 本次交付包追加更新(2026-06-02 15:47 UTC)
104
105 ### 交付结论
106
107 当前最新里程碑已经从“知道该做 dual-axis”推进到 **dual-axis hard-case weighting 已在代码中参数化**
108 - 远程基线当前为:`7812b58`(更新前)
109 - `sample_type_weights``pair_type_weights` 已可配置
110 - 训练 dry-run 已通过
111 - 因此下一轮可直接做最小调参实验,而不是再先改代码结构
112
113 ### 当前最新事实
114
115 #### 代码实现位置
116 - `src/data/dataset.py`
117 - `sample_type_weights` 控制 song-level 采样重复度
118 - `pair_type_weights` 控制 pair-level `hard_weight`
119 - `train.py`:从 `training` 配置透传
120 - `configs/default.yaml`:提供默认 dual-axis 配置
121
122 #### fresh verification
123 - `python -m py_compile train.py src/data/dataset.py`:通过
124 - `train.py --data data/synthetic_v2 --device cpu --epochs 1 --batch-size 4 --dry-run`:通过
125 - 自定义权重实例化检查:
126 - `dataset_len=96`
127 - `sample_multiplicity_minmax=6/6`
128 - `hard_weight=[5.0, 1.0]`
129
130 ### 当前判断
131
132 - 现在已经具备一个最小、低风险、可反复实验的 dual-axis 入口。
133 - 下一阶段最值得做的是直接搜索 `humming_like` / `confused` 的权重组合,而不是继续做只读分析。
134
135 ---
136
137 ## 本次交付包追加更新(2026-06-02 15:46 UTC)
138
139 ### 交付结论
140
141 当前最新里程碑已经从“确定 v6/v5 谁更适合作为基线”推进到 **解释清楚它们为什么会这样表现**
142 - 远程基线当前为:`93dfa15`(更新前)
143 - `v5` 的关键机制是 `type-aware hard-case weighting`
144 - `v6` 的关键机制是 `sample-level confused-priority weighting`
145 - 因此下一轮最合理的不是继续盲 sweep,而是做 `humming_like``confused` 的双轴分治策略
146
147 ### 当前最新事实
148
149 #### v5 / v6 差异来源
150 - `v5`
151 - 历史记录位置:`docs/CHANGELOG.md:6805+`
152 - 定义:`type-aware hard-case weighting`
153 - 结果:`humming_like top1=0.50`, `confused top1=0.00`
154 - `v6`
155 - 历史记录位置:`docs/CHANGELOG.md:2954+`
156 - 定义:`sample-level confused-priority weighting`
157 - 结果:`humming_like top1=0.25`, `confused top1=0.25`
158 - 汇总解释:`docs/sota-research-2026.md:113-114`
159
160 ### 当前判断
161
162 - `v5``v6` 的差异已经可解释,不再是黑箱经验差异。
163 - 下一阶段最值得做的是:
164 1. 设计双轴 hard-case weighting;
165 2.`humming_like``confused` 分开控制;
166 3. 再用现有双轨验证链回归测试。
167
168 ---
169
170 ## 本次交付包追加更新(2026-06-02 15:45 UTC)
171
172 ### 交付结论
173
174 当前最新里程碑已经从“知道 hard-case 有缺口”推进到 **知道哪套历史基线最值得作为下一轮优化起点**
175 - 远程基线当前为:`d4961b1`(更新前)
176 - `v6` 是当前总体最优基线:`top1=0.65`, `topk=0.95`
177 - `v5``humming_like` 上更强:`top1=0.5`
178 - 因此下一轮不该盲改,而应以 `v6` 为主基线,对比吸收 `v5` 的 hard-case 优势
179
180 ### 当前最新事实
181
182 #### hard-case baseline sweep
183 - 观测时间:`2026-06-02 15:45:18 UTC`
184 - 汇总:`/tmp/synth_v2_baseline_sweep/summary.json`
185 - 结果:
186 - `v3`: overall `top1=0.6`, `topk=0.75`; `humming_like=0.0`, `confused=0.25`
187 - `v4`: overall `top1=0.4`, `topk=0.8`; `humming_like=0.0`, `confused=0.0`
188 - `v5`: overall `top1=0.6`, `topk=0.9`; `humming_like=0.5`, `confused=0.0`
189 - `v6`: overall `top1=0.65`, `topk=0.95`; `humming_like=0.25`, `confused=0.25`
190
191 ### 当前判断
192
193 - `v6` 适合作为下一轮总体优化主基线。
194 - `v5` 适合作为 `humming_like` 对照基线。
195 - 下一阶段最值得做的是:
196 1. 审计 `v5``v6` 的配置/数据/切片差异;
197 2.`v5``humming_like` 优势迁移到 `v6`
198 3. 再用真实路径 clean + synthetic hard-case 双轨复测。
199
200 ---
201
202 ## 本次交付包追加更新(2026-06-02 15:43 UTC)
203
204 ### 交付结论
205
206 当前最新里程碑已经从“real-path clean 闭环跑通”推进到 **hard-case 短板已被明确量化**
207 - 远程基线当前为:`81704ac`(更新前)
208 - real-path FMA smoke 已证明 `clean` 闭环可跑通
209 - synthetic hard-case smoke 已证明当前主要短板在 `humming_like` / `confused` 的 top1
210 - 因此下一阶段不应重复 clean smoke,而应聚焦 hard-case 鲁棒性优化
211
212 ### 当前最新事实
213
214 #### hard-case smoke 结果
215 - 观测时间:`2026-06-02 15:43:17 UTC`
216 - 组合:`data/synthetic_v2` + `data/models_v6/best_model.pt` + `data/index_v6/reference`
217 - 结果文件:`/tmp/synthetic_v2_eval_v6_top16.json`
218 - 评测结果:
219 - `num_queries=16`
220 - `top1=0.6875`
221 - `topk=1.0`
222 - `clean: n=7, top1=1.0, topk=1.0`
223 - `augmented: n=4, top1=0.75, topk=1.0`
224 - `humming_like: n=4, top1=0.25, topk=1.0`
225 - `confused: n=1, top1=0.0, topk=1.0`
226
227 #### 关键解释
228 - real-path FMA external smoke manifest 目前只有 `clean` query:
229 - external test = `1613 clean`
230 - rerun overlap test = `35 clean`
231 - 当前仓库里能提供 `humming_like` / `confused` 的现成评测集是 `data/synthetic_v2`
232
233 ### 当前判断
234
235 - 真实路径闭环已经足够证明工程链可运行。
236 - 下一阶段的收益最高点已经收敛到:
237 1. `humming_like` top1 提升;
238 2. `confused` top1 提升;
239 3. 将 hard-case 生成/标注引入真实开放数据评测链。
240
241 ---
242
243 ## 本次交付包追加更新(2026-06-02 15:40 UTC)
244
245 ### 交付结论
246
247 当前最新里程碑已经从“reference index 完成”推进到 **fixed real-path 200-ref rerun 已拿到首份显式 evaluate 指标**
248 - 远程基线当前为:`9371e94`(更新前)
249 - real-path `200-ref` index 已完整完成
250 - 显式 `evaluate.py` smoke 已完成
251 - 当前首份结果:`top1=0.8571`, `topk=1.0`, `num_queries=35`
252 - 因此主线已从“索引能否跑通”进入“评测质量与 hard case 扩展”阶段
253
254 ### 当前最新事实
255
256 #### evaluate smoke 路径
257 - 观测时间:`2026-06-02 15:40:30 UTC`
258 - 结果文件:`/tmp/fma_realpath_small_rerun_eval/eval_top50.json`
259 - 评测结果:
260 - `split=test`
261 - `num_queries=35`
262 - `top1=0.8571`
263 - `topk=1.0`
264 - `by_type.clean`: `n=35`, `top1=0.8571`, `topk=1.0`
265 - query 数来源说明:
266 - 200-ref catalog 与现有 external smoke test overlap = `235` items
267 - 其中非 `reference` query = `35`
268 - 所以 `--max-queries 50` 实际只评到 `35`
269
270 ### 当前判断
271
272 - 当前已经拥有一条完整可复用的真实路径 smoke 证据链:
273 `chromaprint complete -> reference complete -> evaluate complete`
274 - 下一阶段更值得做的是:
275 1. 扩大评测 query 数与 reference 规模;
276 2. 引入 `confused` / `humming_like` / hard negative 评测。
277
278 ---
279
280 ## 本次交付包追加更新(2026-06-02 15:35 UTC)
281
282 ### 交付结论
283
284 当前最新里程碑已经从“进入 reference 阶段”推进到 **fixed real-path 200-ref rerun 已完整产出最终 embedding/reference index**
285 - 远程基线当前为:`41c4d7c`(更新前)
286 - chromaprint 已完整完成:`200/200`
287 - reference 已完整完成:`200/200`
288 - 最终产物 `reference_embs.npy` / `reference_ids.npy` 已落盘
289 - 因此主问题已从“能否穿过建索引核心阶段”转向“后续 evaluate / identify 链如何衔接验证”
290
291 ### 当前最新事实
292
293 #### fixed real-path rerun 路径
294 - 观测时间:`2026-06-02 15:35:19 UTC`
295 - 输出目录:`/tmp/fma_realpath_small_rerun_index2`
296 - `chromaprint_progress.json`
297 - `status=complete`
298 - `refs_done=200 / 200`
299 - `hashes=57577`
300 - `postings=187446`
301 - `skipped_refs=0`
302 - `reference_progress.json`
303 - `status=complete`
304 - `refs_done=200 / 200`
305 - `windows_done=2068`
306 - `elapsed_sec=410.046`
307 - `embedding_shape=[2068, 192]`
308 - `skipped_refs=0`
309 - 当前已出现最终产物:
310 - `reference_embs.npy`
311 - `reference_ids.npy`
312
313 ### 当前判断
314
315 - 这条 fixed rerun 已经给出强证据:`flush=True` 与坏音频 skip tolerance 修复后,真实路径样本可以完整跑完两段核心建索引流程。
316 - 下一阶段应集中验证:
317 1. 是否自动衔接到 evaluate / identify;
318 2. 若没有,补一轮显式 evaluate smoke。
319
320 ---
321
322 ## 本次交付包追加更新(2026-06-02 15:29 UTC)
323
324 ### 交付结论
325
326 当前最新里程碑不是新的失败,而是 **fixed real-path 200-ref rerun 已明确跨入 reference/embedding 阶段**
327 - 远程基线当前为:`707449b`
328 - chromaprint 已完整完成:`200/200`
329 - reference 阶段已写出首个 checkpoint:`25/200`
330 - 已出现 `reference_progress.json` 与 partial numpy 产物
331 - 因此下一 session 不应再把这条 rerun 当作“停在 chromaprint 无下游文件”的旧状态
332
333 ### 当前最新事实
334
335 #### fixed real-path rerun 路径
336 - 前台 session:`19709`
337 - 观测时间:`2026-06-02 15:29:17 UTC`
338 - 输出目录:`/tmp/fma_realpath_small_rerun_index2`
339 - `chromaprint_progress.json`
340 - `status=complete`
341 - `refs_done=200 / 200`
342 - `hashes=57577`
343 - `postings=187446`
344 - `skipped_refs=0`
345 - `reference_progress.json`
346 - `status=building`
347 - `refs_done=25 / 200`
348 - `windows_done=256`
349 - `elapsed_sec=52.567`
350 - `eta_sec=367.967`
351 - `skipped_refs=0`
352 - 当前已出现:
353 - `reference_embs.partial.npy`
354 - `reference_ids.partial.npy`
355
356 ### 当前判断
357
358 - `flush=True` 与坏音频 skip tolerance 修复之后,真实路径 rerun 已穿过 `chromaprint -> reference` 阶段边界。
359 - 当前最高优先级不再是重复证明 chromaprint 完成,而是继续盯 reference 阶段是否:
360 1. 完整落盘 `reference_embs.npy` / `reference_ids.npy`;或
361 2. 暴露新的明确 traceback / failure evidence。
362
363 ### 建议的新 session 接管顺序
364
365 1. 先看 [./session-handoff.md](./session-handoff.md) 顶部新快照
366 2. 读取前台 `session 19709` 最新输出
367 3. 检查 `/tmp/fma_realpath_small_rerun_index2/` 是否已从 partial 转为 final 产物
368
369 ---
370
371 # Delivery Handoff / 2026-06-02
372
373 ## 本次交付包(2026-06-02 15:09 UTC)
374
375 ### 交付结论
376
377 这次新增的关键交付,不再是单纯的进度观察,而是一个**新的异常状态检查点**
378 - 远程基线已推进到:`cdf33bb`
379 - observable chromaprint smoke 与 legacy 全量 FMA `build-index` 进程都已退出
380 - 但两者都**没有**进入 `reference_*` / `evaluate.py`
381 - 因此下一 session 的首要任务,已从“盯进度”切换为“排查 `build-index` 异常退出”
382
383 ### 当前最新事实
384
385 #### observable 路径
386 - 原进程:`PID=431703`
387 - 最后观测时间:`2026-06-02 15:09:19 UTC`
388 - 当前 `ps -p 431703`:无存活进程
389 - 当前目录仅有:
390 - `chromaprint.pkl`
391 - `chromaprint_progress.json`
392 - 最后 progress 状态:
393 - `status=building`
394 - `refs_done=4420 / 8000`
395 - `elapsed_sec=3964.861`
396 - `hashes=357373`
397 - `postings=3774363`
398 - 当前**仍未出现**
399 - `reference_progress.json`
400 - `reference_embs.partial.npy`
401 - `reference_ids.partial.npy`
402 - `reference_embs.npy`
403 - `reference_ids.npy`
404 - `evaluate.py`
405
406 #### legacy 全量 FMA 路径
407 - 原进程:`PID=424691`
408 - 当前 `ps -p 424691`:无存活进程
409 - 当前目录仍只有:
410 - `/tmp/fma_real_smoke_stopcheck/fma_index_smoke`
411 - 仍未看到 index artifact 或 `evaluate.py`
412
413 #### 当前判断
414 - 这不再是“CPU-only 长时间构建但仍在推进”的状态。
415 - 现在更像是:**`build-index` 在 chromaprint 阶段中途退出,但没有留下显式下游产物**
416
417 #### 已完成的低风险修复
418 - 已把 `run_demo.py``chromaprint_matcher.py``ecapa_embedder.py` 的关键日志改为 `flush=True`
419 - 极小样本 `/tmp/chroma_repro_tiny12` 已验证:失败时日志与 traceback 可实时落盘,不再保持 `0 bytes`
420 - 这意味着下一 session 继续排查时,日志可作为一手证据,而不是黑箱。
421
422 #### 已完成的坏音频容错修复
423 - 已为 chromaprint/reference 两个建索引阶段增加单文件容错:坏 MP3 / 缺失音频会被记录并跳过。
424 - 最小复现 `/tmp/chroma_skip_repro` 已验证:
425 - `RC=0`
426 - `skip decode failure` 日志可见
427 - `reference_embs.npy` / `reference_ids.npy` 成功产出
428 - progress 中记录 `skipped_refs=1`
429 - 这说明:单个坏 MP3 不再拖垮整轮 `build-index`
430
431 ## 新 session 接管顺序
432
433 1. 先看 [./session-handoff.md](./session-handoff.md)
434 2. 再看 [./changelist-2026-06-02.md](./changelist-2026-06-02.md)
435 3. 然后优先做 3 件事:
436 1. 复盘 `run_demo.py build-index` 的退出路径与异常处理
437 2. 检查是否存在未捕获 OOM / shell termination / silent failure
438 3. 在更小样本上复现“chromaprint 中途退出但无后续文件”的行为
439
440 ## 当前卡点
441
442 1. 关键进程已经退出,但没有明确 traceback 留存。
443 2. observable 与 legacy 两条路径都停在“没有 `reference_*` / 没有 `evaluate.py`”的中间态。
444 3. 工作树仍有大量数据噪音,提交时必须只显式暂存文档/代码文件。
445
446 ## 本次交付包含的关键文档
447
448 - [./CHANGELOG.md](./CHANGELOG.md)
449 - [./changelist-2026-06-02.md](./changelist-2026-06-02.md)
450 - [./session-handoff.md](./session-handoff.md)
451 - [../AGENT.md](../AGENT.md)
452
453 ## 本次明确不提交
454
455 - `acr-engine/data/raw/*`
456 - `acr-engine/data/external_smoke/*`
457 - `/tmp/*`
458 - checkpoint / index artifacts
459 - `__pycache__`
1 # External Manifest Template
2
3 适用于 FMA / Jamendo / CCMusic / ModelScope 白名单数据集。
4
5 ## catalog.csv 最小字段
6
7 ```csv
8 song_id,audio_path,duration,source_dataset
9 track_0001,raw/track_0001.wav,12.5,fma
10 ```
11
12 转换命令:
13
14 ```bash
15 python src/data/manifest_tools.py csv-to-catalog catalog.csv manifests/catalog.json
16 ```
17
18 ## 输出 catalog.json 结构
19
20 ```json
21 {
22 "song_id": "track_0001",
23 "audio_path": "raw/track_0001.wav",
24 "duration": 12.5,
25 "type": "reference",
26 "source_dataset": "fma"
27 }
28 ```
1 # Open Dataset Integration Plan
2
3 ## Recommended order
4
5 1. **FMA small**
6 - URL: https://github.com/mdeff/fma
7 - Why: easiest small realistic music subset for retrieval experiments
8 2. **MTG-Jamendo**
9 - URL: https://github.com/MTG/mtg-jamendo-dataset
10 - Why: larger CC-licensed corpus with scriptable upstream tooling
11 3. **QBSH / humming corpora**
12 - Why: add after retrieval baseline is stable
13
14 ## Repo strategy
15
16 - Keep external dataset ingestion optional
17 - Convert external tracks into:
18 - `catalog.json` for searchable references
19 - query segment manifests for evaluation
20 - Start with small local subsets before full-corpus scaling
1 # ACR 项目 Roadmap
2
3 > 更新:2026-06-02
4
5 ## Phase 0:原型跑通(当前阶段)
6
7 ### 目标
8 完成一个端到端可运行的本地 demo。
9
10 ### 范围
11 - [x] 合成数据生成
12 - [x] 数据增强
13 - [x] ECAPA embedding 模型
14 - [x] 传统指纹匹配器
15 - [x] HybridEngine
16 - [x] 最小训练入口
17 - [x] 最小识别入口
18 - [x] 文档补全
19
20 ### 验收标准
21 - 能生成数据
22 - 能训练至少 1 epoch
23 - 能建立 reference 索引
24 - 能对测试片段输出 Top-K 候选
25
26 ---
27
28 ## Phase 1:研究验证
29
30 ### 目标
31 验证不同场景下识别效果是否可接受。
32
33 ### 任务
34 - [ ] 增加 top-1 / top-5 / MRR 评估脚本
35 - [ ] 对 clean / noisy / stretched / pitch-shifted 分开评测
36 - [ ] 增加 query-by-humming 专项评测集
37 - [ ] 加入更稳健的 negative sampling
38 - [ ] 补充 checkpoint / config versioning
39
40 ---
41
42 ## Phase 2:工程化
43
44 ### 目标
45 把原型升级为可复现实验项目。
46
47 ### 任务
48 - [ ] 增加 `Makefile``justfile`
49 - [ ] 增加 `pytest` 基础测试
50 - [ ] 增加日志与指标记录
51 - [ ] 增加模型导出与加载规范
52 - [ ] 增加 CLI 参数校验
53 - [ ] 增加 Docker 运行方式
54
55 ---
56
57 ## Phase 3:产品化 PoC
58
59 ### 目标
60 提供可被业务方调用的服务接口。
61
62 ### 任务
63 - [ ] FastAPI 服务化
64 - [ ] 上传音频并返回候选歌曲
65 - [ ] 曲库增量入库命令
66 - [ ] 元数据管理接口
67 - [ ] 结果缓存与批量检索
68
69 ---
70
71 ## Phase 4:大规模检索
72
73 ### 目标
74 支持百万级以上曲库。
75
76 ### 任务
77 - [ ] 接入 Faiss / HNSW
78 - [ ] embedding 分片与压缩
79 - [ ] 双层召回 + 精排
80 - [ ] 在线索引更新
81 - [ ] 冷热分层存储
82
83 ---
84
85 ## Phase 5:真实业务能力
86
87 ### 目标
88 逼近真实听歌识曲产品。
89
90 ### 任务
91 - [ ] 真实版权音频数据接入
92 - [ ] 哼唱专项模型/旋律塔
93 - [ ] 多模态融合(旋律 + 声纹 + 指纹)
94 - [ ] 在线 A/B 评估
95 - [ ] 监控与质量回流
...@@ -5,267 +5,204 @@ ...@@ -5,267 +5,204 @@
5 > 1. 当前项目已经走到哪里 5 > 1. 当前项目已经走到哪里
6 > 2. 应该先读哪些文档 6 > 2. 应该先读哪些文档
7 > 3. 应该从哪一步开始推进 7 > 3. 应该从哪一步开始推进
8 > 4. 哪些是当前稳定结论,哪些还只是待验证假设 8 > 4. 哪些是稳定结论,哪些还是待验证缺口
9 9
10 --- 10 ---
11 11
12 ## 首选启动流程(最短路径) 12 ## 0. 下次启动先做什么
13 13
14 下次启动如果目标是“先判断当前 host 能不能继续推进 Phase-1”,不要先手工翻很多文档,先直接跑 14 先执行
15 15
16 ```bash 16 ```bash
17 cd /workspace/acr-engine 17 cd /workspace/acr-engine
18 /usr/local/miniconda3/bin/python scripts/run_planner_validation_commands_live.py --dsn 'postgres://d2:d2pass@127.0.0.1:5432/d2' --output data/pgvector_eval/music20/planner_validation_commands_runner_report.json 18 /usr/local/miniconda3/bin/python scripts/run_planner_validation_commands_live.py \
19 --dsn 'postgres://d2:d2pass@127.0.0.1:5432/d2' \
20 --output data/pgvector_eval/music20/planner_validation_commands_runner_report.json
19 ``` 21 ```
20 22
21 当前这条命令的 fresh evidence 已有: 23 也可以用包装脚本:`acr-engine/scripts/start_phase1_shortest_path.sh 'postgres://d2:d2pass@127.0.0.1:5432/d2'`
22 24
25 当前 fresh evidence:
23 - `executed_count = 4` 26 - `executed_count = 4`
24 - `all_passed = true` 27 - `all_passed = true`
25 28
26 它会一次性执行: 29 这条 runner 会一次性执行:
27
28 1. `prereq_audit` 30 1. `prereq_audit`
29 2. `worker_contract_smoke` 31 2. `worker_contract_smoke`
30 3. `semantic_vector_negative_matrix` 32 3. `semantic_vector_negative_matrix`
31 4. `asset_level_upsert_validation` 33 4. `asset_level_upsert_validation`
32 34
33 ### 跑完之后怎么判断 35 如果结果仍是:
34
35 如果结果仍是当前状态:
36 - `downloads_root_exists = false` 36 - `downloads_root_exists = false`
37 - `ready_jobs = 0` 37 - `ready_jobs = 0`
38 - exact = `failed/unreadable_audio_assets` 38 - exact = `failed/unreadable_audio_assets`
39 - semantic = `4/4 failed` 39 - semantic = `4/4 failed`
40 40
41 那么说明: 41 则说明当前优先级仍然是:
42 42 1.`/workspace/downloads` 挂载
43 > 当前不该继续怀疑 PostgreSQL contract,而应该优先解决 **音频挂载** 与 **模型 runtime 依赖**。 43 2.`torch / torchaudio / transformers / speechbrain`
44
45 如果未来这条 runner 开始失败,才优先检查:
46 - planner 报告是否变了
47 - validation scripts 是否回归
48 - schema / worker contract 是否被破坏
49
50 ## 一页结论
51
52 当前项目主线已经从“原型是否能跑通”切到:
53
54 > **为版权保护场景建设一个可演进的音乐 ACR / 检索系统**,
55 > 目标是让 `100w` 音频、约 `30w` 歌曲能够在未来通过
56 > `canonical_song / work / recording / recording_asset / audio_window`
57 > 这条主数据链,以及 `model_registry / feature_set_registry`
58 > 这套模型注册机制,稳定支撑检索、归属、升级与回滚。
59
60 当前已经完成的关键交付:
61 - 文档体系已重构为“角色化阅读路径”
62 - SOTA 演进路径已明确:**Phase-1 先走 encoder-only**
63 - PostgreSQL 主数据与特征注册 DDL 已落地为推荐版 schema
64 - Phase-1 实施 checklist 和 model/feature/reference set 初始化手册已补齐
65 - `acr_test` schema 上已经真实完成 Phase-1 `model_registry / feature_set_registry / reference_set_registry` bootstrap 验证
66 44
67 当前最重要的下一步不是继续写方案,而是: 45 而不是回头怀疑 PostgreSQL contract。
68
69 1. **按 schema v2 落 PostgreSQL 主数据模型**
70 2. **把 reference set / audio_window / feature_set 初始化做起来**
71 3. **接入 MERT / MuQ 的 encoder-only 抽特征链**
72 4. **跑通 fingerprint lane + semantic lane 的第一版聚合闭环**
73 46
74 --- 47 ---
75 48
76 ## 下次启动先读什么 49 ## 1. 当前项目一句话状态
77 50
78 ### 最短阅读顺序(推荐) 51 项目已经从“原型能否跑通”转为:
79 1. [docs/README.md](./README.md)
80 2. [docs/acr-architecture.md](./acr-architecture.md)
81 3. [docs/sota-evolution-guide.md](./sota-evolution-guide.md)
82 4. [docs/postgresql-data-model.md](./postgresql-data-model.md)
83 5. [docs/phase1-implementation-checklist.md](./phase1-implementation-checklist.md)
84 6. [docs/model-feature-registry-bootstrap.md](./model-feature-registry-bootstrap.md)
85 7. [docs/phase1-worker-contract.md](./phase1-worker-contract.md)
86 8. [docs/CHANGELOG.md](./CHANGELOG.md)
87 52
88 如果只想快速恢复上下文,至少读前 5 个。 53 > **面向版权保护 / 听歌识曲 / 版本归属的可演进音乐 ACR 系统。**
89 54
90 --- 55 当前目标是让 `100w` 音频、约 `30w` 歌曲能通过稳定的数据主链和模型注册机制,支撑检索、归属、升级与回滚。
91 56
92 ## 当前稳定结论(可以直接继承) 57 ---
93 58
94 ### 1. 技术方向 59 ## 2. 当前稳定结论
95 - **当前 ECAPA 路线保留为 baseline,不再作为长期主底座。**
96 - **Phase-1 主推 encoder-only foundation 路线。**
97 - exact lane:`Chromaprint`
98 - semantic lane 主 baseline:`MERT-v1-95M`
99 - semantic lane challenger:`MuQ`
100 - **Phase-2 才考虑 version / cover lane。**
101 - **Phase-3 再进入工业化检索/重排/治理。**
102 60
103 ### 2. 数据主链 61 ### 技术路线
104 后续主数据一律围绕: 62 - exact lane:`Chromaprint`
63 - semantic baseline:`MERT-v1-95M`
64 - semantic challenger:`MuQ`
65 - `ECAPA`:historical baseline
66 - Phase-1:先走 **encoder-only**,先不用微调底座
105 67
68 ### 数据主链
106 ```text 69 ```text
107 canonical_song -> work -> recording -> recording_asset -> audio_window 70 canonical_song -> work -> recording -> recording_asset -> audio_window
108 ``` 71 ```
109 72
110 不要再退回到仅有 `song_id` 的扁平结构。 73 ### 模型主链
111
112 ### 3. 模型/特征主链
113 后续 encoder、feature、索引一律围绕:
114
115 ```text 74 ```text
116 model_registry -> feature_set_registry -> audio_embedding / audio_fingerprint -> retrieval_index_registry 75 model_registry -> feature_set_registry -> audio_embedding / audio_fingerprint -> retrieval_index_registry
117 ``` 76 ```
118 77
119 不要设计成固定列: 78 ### reference set 结论
120 - `mert_embedding` 79 - 保留 `is_reference=true`
121 - `muq_embedding` 80 - 但生产切换必须依赖 `reference_set_registry / reference_set_member`
122 - `ecapa_embedding` 81 - 后续 A/B、热切换、回滚都围绕 reference set 版本化进行
123
124 ### 4. reference 集合
125 当前结论是:
126 - 需要显式 `reference_set_registry`
127 - `is_reference=true` 仍然保留,但不再足够表达生产切换
128 - 未来热 reference 集、A/B、回滚、encoder 升级都要依赖 reference set 版本化
129 82
130 --- 83 ---
131 84
132 ## 本轮新增/修改的关键文件 85 ## 3. 当前已经完成的关键交付
133 86
134 ### 主文档 87 ### 文档与设计
135 - [docs/README.md](./README.md) 88 - 文档主入口已收敛到 `README -> start-here -> session-handoff`
136 - [docs/acr-architecture.md](./acr-architecture.md) 89 - SOTA 演进路径已明确
137 - [docs/sota-evolution-guide.md](./sota-evolution-guide.md) 90 - PostgreSQL 主数据与特征模型已固定为 v2 推荐方案
138 - [docs/postgresql-data-model.md](./postgresql-data-model.md) 91 - Phase-1 实施 checklist / registry bootstrap / worker contract 文档已齐备
139 - [docs/phase1-implementation-checklist.md](./phase1-implementation-checklist.md)
140 - [docs/model-feature-registry-bootstrap.md](./model-feature-registry-bootstrap.md)
141 92
142 ### SQL / schema 93 ### PostgreSQL / live contract
143 - `acr-engine/sql/acr_pg_schema_v2.sql` 94 - `acr-engine/sql/acr_pg_schema_v2.sql` 已落地
95 - `model_registry / feature_set_registry / reference_set_registry` 已 live bootstrap 验证
96 - `audio_embedding` 的 asset-level 幂等 upsert 已 live 验证
97 - semantic vector-table 负例矩阵已 live 验证
98 - planner validation commands 已可被 runner 一键执行
144 99
145 ### 历史/补充说明(仍有参考价值) 100 ### worker / script
146 - [docs/sota-research-2026.md](./sota-research-2026.md) 101 - `run_chromaprint_job.py` 已具备真实写入路径
147 - [docs/production-encoder-freeze-and-embedding-strategy.md](./production-encoder-freeze-and-embedding-strategy.md) 102 - `run_embedding_job.py` 已具备 preflight failure contract
148 - [docs/training-data-and-pgvector-guide.md](./training-data-and-pgvector-guide.md) 103 - `run_phase1_prereq_audit_live.py` 已能输出 host 前置条件审计
104 - `run_planner_validation_commands_live.py` 已收敛最短验证链路
149 105
150 --- 106 ---
151 107
152 ## 当前推荐的启动动作 108 ## 4. 当前明确的 blocker
153
154 ## 路线 A:如果下次 session 继续“补文档/补设计”
155 优先顺序:
156 1.**数据导入手册**:100w 音频如何映射到 `canonical_song/work/recording/recording_asset`
157 2.**检索聚合设计文档**:fingerprint lane + semantic lane 的分数融合与 song/work 聚合规则
158 3.**索引与版本治理文档**:reference set / feature set / index set 的上线切换规则
159
160 ## 路线 B:如果下次 session 开始“进入实现”
161 直接按下面顺序推进:
162 1. 建库执行 `acr-engine/sql/acr_pg_schema_v2.sql`
163 2. 初始化 `canonical_song / work / recording / recording_asset`
164 3. 初始化 `reference_set_registry`
165 4. 生成 `audio_window`
166 5. 初始化 `model_registry / feature_set_registry`
167 6. 接入 MERT / MuQ encoder-only 抽特征
168 7. 构建 semantic index
169 8. 跑通 query -> candidate -> canonical_song 闭环
170 109
171 --- 110 ### 环境 blocker
111 - `/workspace/downloads` 缺失
112 - 缺少 `torch`
113 - 缺少 `torchaudio`
114 - 缺少 `transformers`
115 - 缺少 `speechbrain`
172 116
173 ## 下次 session 第一条可直接复制执行的检查命令 117 ### 能力 blocker
118 - 还未真实跑通 `MERT / MuQ` inference
119 - 还未完成线上融合策略
120 - 还未接入更大规模真实 reference set
174 121
175 ```bash 122 因此当前最该优先推进的是:
176 cd /workspace 123 > **把环境补齐,再把 semantic lane 从 guarded failure 推到真实抽特征。**
177 sed -n '1,220p' docs/README.md 124
178 sed -n '1,260p' docs/phase1-implementation-checklist.md 125 ---
179 sed -n '1,260p' docs/model-feature-registry-bootstrap.md
180 sed -n '1,260p' docs/postgresql-data-model.md
181 ```
182 126
183 如果要直接看 schema: 127 ## 5. 下次启动先读什么
184 128
185 ```bash 129 按这个顺序即可:
186 cd /workspace 130 1. [README.md](./README.md)
187 sed -n '1,320p' acr-engine/sql/acr_pg_schema_v2.sql 131 2. [start-here.md](./start-here.md)
188 ``` 132 3. [acr-architecture.md](./acr-architecture.md)
133 4. [postgresql-data-model.md](./postgresql-data-model.md)
134 5. [phase1-implementation-checklist.md](./phase1-implementation-checklist.md)
135 6. [model-feature-registry-bootstrap.md](./model-feature-registry-bootstrap.md)
136 7. [phase1-worker-contract.md](./phase1-worker-contract.md)
137 8. [CHANGELOG.md](./CHANGELOG.md)
189 138
190 --- 139 ---
191 140
192 ## 当前实现与未来实现的边界 141 ## 6. 下次启动优先动作
193
194 ### 当前仓库已经有的东西
195 - `Chromaprint` 原型链
196 - `ECAPA` embedding baseline
197 - hybrid engine 原型
198 - 早期 pgvector prototype schema
199 142
200 ### 当前还没做完的东西 143 ### 路线 A:继续环境恢复
201 - PostgreSQL v2 schema 的实际落库 144 1. 检查 `/workspace/downloads` 是否已挂载
202 - Phase-1 的 reference set 初始化 145 2. 检查 `torch / torchaudio / transformers / speechbrain` 是否已可导入
203 - MERT / MuQ encoder-only 特征抽取与入库 146 3. 重跑 planner validation runner
204 - semantic lane 的第一版 production-oriented 聚合 147 4. 确认 `ready_jobs` 是否从 `0` 开始提升
205 148
206 所以: 149 ### 路线 B:继续语义特征抽取实现
150 1. 查看 `acr-engine/workers/run_embedding_job.py`
151 2. 保持现有失败语义 contract
152 3. 接入真实 inference adapter
153 4. 复用现有 `audio_embedding` upsert 逻辑
207 154
208 > 当前项目的“方案层”已经足够启动实现, 155 ### 路线 C:继续数据规模化落库
209 > 下次 session 不应再从头讨论“要不要 song/work/recording”, 156 1. 查看 [postgresql-data-model.md](./postgresql-data-model.md)
210 > 而应该直接进入 **Schema -> Reference Set -> Feature Set -> Extraction -> Retrieval** 的执行链。 157 2. 查看 [postgres_db_schema_samples.md](./postgres_db_schema_samples.md)
158 3. 规划 100w 音频导入批次
159 4. 固定 `reference_set` / `feature_set` / `index` 版本治理
211 160
212 --- 161 ---
213 162
214 ## 当前验证状态 163 ## 7. 当前不要再重复讨论的结论
215 164
216 ### 已验证 165 - 不要回退到只有 `song_id` 的扁平表
217 - 新文档结构已补齐并接入 README 166 - 不要把 embedding 设计成固定列
218 - Phase-1 方案、PostgreSQL 设计、实施 checklist、registry bootstrap 均已提交 167 - 不要在 Phase-1 先讨论重新训练底座
219 - architect 审核结论:**APPROVED** 168 - 不要把当前问题误判成 PostgreSQL schema 问题
220 - 代码已推送远端
221 - PostgreSQL `acr_test` live 路径已再次验证:`recording` / `audio_window` / `audio_embedding` 三类 lineage trigger 均有真实负例证据
222 - 机械校验已补齐:`live_pgvector_music20_eval.py``py_compile` 通过,相关变更 `diff --check` 通过
223 - PostgreSQL `acr_test` schema 上已真实写入 Phase-1 registry bootstrap:`chromaprint / mert / muq / ecapa` + 5 组 feature set + `phase1_hot_reference_v1`
224 - Phase-1 registry bootstrap 已有幂等性证据:同 schema 连续执行两次后,`model_registry=5 / feature_set_registry=6 / reference_set_registry=2` 保持不变
225 - PostgreSQL `acr_test` schema 上已真实创建 5 条 `feature_extraction_job`,后续 MERT / MuQ 接入可直接从 pending jobs 启动
226 - PostgreSQL `acr_test` schema 上已真实生成 Phase-1 extraction execution plan,当前顺序是 `chromaprint -> mert -> mert-long -> muq -> ecapa`
227 - extraction plan 报告里已包含 `command_suggestions / primary_command`,下次可直接从 plan 抄 worker 命令模板
228 - Phase-1 worker 入口已真实落地:`run_chromaprint_job.py / run_embedding_job.py / mark_job_status.py`
229 - 下一阶段已经不是“补 planner”,而是把 dry-run worker 替换为真实 extractor,并把 `audio_fingerprint / audio_embedding` 写入做成幂等执行
230 - semantic lane 也已完成 live failure contract:`run_embedding_job.py` 现在会同时暴露 `unreadable_audio_assets``model_runtime_unavailable`,而不是把失败伪装成 completed
231 - `audio_embedding` 已补上 window / asset 双路唯一键,后续真实 encoder 只需替换 inference adapter 即可复用同一 upsert 合同
232 - `scripts/run_phase1_embedding_preflight_matrix_live.py` 已跑通,4 条 semantic jobs(mert/muq/ecapa)在 `acr_test` 上都被稳定标记为 `preflight_failed`;当前共性 blocker 已收敛为 `/workspace/downloads` 缺失 + 语义模型 runtime 缺失
233 - `scripts/validate_audio_embedding_asset_upsert_live.py` 已在隔离 schema `acr_asset_upsert_test` 上验证 `uq_audio_embedding_feature_asset`:重复 insert 会被唯一键拒绝,upsert 会复用同一 `embedding_id`,说明 asset-level 幂等键也已有真实证据
234 - `scripts/run_phase1_worker_contract_smoke_live.py` 已提供一条命令的全局 smoke:当前 exact lane = `failed/unreadable_audio_assets`,semantic lane = `4/4 failed`,共性 blocker 已固化为音频挂载缺失 + 语义模型 runtime 缺失
235 - `scripts/run_embedding_vector_table_negative_matrix_live.py` 已在 live PostgreSQL 上补齐 semantic vector-table 负例矩阵:`vector_table_dim_mismatch``vector_table_not_allowlisted``vector_table_missing_in_schema` 三类错误都能被稳定写入 `vector_table_report.reason`
236 - `scripts/run_phase1_prereq_audit_live.py` 已给出当前 host 的先决条件审计:`downloads_root_exists=false``ready_jobs=0/5`,并把 `torch/torchaudio/transformers/speechbrain` 的缺失状态按 job 落成 JSON 报告
237 - `phase1_extraction_plan_report.json` 现已附带 `validation_commands`,下次 session 可以直接从 planner 复制 `prereq_audit / worker_contract_smoke / semantic_vector_negative_matrix / asset_level_upsert_validation` 四类命令
238 - `phase1_validation_commands_execution_report.json` 已证明 planner 里的 4 条 validation commands 都可以被直接脚本消费且 `returncode=0``prereq_audit``worker_contract_smoke``semantic_vector_negative_matrix``asset_level_upsert_validation`
239 - `scripts/run_planner_validation_commands_live.py` 已把这 4 条 validation commands 收敛成通用 runner;当前 `planner_validation_commands_runner_report.json` 显示 `executed_count=4``all_passed=true`
240 - `phase1_hot_reference_v1``acr_test` 里已经真实补齐 `20` 个 reference members,因此 worker dry-run 当前看到的 scope 已是 `20 recordings / 20 assets / 20 windows`
241 - worker contract 现在已有基础前置状态保护;重复执行同一 chromaprint dry-run job 会被 `expected_status=pending` 明确拒绝,证据见 `phase1_worker_double_claim_guard_report.json`
242 - exact lane 的 `run_chromaprint_job.py` 已具备非 dry-run 写入路径;当前在 `acr_test` 的 live 结果是因为 `/workspace/downloads/...` 缺失而明确 `failed`,不是继续假装 `completed`
243
244 ### 未验证 / 仍是缺口
245 - **未实际跑 MERT / MuQ encoder-only 特征抽取**
246 - **semantic / cover 等后续 lane 仍主要停留在 dry-run;exact lane 已接上真实 `audio_fingerprint` 写入路径,但当前容器缺 reference 音频挂载,live 结果仍停在可审计失败**
247 - **还未落更大规模的生产 reference set 真实业务数据(当前仅验证了 `acr_test` 下的 20-song live members)**
248 - **未定义最终线上分数融合细则**
249 - **type_8 / type_16 还没有进入当前 live JSONL 的 PostgreSQL 实测链**
250 - **当前容器里缺少 `/workspace/downloads`,因此暂时无法直接从业务样本目录继续补 type_8 / type_16 live query**
251
252 因此下次 session 应优先从这些未验证缺口里挑一条推进,而不是重复写总方案。
253 169
254 --- 170 ---
255 171
256 ## 最近相关提交 172 ## 8. 关键文件入口
173
174 ### 文档
175 - [README.md](./README.md)
176 - [start-here.md](./start-here.md)
177 - [postgresql-data-model.md](./postgresql-data-model.md)
178 - [phase1-worker-contract.md](./phase1-worker-contract.md)
257 179
258 按当前 handoff 相关主线,最近重要提交是: 180 ### 代码与脚本
259 - `a549d1d` — Clarify the ACR evolution path and freeze a production-grade data model 181 - `acr-engine/sql/acr_pg_schema_v2.sql`
260 - `e514a6c` — Keep the new ACR architecture guide clean for follow-up edits 182 - `acr-engine/workers/run_chromaprint_job.py`
261 - `4b23f54` — Make the Phase-1 ACR plan executable for each delivery role 183 - `acr-engine/workers/run_embedding_job.py`
262 - `0679481` — Attach runnable command templates to the extraction plan 184 - `acr-engine/scripts/run_planner_validation_commands_live.py`
185 - `acr-engine/scripts/run_phase1_prereq_audit_live.py`
263 186
264 如果下次需要追踪文档补充点,可以从这三个提交开始看。 187 ---
188
189 ## 9. 当前验证状态摘要
190
191 ### 已验证
192 - planner validation runner 可执行且 `all_passed = true`
193 - exact lane 当前会诚实落成 `failed/unreadable_audio_assets`
194 - semantic lane 当前会诚实落成 `preflight_failed`
195 - asset-level embedding upsert 幂等合同已验证
196 - vector table 负例矩阵已验证
197 - prerequisites audit 已验证
198
199 ### 未验证
200 - MERT / MuQ 真实 inference
201 - 更大规模生产 reference set 导入
202 - 最终线上融合与重排策略
265 203
266 --- 204 ---
267 205
268 ## 一句话交接 206 ## 一句话 handoff
269 207
270 > **下次启动不要再从“要不要换模型、要不要重构数据结构”开始讨论。** 208 > 下次接手不要再从总方案开始,先跑 runner;若结果仍显示 downloads/runtime 缺失,就优先补环境,再推进 semantic lane 真实抽特征。
271 > 这些方向已经定了。直接从 **PostgreSQL v2 schema 落库 + Phase-1 worker/extractor 执行链** 开始推进。
......
1 # Start Here / 新同学接手入口
2
3 > 目标:让新来的同学在 **10 分钟内**知道:先跑什么、先读什么、当前卡在哪、下一步该做什么。
4
5 ---
6
7 ## 1. 先执行这条命令
8
9 ```bash
10 cd /workspace/acr-engine
11 /usr/local/miniconda3/bin/python scripts/run_planner_validation_commands_live.py \
12 --dsn 'postgres://d2:d2pass@127.0.0.1:5432/d2' \
13 --output data/pgvector_eval/music20/planner_validation_commands_runner_report.json
14 ```
15
16 也可以用包装脚本:`acr-engine/scripts/start_phase1_shortest_path.sh 'postgres://d2:d2pass@127.0.0.1:5432/d2'`
17
18 ### 当前 fresh evidence
19 - `executed_count = 4`
20 - `all_passed = true`
21
22 ### 这条命令会执行
23 1. `prereq_audit`
24 2. `worker_contract_smoke`
25 3. `semantic_vector_negative_matrix`
26 4. `asset_level_upsert_validation`
27
28 ### 看到下面这些结果时应该如何判断
29 如果你看到:
30 - `downloads_root_exists = false`
31 - `ready_jobs = 0`
32 - exact lane = `failed/unreadable_audio_assets`
33 - semantic lane = `4/4 failed`
34
35 说明当前优先级是:
36 1. 挂载 `/workspace/downloads`
37 2. 安装 `torch / torchaudio / transformers / speechbrain`
38
39 也就是说:
40 > 当前首要问题是运行环境前置条件,不是 PostgreSQL schema,也不是 worker contract 设计错误。
41
42 ---
43
44 ## 2. 接手时只读这 5 份文档
45
46 1. [README.md](./README.md)
47 2. [session-handoff.md](./session-handoff.md)
48 3. [acr-architecture.md](./acr-architecture.md)
49 4. [postgresql-data-model.md](./postgresql-data-model.md)
50 5. [phase1-implementation-checklist.md](./phase1-implementation-checklist.md)
51
52 如果你负责算法或检索,再补:
53 - [sota-evolution-guide.md](./sota-evolution-guide.md)
54 - [model-feature-registry-bootstrap.md](./model-feature-registry-bootstrap.md)
55 - [phase1-worker-contract.md](./phase1-worker-contract.md)
56
57 ---
58
59 ## 3. 用一句话理解项目
60
61 我们在做的是一个面向 **版权保护 / 听歌识曲 / 版本归属** 的音乐 ACR 系统,
62 目标是从 `100w` 音频、约 `30w` 歌曲中,快速定位正确的 `song_id / work / recording` 归属。
63
64 ---
65
66 ## 4. 当前主线方案
67
68 ### 检索主线
69 - exact lane:`Chromaprint`
70 - semantic lane baseline:`MERT-v1-95M`
71 - semantic lane challenger:`MuQ`
72 - historical baseline:`ECAPA`
73
74 ### 数据主线
75 ```text
76 canonical_song -> work -> recording -> recording_asset -> audio_window
77 ```
78
79 ### 模型主线
80 ```text
81 model_registry -> feature_set_registry -> audio_embedding / audio_fingerprint -> retrieval_index_registry
82 ```
83
84 ---
85
86 ## 5. 当前哪些已经稳定
87
88 - PostgreSQL v2 schema 已落地
89 - registry bootstrap 已有 live 验证
90 - worker contract 已有 live 验证
91 - exact / semantic 的失败语义已可审计
92 - planner 已能输出 validation commands
93 - planner validation runner 已可一键执行
94
95 ## 6. 当前哪些还没完成
96
97 - 还没有真正跑通 MERT / MuQ inference
98 - 当前 host 没有 `/workspace/downloads`
99 - 当前 host 缺 `torch / torchaudio / transformers / speechbrain`
100 - 还没完成最终线上融合策略
101 - 还没接入更大规模真实 reference set
102
103 ---
104
105 ## 7. 如果你现在继续推进,按这个顺序
106
107 ### 路线 A:先解环境
108 1. 挂载 `/workspace/downloads`
109 2. 安装 semantic runtime 依赖
110 3. 重跑 planner validation runner
111 4. 确认 `ready_jobs` 是否开始恢复
112
113 ### 路线 B:先解实现
114 1. 阅读 [phase1-worker-contract.md](./phase1-worker-contract.md)
115 2. 阅读 `acr-engine/workers/run_embedding_job.py`
116 3. 用真实 inference adapter 替换 guarded failure path
117 4. 保持当前 PostgreSQL contract 不变
118
119 ### 路线 C:先解数据
120 1. 阅读 [postgresql-data-model.md](./postgresql-data-model.md)
121 2. 阅读 [postgres_db_schema_samples.md](./postgres_db_schema_samples.md)
122 3. 准备更大的 reference set
123 4. 保持 `reference_set_registry / reference_set_member` 版本化
124
125 ---
126
127 ## 8. 当前不建议优先做的事
128
129 - 不要重新讨论要不要 `song/work/recording` 分层
130 - 不要回退到只有 `song_id` 的扁平表
131 - 不要先讨论重新训练底座
132 - 不要把当前问题误判成 PostgreSQL contract 设计问题
133
134 ---
135
136 ## 9. 仓库常用入口
137
138 ### 文档
139 - [README.md](./README.md)
140 - [session-handoff.md](./session-handoff.md)
141 - [postgresql-data-model.md](./postgresql-data-model.md)
142 - [phase1-worker-contract.md](./phase1-worker-contract.md)
143
144 ### 脚本
145 - `acr-engine/scripts/run_planner_validation_commands_live.py`
146 - `acr-engine/scripts/run_phase1_prereq_audit_live.py`
147 - `acr-engine/scripts/run_phase1_worker_contract_smoke_live.py`
148 - `acr-engine/scripts/run_embedding_vector_table_negative_matrix_live.py`
149 - `acr-engine/scripts/validate_audio_embedding_asset_upsert_live.py`
150
151 ---
152
153 ## 一句话结论
154
155 > 新同学接手时,先跑 runner,再读 5 份核心文档;当前首要问题是环境前置条件,不是 schema/contract 本身。