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
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
PYTHON_BIN="${PYTHON_BIN:-/usr/local/miniconda3/bin/python}"
DSN="${1:-${PG_DSN:-}}"
OUTPUT="${2:-$ROOT_DIR/data/pgvector_eval/music20/planner_validation_commands_runner_report.json}"
if [[ -z "$DSN" ]]; then
echo "usage: $0 <postgres-dsn> [output-json]" >&2
echo "or set PG_DSN before running this script" >&2
exit 1
fi
cd "$ROOT_DIR"
"$PYTHON_BIN" scripts/run_planner_validation_commands_live.py \
--dsn "$DSN" \
--output "$OUTPUT"
## 2026-06-04
- 收敛文档入口链路,新增 `docs/start-here.md`,统一新同学接手路径为:`README -> start-here -> session-handoff`
- 重写 `docs/README.md`,按“接手 / 方案 / 实施 / 运行 / 角色”重组导航,降低首次阅读成本。
- 重构 `docs/session-handoff.md`,把最新 Phase-1 runner、稳定结论、blocker 与下一步动作收口到单页文档。
- 清理重复或过期文档:删除 `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`
- 历史记录仍保留在 `docs/CHANGELOG.md`,当前有效入口以上述主链为准。
## 2026-06-04
- 更新 `docs/README.md` 顶部为与 `session-handoff` 一致的“最短启动路径”,并再次用该入口命令重跑 `run_planner_validation_commands_live.py`,确认 fresh 结果仍为 `executed_count=4``all_passed=true`
- 重构 `docs/session-handoff.md` 顶部为“首选启动流程(最短路径)”,直接给出 `run_planner_validation_commands_live.py` 的一条启动命令,以及基于 fresh runner 报告(`executed_count=4`, `all_passed=true`)的结果判断逻辑,减少下次 session 的恢复成本。
- 新增 `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`
......
# ACR Docs Overview
> 面向“版权保护 / 听歌识曲 / 版本归属”的音乐 ACR 文档入口。默认先看主路径,历史细节文档作为补充材料保留
> 面向“版权保护 / 听歌识曲 / 版本归属”的音乐 ACR 文档总入口
## 最短启动路径(推荐)
---
## 0. 新同学先做什么
如果下次启动的目标是:**先判断当前 host 能不能继续推进 Phase-1**,不要先手工翻很多文档,先直接跑:
### 先跑,不要先读一堆文档
```bash
cd /workspace/acr-engine
/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
/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
```
当前这条命令的 fresh evidence 已有:
也可以用包装脚本:`acr-engine/scripts/start_phase1_shortest_path.sh 'postgres://d2:d2pass@127.0.0.1:5432/d2'`
当前 fresh evidence:
- `executed_count = 4`
- `all_passed = true`
它会一次性执行:
1. `prereq_audit`
2. `worker_contract_smoke`
3. `semantic_vector_negative_matrix`
4. `asset_level_upsert_validation`
如果结果仍是:
- `downloads_root_exists = false`
- `ready_jobs = 0`
- exact = `failed/unreadable_audio_assets`
- semantic = `4/4 failed`
### 再按这条阅读链路走
1. [start-here.md](./start-here.md)
2. [session-handoff.md](./session-handoff.md)
3. [acr-architecture.md](./acr-architecture.md)
4. [postgresql-data-model.md](./postgresql-data-model.md)
5. [phase1-implementation-checklist.md](./phase1-implementation-checklist.md)
那么说明当前优先级应该是:
---
1. 解决 `/workspace/downloads` 挂载
2. 安装语义模型 runtime 依赖
## 1. 文档总导航
而不是继续怀疑 PostgreSQL contract。
### A. 接手项目 / 恢复上下文
- [start-here.md](./start-here.md) — 新同学 10 分钟接手入口
- [session-handoff.md](./session-handoff.md) — 当前状态、阻塞、下一步
- [CHANGELOG.md](./CHANGELOG.md) — 变更记录
## 一页结论
### B. 系统方案 / 设计主线
- [acr-architecture.md](./acr-architecture.md) — 总体架构与分层
- [sota-evolution-guide.md](./sota-evolution-guide.md) — SOTA 演进路径
- [postgresql-data-model.md](./postgresql-data-model.md) — PostgreSQL 主数据/特征模型
- [production-encoder-freeze-and-embedding-strategy.md](./production-encoder-freeze-and-embedding-strategy.md) — encoder-only 冻结策略
当前项目已经从“原型是否能跑通”转向“**如何把 100w 音频 / 30w 歌曲做成可演进的版权检索系统**”。
默认阅读顺序不再按“训练脚本 -> demo”,而按:
### C. 第一个阶段怎么落地
- [phase1-implementation-checklist.md](./phase1-implementation-checklist.md) — Phase-1 执行清单
- [model-feature-registry-bootstrap.md](./model-feature-registry-bootstrap.md) — model/feature/reference set 初始化
- [phase1-worker-contract.md](./phase1-worker-contract.md) — worker、job、失败语义合同
- [postgres_db_schema_samples.md](./postgres_db_schema_samples.md) — PostgreSQL 存储样例
1. **系统蓝图**:当前系统是什么、未来要演进成什么
2. **SOTA 演进**:Phase-1 不微调底座时怎么做,后面如何升级
3. **PostgreSQL 数据模型**:资产、窗口、特征、索引、匹配结果如何落盘
4. **现有实现对照**:当前仓库代码和文档分别在哪
### D. 运行 / 服务 / 数据治理
- [runbook.md](./runbook.md) — 运维/运行手册
- [service-api.md](./service-api.md) — 服务 API
- [training-data-and-pgvector-guide.md](./training-data-and-pgvector-guide.md) — 训练/向量检索说明
- [open-dataset-workflow.md](./open-dataset-workflow.md) — 开源数据接入流程
---
## 主阅读路径(推荐)
## 2. 按角色阅读
### 1. 管理 / 架构 / 跨团队负责人
1. [acr-architecture.md](./acr-architecture.md)
2. [sota-evolution-guide.md](./sota-evolution-guide.md)
3. [postgresql-data-model.md](./postgresql-data-model.md)
4. [phase1-implementation-checklist.md](./phase1-implementation-checklist.md)
5. [session-handoff.md](./session-handoff.md)
### 产品 / 业务 / 版权策略
1. [start-here.md](./start-here.md)
2. [acr-architecture.md](./acr-architecture.md)
3. [project-responsibility-map.md](./project-responsibility-map.md)
4. [business-export-cookbook.md](./business-export-cookbook.md)
### 2. 开发 / 数据 / 检索工程师
### 数据 / 平台 / PostgreSQL
1. [postgresql-data-model.md](./postgresql-data-model.md)
2. [phase1-implementation-checklist.md](./phase1-implementation-checklist.md)
3. [model-feature-registry-bootstrap.md](./model-feature-registry-bootstrap.md)
4. [training-data-and-pgvector-guide.md](./training-data-and-pgvector-guide.md)
5. [acr-architecture.md](./acr-architecture.md)
6. [runbook.md](./runbook.md)
### 3. 运维 / 平台 / 服务工程师
1. [acr-architecture.md](./acr-architecture.md)
2. [postgresql-data-model.md](./postgresql-data-model.md)
3. [phase1-implementation-checklist.md](./phase1-implementation-checklist.md)
4. [service-api.md](./service-api.md)
5. [runbook.md](./runbook.md)
### 4. 模型 / 底座 / 研究工程师
1. [sota-research-2026.md](./sota-research-2026.md)
2. [sota-evolution-guide.md](./sota-evolution-guide.md)
2. [postgres_db_schema_samples.md](./postgres_db_schema_samples.md)
3. [model-feature-registry-bootstrap.md](./model-feature-registry-bootstrap.md)
4. [production-encoder-freeze-and-embedding-strategy.md](./production-encoder-freeze-and-embedding-strategy.md)
5. [training-data-and-pgvector-guide.md](./training-data-and-pgvector-guide.md)
---
4. [runbook.md](./runbook.md)
## 新的核心文档分工
### 算法 / 检索 / 模型
1. [sota-evolution-guide.md](./sota-evolution-guide.md)
2. [production-encoder-freeze-and-embedding-strategy.md](./production-encoder-freeze-and-embedding-strategy.md)
3. [phase1-worker-contract.md](./phase1-worker-contract.md)
4. [sota-research-2026.md](./sota-research-2026.md)
| 文档 | 作用 | 适合谁先读 |
|---|---|---|
| [acr-architecture.md](./acr-architecture.md) | 当前系统蓝图、角色分工、在线/离线链路 | 架构、开发、运维 |
| [sota-evolution-guide.md](./sota-evolution-guide.md) | SOTA 演进路径、Phase-1 encoder-only 方案、后续升级路线 | 架构、模型、检索 |
| [postgresql-data-model.md](./postgresql-data-model.md) | PostgreSQL 数据字典、DDL 设计意图、流程图、查询路径 | 数据、后端、检索、平台 |
| [postgres_db_schema_samples.md](./postgres_db_schema_samples.md) | PostgreSQL 实际落库样例、live pgvector 测试链路、召回/混淆结果 | 数据、后端、检索、平台 |
| [phase1-implementation-checklist.md](./phase1-implementation-checklist.md) | Phase-1 落地 checklist,按阶段拆执行项 | 架构、开发、平台 |
| [model-feature-registry-bootstrap.md](./model-feature-registry-bootstrap.md) | 模型、feature set、reference set 初始化手册 | 模型、检索、数据 |
| [training-data-and-pgvector-guide.md](./training-data-and-pgvector-guide.md) | 当前训练/manifest/pgvector 原型链说明 | 开发、数据 |
| [session-handoff.md](./session-handoff.md) | 最新状态与续跑上下文 | 新 session 接手人 |
### 开发 / 实施 / 交付
1. [phase1-implementation-checklist.md](./phase1-implementation-checklist.md)
2. [session-handoff.md](./session-handoff.md)
3. [CHANGELOG.md](./CHANGELOG.md)
4. [release-checklist.md](./release-checklist.md)
---
## 当前实现与未来目标的关系
## 3. 当前最重要的稳定结论
```mermaid
flowchart LR
A[当前实现\nChromaprint + ECAPA + Melody Rerank] --> B[Phase-1\nEncoder-only Foundation Backbone]
B --> C[Phase-2\nVersion/Cover Lane + Better Aggregation]
C --> D[Phase-3\nIndustrial Retrieval + Reranker + Governance]
- 目标场景不是普通歌曲推荐,而是 **版权保护 / 听歌识曲 / 版本归属**
- Phase-1 先走 **encoder-only** 路线,不先微调底座。
- exact lane:`Chromaprint`
- semantic baseline:`MERT-v1-95M`
- semantic challenger:`MuQ`
- `ECAPA` 保留为 historical baseline,不再作为长期主底座。
- PostgreSQL 主链固定为:
```text
canonical_song -> work -> recording -> recording_asset -> audio_window
```
- **当前实现** 已验证基础链路可运行。
- **Phase-1** 目标是:不微调底座,直接上更强开源 encoder,并把 PostgreSQL 数据规范先落稳。
- **Phase-2** 目标是:增强 version / cover / hard-case 归属能力。
- **Phase-3** 目标是:多索引、多角色协作、数据治理、服务化上线。
- 模型/特征主链固定为:
```text
model_registry -> feature_set_registry -> audio_embedding / audio_fingerprint -> retrieval_index_registry
```
---
## 现有实现入口
## 4. 当前不要浪费时间的方向
### 代码入口
- `acr-engine/src/engines/chromaprint_matcher.py`
- `acr-engine/src/engines/ecapa_embedder.py`
- `acr-engine/src/engines/hybrid_engine.py`
- `acr-engine/src/service/app.py`
- `acr-engine/sql/pgvector_schema.sql`(原型版)
- `acr-engine/sql/acr_pg_schema_v2.sql`(本轮新增的推荐版)
### 历史/补充文档
- [sota-research-2026.md](./sota-research-2026.md)
- [production-encoder-freeze-and-embedding-strategy.md](./production-encoder-freeze-and-embedding-strategy.md)
- [project-responsibility-map.md](./project-responsibility-map.md)
- [industrialization-roadmap.md](./industrialization-roadmap.md)
- 不要回退到只用一个 `song_id` 的扁平结构。
- 不要把 embedding 存成固定列(如 `mert_embedding` / `muq_embedding`)。
- 不要在 Phase-1 先讨论重新训练底座。
- 不要把当前阻塞误判成 PostgreSQL schema 问题;当前主要 blocker 是音频挂载与 runtime 依赖。
---
## 如何理解当前文档体系
- **主文档**:优先保证“读完就知道怎么推进”
- **历史文档**:保留实验上下文、旧方案与补充解释
- **SQL 文件**:保证可以直接落地数据库原型
## 5. 补充但不建议作为第一入口
如果你只读 3 份:
1. [acr-architecture.md](./acr-architecture.md)
2. [sota-evolution-guide.md](./sota-evolution-guide.md)
3. [postgresql-data-model.md](./postgresql-data-model.md)
以下文档保留用于专题补充,不建议新同学第一轮就读:
- [dataset-spec.md](./dataset-spec.md)
- [dataset-sources-and-licensing.md](./dataset-sources-and-licensing.md)
- [references-and-sources.md](./references-and-sources.md)
- [current-capability-map.md](./current-capability-map.md)
- [industrialization-roadmap.md](./industrialization-roadmap.md)
- [industrial-benchmark-spec.md](./industrial-benchmark-spec.md)
- [benchmark-report-template.md](./benchmark-report-template.md)
- [model-card-template.md](./model-card-template.md)
- [report-layout.md](./report-layout.md)
......
# Audio Content Recognition (ACR) System — 听歌识曲引擎设计文档
> 版本: v1.0 | 更新: 2026-06-02 | 状态: Draft
---
## 目录
1. [概述与背景](#1-概述与背景)
2. [解决的问题](#2-解决的问题)
3. [技术原理](#3-技术原理)
4. [系统架构设计](#4-系统架构设计)
5. [数据准备与增强](#5-数据准备与增强)
6. [模型设计](#6-模型设计)
7. [训练细节](#7-训练细节)
8. [推理与匹配策略](#8-推理与匹配策略)
9. [使用方法](#9-使用方法)
10. [SOTA 调研与对比](#10-sota-调研与对比)
11. [Roadmap](#11-roadmap)
12. [Checklist](#12-checklist)
13. [Changelog](#13-changelog)
14. [Handoff 交付清单](#14-handoff-交付清单)
15. [参考与引用](#15-参考与引用)
---
## 1. 概述与背景
### 1.1 项目目标
构建一个**音频内容识别(Audio Content Recognition, ACR)引擎**,能够根据一段**BGM(背景音乐)****哼唱(Humming)****录音片段**等音频输入,在歌曲库中快速准确地识别出对应的歌曲。核心能力对标 Shazam、SoundHound、网易云音乐"听歌识曲"等工业级产品。
### 1.2 核心能力
| 能力 | 说明 |
|------|------|
| **BGM 识别** | 输入一段背景音乐,识别原曲 |
| **哼唱识别** (Query-by-Humming) | 输入用户哼唱的旋律,识别匹配的歌曲 |
| **录音片段识别** | 输入现场录音(含环境噪声),匹配库中歌曲 |
| **抗噪鲁棒性** | 在嘈杂环境、低码率、压缩失真下保持准确率 |
| **快速检索** | 亿级曲库下毫秒级响应 |
| **增量扩展** | 歌曲库可动态增加,无需全量重训练 |
### 1.3 命名规范
| 术语 | 含义 |
|------|------|
| **Song / Track** | 库中原始歌曲 |
| **Reference** | 歌曲在库中的指纹/特征表示 |
| **Query** | 用户输入的待识别音频片段 |
| **Fingerprint** | 音频指纹(特征向量或哈希序列) |
| **Landmark** | 频谱图中的峰值点,用于构建指纹 |
| **Candidate** | 匹配候选歌曲列表 |
| **Segment** | 一个Query对应的录音片段或BGM片段 |
---
## 2. 解决的问题
### 2.1 核心问题域
| 问题 | 描述 | 技术挑战 |
|------|------|---------|
| **音频退化** | Query 可能经过压缩(MP3/AAC)、降采样、远场录制 | 特征需对退化具有不变性 |
| **时间截断** | Query 仅为歌曲的中间某一小段(3-15s) | 指纹需支持局部匹配 |
| **哼唱偏差** | 用户哼唱的音高、节奏、音色与原曲不同 | 需旋律归一化与音高轮廓匹配 |
| **环境噪声** | 录音含背景人声、街道噪声、混响 | 特征提取需有一定抗噪性 |
| **速度变化** | Query 播放速度可能快于或慢于原曲(±15%) | 指纹对时间伸缩不敏感 |
| **键位偏移** | Query 的调性可能不同于原曲(哼唱场景常见) | 需相对旋律表示而非绝对音高 |
| **曲库规模** | 曲库可能达到百万至亿级 | 检索必须依赖哈希/近似最近邻索引 |
### 2.2 与现有方案对比
| 维度 | 传统指纹法 (Shazam-like) | 深度学习 embedding 法 (本方案) | 混合方案 |
|------|------------------------|-------------------------------|---------|
| 哼唱识别 | 不支持 | 支持(训练时加入哼唱数据) | 支持 |
| 抗噪性 | 中等 | 高(数据增强可大幅提升) | 高 |
| 检索速度 | 极快(哈希表) | 快(ANN 索引) | 极快 |
| 曲库扩展 | 容易 | 容易(增量索引) | 容易 |
| 硬件要求 | 低 | 中等(需 GPU 训练) | 中等 |
| 调音适应性 | 差 | 好(对比学习可学到不变性) | 好 |
| 时间碎片适应性 | 好 | 好(滑窗机制) | 好 |
---
## 3. 技术原理
### 3.1 音频信号处理基础
#### 3.1.1 短时傅里叶变换 (STFT)
音频信号经 STFT 转化为时频表示:
```
X(t, f) = Σₙ x[n]·w[n-t]·e^{-j2πfn/N}
```
其中 `w[n]` 为窗函数(Hamming/Hann),典型窗长 1024-4096 samples,步长 256-512 samples。
#### 3.1.2 Mel 频谱
将 STFT 的线性频率通过 Mel 滤波器组映射到 Mel 刻度:
```
Mel(f) = 2595 · log₁₀(1 + f/700)
```
得到 Mel 频谱图作为模型的 2D 输入特征。Mel 频谱更符合人耳听觉感知,且对高频噪声有一定抑制作用。
#### 3.1.3 色谱图 (Chroma Feature)
色谱图将频谱能量投影到 12 个半音(C, C#, D, ..., B),对音色和音高变化具有不变性,特别适合哼唱识别。
```
Chroma(t, p) = Σ_{f ∈ pitches_in_class_p} |X(t, f)|²
```
#### 3.1.4 谱峰提取 (Spectral Peaks)
在频谱图中提取能量峰值点(landmarks),每个 landmark 定义为 `(t, f, energy)`。Shazam 算法基于这些 landmark 构建哈希指纹。
#### 3.1.5 哼唱旋律轮廓 (Melody Contour)
对于哼唱输入,使用基频(F0)估计提取旋律轮廓线。常用算法:
- **PYIN** (Probabilistic YIN):基于 YIN 算法的概率改进版
- **CREPE**:基于深度学习的基频估计
- **TorchCREPE**:CREPE 的 PyTorch 实现
旋律轮廓经归一化后得到相对音高序列:`ΔP(t) = P(t) - P(t-1)`
### 3.2 音频指纹技术
#### 3.2.1 传统指纹法 (Shazam Algorithm)
1. 对音频做 STFT 得到频谱图
2. 在时频平面提取能量峰值(landmarks)
3. 对每对 landmark `(f₁, t₁)``(f₂, t₂)` 构建哈希对:
```
hash = (f₁, f₂, Δt) → (t₁, song_id)
```
4. 查询时计算 Query 的 landmarks 和 hashes
5. 在哈希表中找到匹配的歌曲候选
6. 对候选做时间偏移直方图投票,选出最高票歌曲
**优点**:极快、曲库可极大、无需训练
**缺点**:对哼唱、速度变化、调性变化不适应
#### 3.2.2 深度嵌入法 (Deep Embedding) —— 本方案核心
将音频片段映射到一个固定维度的嵌入向量(如 256 维),在嵌入空间中相似歌曲的 Query 和 Reference 距离接近。
**对比学习目标 (Contrastive Learning)**:
```
Loss = -log( exp(sim(q, p)/τ) / Σ_{n=1}^{N} exp(sim(q, n)/τ) )
```
其中 `sim(q, p)` 是 Query 与正样本 Reference 的余弦相似度,`τ` 是温度系数。
**核心优势**:
- 通过对比学习,嵌入对音色、噪声、速度变化、调性变化具有不变性
- 哼唱 Query 可与原曲 Reference 在嵌入空间中对齐
- 支持增量曲库(新歌只需过一次模型生成嵌入)
### 3.3 检索策略
#### 3.3.1 精确检索 (Brute Force)
当库规模 < 10K 时,直接计算 Query 嵌入与所有 Reference 嵌入的余弦相似度。
```
score_i = cosine(query_emb, ref_emb_i)
result = argmax(score_i)
```
#### 3.3.2 近似最近邻检索 (ANN)
当库规模 > 10K 时,使用近似最近邻索引:
| 算法 | 特点 | 适用场景 |
|------|------|---------|
| **IVF** | 倒排文件索引,训练聚类中心 | 百万级 |
| **IVF + PQ** | 乘积量化压缩向量 | 千万级 |
| **HNSW** | 分层导航小世界图 | 亿级,高精度 |
| **DiskANN** | 基于 SSD 的图索引 | 十亿级 |
推荐使用 **Faiss** 库实现 ANN 检索。
#### 3.3.3 级联检索策略
```
Query → 粗筛 (ANN, top-K) → 精排 (余弦相似度) → 时间对齐验证 → Top-1
```
- 粗筛:ANN 检索 Top-50/100 候选
- 精排:计算精确余弦相似度,取 Top-10
- 时间对齐验证:对 Top-10 候选做频谱图谱峰对齐验证,确认时序一致性
---
## 4. 系统架构设计
### 4.1 整体架构
```
┌─────────────────────────────────────────────────────────────┐
│ API Gateway │
└─────────────────────┬───────────────────────────────────────┘
┌─────────────┼─────────────┐
▼ ▼ ▼
┌───────────────┐ ┌───────┐ ┌───────────────┐
│ Audio Ingest │ │ Search│ │ Admin Service │
│ (Ingestion) │ │ (QPS) │ │ (管理) │
└───────┬───────┘ └───┬───┘ └───────┬───────┘
│ │ │
▼ ▼ ▼
┌─────────────────────────────────────────────────────────────┐
│ Core Engine Layer │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌───────────────┐ │
│ │ Pre- │ │ Feature │ │ Embedder│ │ Matcher │ │
│ │ processor│ │ Extractor│ │ (Model) │ │ (Searcher) │ │
│ └──────────┘ └──────────┘ └──────────┘ └───────────────┘ │
└─────────────────────────────────────────────────────────────┘
│ │ │
▼ ▼ ▼
┌─────────────────────────────────────────────────────────────┐
│ Storage Layer │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌───────────────┐ │
│ │ Raw Audio│ │ Finger- │ │ Embedding│ │ Song Metadata │ │
│ │ (S3/OSS) │ │ print DB │ │ Index │ │ (PostgreSQL) │ │
│ └──────────┘ └──────────┘ └──────────┘ └───────────────┘ │
└─────────────────────────────────────────────────────────────┘
```
### 4.2 模块详细设计
#### 4.2.1 Audio Preprocessor
```
输入: raw_audio_bytes / file_path / stream
功能:
1. 格式解码 (MP3, WAV, FLAC, AAC, OGG, M4A)
2. 重采样到统一采样率 (16kHz 或 22.05kHz)
3. 通道合并 (多声道 → 单声道)
4. 归一化 (RMS 归一化到目标响度)
5. 分帧/滑窗 (非重叠或非重叠滑窗,每帧 3-15s)
输出: numpy.ndarray, shape=(samples,)
```
#### 4.2.2 Feature Extractor
```
支持多种特征提取策略,可通过配置切换:
模式 A: Spectrogram + Log-Mel
- STFT: window=2048, hop=512, window_fn=hann
- Mel filters: 64/128 bins, fmin=0, fmax=8000
- Log(spectrogram + 1e-6)
模式 B: Chroma CQT
- Constant Q Transform, 12 bins/octave
- 适用于哼唱场景
模式 C: Landmark + Hash (Shazam 兼容)
- Peak extraction (2D local maxima)
- Target zone pairing for hash construction
模式 D: Raw Waveform (可选)
- 直接输入原始波形给 1D CNN
```
#### 4.2.3 Embedder (深度模型)
参见第 [6 节](#6-模型设计)。
#### 4.2.4 Matcher / Searcher
```
输入: query_embedding (dim=256)
流程:
1. ANN 检索: Faiss IVF+HNSW, top_k=100
2. 精排: 计算精确余弦相似度, top_k=10
3. 时间对齐验证 (可选):
- 对 Top-10 候选提取谱峰
- 计算 Query 与候选的时间偏移直方图
- 确认存在一致性偏移峰值
4. 置信度校准: 计算相似度分布 z-score
5. 输出: sorted_results[ {song_id, score, match_type} ]
```
### 4.3 API 设计
```protobuf
// Recognize — 识别音频
service ACRService {
// 输入音频返回 Top-N 匹配歌曲
rpc Recognize(RecognizeRequest) returns (RecognizeResponse);
// 批量入库
rpc IngestSong(IngestSongRequest) returns (IngestSongResponse);
// 删除歌曲
rpc DeleteSong(DeleteSongRequest) returns (DeleteSongResponse);
// 健康检查
rpc HealthCheck(Empty) returns (HealthCheckResponse);
}
message RecognizeRequest {
bytes audio_data = 1; // 音频数据
string audio_format = 2; // wav, mp3, ogg
float duration_sec = 3; // 实际有效时长 (若未知留空)
RecognizeMode mode = 4; // AUTO, BGM, HUMMING, RECORDING
int32 top_n = 5; // 返回 Top-N (默认 5)
}
enum RecognizeMode {
AUTO = 0; // 自动检测模式
BGM = 1; // 纯 BGM 片段
HUMMING = 2; // 哼唱
RECORDING = 3; // 现场录音
}
message RecognizeResponse {
repeated Candidate candidates = 1;
float processing_time_ms = 2;
}
message Candidate {
string song_id = 1;
string title = 2;
string artist = 3;
float confidence = 4;
float matched_begin_sec = 5; // 匹配起始时间
float matched_end_sec = 6; // 匹配结束时间
string match_type = 7; // bgm / humming / recording
}
```
### 4.4 存储设计
| 数据 | 存储引擎 | 说明 |
|------|---------|------|
| 原始音频 | S3/MinIO/OSS | 对象存储,按 song_id 组织 |
| 歌曲元数据 | PostgreSQL | 标题、歌手、专辑、时长、标签 |
| 嵌入向量 | Faiss Index (IVF+HNSW) | 256 维浮点向量 |
| 指纹哈希 | Redis / LevelDB | Shazam 兼容指纹键值对 |
| 频谱缓存 | Redis / S3 | 预处理后的频谱图缓存 |
| 操作日志 | ClickHouse / ELK | 查询日志、性能监控 |
### 4.5 部署架构
```
┌──────────┐
│ LB/Nginx│
└────┬─────┘
┌──────────┼──────────┐
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ API │ │ API │ │ API │
│ Server 1 │ │ Server 2 │ │ Server N │
└────┬─────┘ └────┬─────┘ └────┬─────┘
│ │ │
▼ ▼ ▼
┌─────────────────────────────────────┐
│ Faiss Index (Sharded) │
│ GPU/CPU Hybrid │
├─────────────────────────────────────┤
│ PostgreSQL (RDS) │
├─────────────────────────────────────┤
│ S3-compatible Object Store │
└─────────────────────────────────────┘
```
---
## 5. 数据准备与增强
### 5.1 数据来源
#### 5.1.1 歌曲原始数据
| 来源 | 类型 | 规模目标 | 许可注意 |
|------|------|---------|---------|
| FMA (Free Music Archive) | 开源音乐 | 100K+ 曲 | CC 授权 |
| MUSDB18 | 多轨分离数据集 | 150 曲 | 研究用途 |
| GTZAN | 流派分类 | 1000 曲 | 研究用途 |
| 自行爬取/合作 | 商业音乐 | 1M+ 曲 | 需版权授权 |
| 自建录制 | 哼唱/翻唱 | 10K+ 段 | 内部数据 |
#### 5.1.2 训练数据构造
每个歌曲在库中作为 **Reference**,需为每个 Reference 构造多样化的 **Query** 用于训练。
**基础构造逻辑**:
```
song.mp3 → 随机裁剪片段 (3-15s) → 数据增强 → Query
song.mp3 → 全曲 → Reference
```
#### 5.1.3 哼唱数据
哼唱数据可通过以下方式获取:
1. **MIR-QBSH Corpus**:专业哼唱数据集
2. **自建哼唱数据集**:组织用户录制哼唱旋律
3. **MIDI 转音频模拟**:将 MIDI 文件通过合成器转为模拟哼唱
4. **M-Humming**:自行标注的哼唱数据集
哼唱数据格式要求:
```
{
"song_id": "song_001",
"humming_id": "hum_001",
"audio_path": "/data/humming/song_001_hum_001.wav",
"original_song_path": "/data/songs/song_001.mp3",
"humming_duration_sec": 8.5,
"relative_pitch_shift": -2, // 相对原曲的半音偏移
"tempo_ratio": 1.1 // 相对原曲的速度倍率
}
```
### 5.2 数据增强策略
增强的目的是**使模型学到对真实世界干扰的不变性**。
#### 5.2.1 基础增强
| 增强操作 | 参数范围 | 目标 |
|---------|---------|------|
| Additive White Gaussian Noise (AWGN) | SNR: 5-30dB | 环境噪声 |
| Pink Noise / Brown Noise | SNR: 10-25dB | 自然噪声 |
| Band-stop Filtering | 随机 0.5-2kHz 陷波 | 频率缺失 |
| Low-pass / High-pass | 截止频率 1-8kHz | 频带限制 |
| Time Stretch | 0.85-1.15x | 速度变化 |
| Pitch Shift | -6 ~ +6 semitones | 调性变化(哼唱) |
| Equalizer Randomization | 随机增益 ±6dB | 音色变化 |
| Resampling | 8-44.1kHz | 采样率退化 |
| MP3 Compression | 32-128kbps | 压缩失真 |
| Reverb | 房间混响模拟 | 远场录音 |
| Volume Jitter | -12 ~ 0 dB | 响度变化 |
| Time Masking (SpecAug) | 遮罩 10-50 帧 | 局部缺失 |
| Frequency Masking (SpecAug) | 遮罩 8-16 bins | 局部频率缺失 |
#### 5.2.2 哼唱专用增强
| 增强操作 | 说明 |
|---------|------|
| F0 抖动 | 基频随机扰动 ±5% |
| 节奏抖动 | 节拍随机扰动 ±10% |
| 添加呼吸声 | 插入随机位置的呼吸音 |
| 音色变异 | 使用不同的合成器/人声 |
| 单音偏差 | 部分音符替换为邻音(模拟跑调) |
#### 5.2.3 数据增强管线
```
原始音频 (16kHz mono)
├─→ [随机裁剪] 3-15s 随机片段
├─→ [重采样] 8kHz / 16kHz / 22.05kHz / 44.1kHz 随机选择
├─→ [响度归一化] RMS = target_loudness
├─→ [噪声叠加] AWGN / Pink / 背景音 按概率叠加
├─→ [滤波器] 低通/高通/带阻/均衡器 随机选择
├─→ [时域变化] Time Stretch ±15%
├─→ [频域变化] Pitch Shift ±6 semitones
├─→ [压缩模拟] MP3 编码再解码 (64-128kpbs)
├─→ [混响] 小型/中型/大型房间混响
├─→ [SpecAug] Time & Frequency Masking
└─→ [特征提取] Mel Spectrogram / Chroma / Raw
└─→ [输出] 增强后的特征张量
```
实现:`torchaudio` / `audiomentations` / `librosa` 组合管线。
### 5.3 数据格式与存储
**训练数据格式**:
```
/data/
├── songs/ # 原始歌曲
│ ├── song_001.mp3
│ └── ...
├── references/ # 参考指纹/嵌入
│ ├── ref_001.npy # 歌曲全曲或多段嵌入
│ └── ...
├── queries/ # 查询片段 (训练数据)
│ ├── train/
│ │ ├── song_001_seg_001.wav
│ │ └── ...
│ └── val/
│ └── ...
├── metadata.csv # 歌曲元数据
└── train_pairs.csv # (query_path, song_id, type)
```
**metadata.csv 格式**:
```csv
song_id,title,artist,album,duration_sec,genre,language
song_001,Song Title,Artist Name,Album Name,240.5,Pop,en
```
**train_pairs.csv 格式**:
```csv
query_path,song_id,query_type,augmentation_params
queries/train/song_001_seg_001.wav,song_001,bgm,"{snr:15, pitch_shift:0}"
queries/train/song_001_hum_001.wav,song_001,humming,"{pitch_shift:-2, tempo:1.1}"
```
### 5.4 数据流水线性能要求
| 指标 | 目标 |
|------|------|
| 增强吞吐 | ≥ 200 样本/秒/GPU |
| 预处理缓存 | 频谱图存入 LMDB/RecordIO |
| 训练样本总量 | ≥ 5M Query-Reference 对 |
| 参考曲库 | ≥ 100K 歌曲(测试阶段) |
---
## 6. 模型设计
### 6.1 模型架构选型
本方案采用 **双塔结构 (Two-Tower / Siamese Network)**,两塔共享权重。
```
┌─────────────────────────────────────┐
│ Similarity Score │
│ cosine(q_emb, r_emb) │
└──────────────────┬──────────────────┘
┌────────────────────┴────────────────────┐
▼ ▼
┌───────────────┐ ┌───────────────┐
│ Query │ │ Reference │
│ Encoder │ │ Encoder │
│ (shared) │ │ (shared) │
└───────┬───────┘ └───────┬───────┘
│ │
┌───────┴───────┐ ┌───────┴───────┐
│ Input 1 │ │ Input 2 │
│ (Mel Spec) │ │ (Mel Spec) │
└───────────────┘ └───────────────┘
```
### 6.2 候选骨干网络
#### 方案 A: CNN-Transformer (推荐)
```
Input: Mel-Spectrogram (1, 128, T) — 单通道, 128 Mel bins, 变长时间
├─ Conv2D(1→32, 3×3, stride=1) + BN + ReLU
├─ Conv2D(32→64, 3×3, stride=2) + BN + ReLU
├─ Conv2D(64→128, 3×3, stride=2) + BN + ReLU
├─ Conv2D(128→256, 3×3, stride=2) + BN + ReLU
├─ Reshape: (batch, T', 256)
├─ Transformer Encoder × 4 (d_model=256, nhead=8, dim_feedforward=1024)
├─ [CLS] Token Pooling / Global Average Pooling
├─ Projection: 256 → 256 (Linear + LayerNorm)
└─ L2 Normalize → Embedding (256-dim)
```
**总参数量**: ~8-12M | **MACs**: ~2-5G per 5s audio
#### 方案 B: EfficientNet-ish (轻量级)
```
Input: Mel-Spectrogram (3, 128, T) — 拼接近邻帧伪 RGB
├─ MBConv blocks (EfficientNet-B0 like)
│ - Stem: Conv 3×3, 32ch
│ - Stage 1-7: MBConv with SE
│ - Head: Conv 1×1, 1280ch
├─ Global Average Pooling
├─ Dropout 0.2
├─ Projection: 1280 → 256
└─ L2 Normalize → Embedding (256-dim)
```
**总参数量**: ~5-8M | **MACs**: ~1-3G per 5s audio
#### 方案 C: 纯 Attention (AST-like)
```
Input: Mel-Spectrogram (1, 128, T)
├─ Patch Embedding (16×16 patches) + Position Embedding
├─ Transformer Encoder × 12 (d_model=768, nhead=12)
├─ [CLS] Token
├─ Projection: 768 → 256
└─ L2 Normalize → Embedding (256-dim)
```
**总参数量**: ~80-90M | **MACs**: ~5-15G per 5s audio
**优势**: 准确率最高 | **劣势**: 推理速度较慢
#### 推荐: 方案 A (CNN-Transformer) 作为主选,方案 B 作为备选轻量级。
### 6.3 训练损失函数
#### 6.3.1 主损失: SupConLoss (Supervised Contrastive Loss)
```
对于 batch 中每个 anchor a,
正样本集 P(a) = 所有与 a 同歌曲的样本
负样本集 N(a) = 与 a 不同歌曲的样本
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)/τ) ) ]
```
#### 6.3.2 辅助损失: ArcFace / CosFace (可选)
当曲库有固定类别标签时,可附加分类损失:
```
L_arcface = -log( exp(s·cos(θ_y + m)) / (exp(s·cos(θ_y + m)) + Σ_j≠y exp(s·cos θ_j)) )
```
#### 6.3.3 总损失
```
L_total = λ₁ · L_supcon + λ₂ · L_arcface + λ₃ · L_triplet
```
推荐 `λ₁=1.0, λ₂=0.3, λ₃=0.1`。
### 6.4 哼唱识别专用模块
对于哼唱输入,在主干网络外增加一个**旋律编码分支**:
```
哼唱音频
├─ F0 估计 (CREPE / PYIN) → F0 轮廓 (hourglass-shaped)
├─ Chroma CQT → 12-bin 色谱图
├─ 可选融合策略:
│ A) 早融合 (Early Fusion): Mel + Chroma 通道拼接 → 同一网络
│ B) 晚融合 (Late Fusion): Mel 分支 + Chroma 分支分别编码 → 拼接嵌入
│ C) 分叉网络 (Forked): 共享底层特征层,高层分支出 Mel 和 Chroma 特征
└─ → 256-dim Embedding
```
推荐使用 **晚融合** 方案,在训练时将 Mel 特征和 Chroma 特征分别经过共享底层后拼接,再投影到 256 维。
### 6.5 多尺度匹配策略
由于 Query 长度可变(3-15s),使用多尺度滑窗:
```
Reference (全曲 3min):
[───── Window 1 (5s) ─────]
[───── Window 2 (5s) ─────]
[───── Window 3 (5s) ─────]
... (stride = 2.5s)
每个窗口 → Reference Embedding Matrix: (num_windows, 256)
Query (5s) → Query Embedding: (1, 256)
匹配: max_sim = max(sim(query_emb, ref_window_emb_i) for i in windows)
```
---
## 7. 训练细节
### 7.1 实验环境
| 配置 | 规格 |
|------|------|
| GPU | NVIDIA A100 (80GB) × 4 |
| CPU | AMD EPYC 64C / Intel Xeon 48C |
| RAM | 512 GB |
| 存储 | NVMe SSD 4TB |
| 框架 | PyTorch 2.x + Lightning / FSDP |
| 加速 | Flash Attention, torch.compile |
| 监控 | W&B / MLflow |
### 7.2 超参数
| 参数 | 值 | 备注 |
|------|-----|------|
| Audio SR | 16000 Hz | 统一采样率 |
| Frame Size | 1024 (~64ms) | STFT 窗长 |
| Hop Size | 512 (~32ms) | STFT 步长 |
| Mel Bins | 128 | 梅尔滤波器数量 |
| Max Duration | 10s | 训练时音频截断长度 |
| Embedding Dim | 256 | 嵌入向量维度 |
| Batch Size | 512-1024 | 分布式训练 |
| Optimizer | AdamW | β=(0.9, 0.999) |
| Learning Rate | 3e-4 | Cosine Annealing |
| Weight Decay | 0.01 | L2 正则化 |
| Warmup Steps | 5000 | Linear Warmup |
| Epochs | 100-200 | Early Stopping |
| Temperature τ | 0.07 | 对比学习温度 |
| Label Smoothing | 0.1 | 防止过拟合 |
| Gradient Clipping | 1.0 | Max norm |
| Mixed Precision | bfloat16 | 加速训练 |
| Scheduler | Cosine Decay | Warm restarts |
### 7.3 训练流程
```
Step 1: 数据准备
1. 收集原始歌曲 → 16kHz mono → 存储为 WAV
2. 随机裁剪 + 数据增强 → 生成 Query/Reference 对
3. 提取 Mel 频谱 → 存储为 .npy (可选在线提取)
4. 分割 train/val/test (80/10/10)
Step 2: 预训练 (可选)
1. 在大规模无标签数据上使用 SimCLR / BYOL 做自监督预训练
2. 或使用公开预训练权重 (AudioMAE, CLAIR, CLAP)
Step 3: 有监督对比学习训练
1. 加载预训练权重或从头初始化
2. 每个 batch: 从 B 个歌曲各取 K 个片段 → B×K 样本
3. 计算 SupConLoss + 辅助损失
4. 每 N 步验证集评估 Recall@1, Recall@5
5. 最佳模型保存 checkpoint
Step 4: 哼唱微调 (可选阶段)
1. 使用哼唱数据 + 数据增强对模型做有监督微调
2. 固定部分底层参数,微调顶层和高层 Transformer
3. Learning rate: 1e-5 (较小)
Step 5: 索引构建
1. 对所有歌曲提取 Reference Embeddings
2. 使用 Faiss 构建 IVF+HNSW 索引
3. 评估索引准确率与检索速度
```
### 7.4 评估指标
| 指标 | 说明 | 目标值 |
|------|------|--------|
| **Recall@1** | Top-1 准确率 | ≥ 90% (BGM), ≥ 80% (哼唱) |
| **Recall@5** | Top-5 召回率 | ≥ 95% (BGM), ≥ 90% (哼唱) |
| **MRR** | Mean Reciprocal Rank | ≥ 0.9 |
| **mAP** | Mean Average Precision | ≥ 0.88 |
| **QPS** | Queries Per Second (单 GPU) | ≥ 500 |
| **P50 Latency** | 中位数响应时间 | ≤ 100ms |
| **P99 Latency** | 99% 响应时间 | ≤ 500ms |
| **Index Build** | 10万曲库索引构建时间 | ≤ 30min |
| **Index Size** | 索引占用内存 | ≤ 2GB (100K 曲) |
### 7.5 消融实验设计
| 实验 | 变量 | 预期验证目标 |
|------|------|------------|
| 特征对比 | Mel vs Chroma vs CQT vs Raw | 最优输入特征 |
| 骨干对比 | CNN vs CNN-Tfm vs AST vs EffNet | 最优架构 |
| 嵌入维度 | 64 vs 128 vs 256 vs 512 | 性能-容量平衡 |
| 对比损失 | SupCon vs Triplet vs NT-Xent vs ArcFace | 最优损失函数 |
| 温度系数 | τ=0.05, 0.07, 0.1, 0.2 | 最优温度 |
| 数据增强 | 无增强 vs 基础 vs 全部 | 增强贡献度 |
| 哼唱策略 | 早融合 vs 晚融合 vs 分叉 | 最优融合方式 |
| 曲库抗噪 | 添加噪声曲库干扰 | 抗干扰能力 |
### 7.6 分布式训练策略
```bash
# 使用 PyTorch DDP / FSDP
torchrun --nproc_per_node=8 train.py \
--batch_size 64 \
--model cnn_transformer \
--embed_dim 256 \
--max_duration 10 \
--lr 3e-4 \
--epochs 200 \
--warmup 5000 \
--fp16 \
--dataset_path /data/acr \
--save_interval 10
```
---
## 8. 推理与匹配策略
### 8.1 推理流程
```
用户输入 Query (任意时长)
├─ 1. 音频预处理 (重采样+通道合并+归一化)
├─ 2. 滑窗切片 (5s 窗口, 2.5s 步长)
│ 如果 Query < 3s: 补充静音到 3s → 拒绝/低置信度
│ 如果 3s ≤ Query ≤ 15s: 单窗口或最多 2 窗口
│ 如果 Query > 15s: 多窗口 5s 滑窗
├─ 3. 特征提取 (Mel Spectrogram)
├─ 4. 嵌入推理 (模型 forward) → query_embs: (num_windows, 256)
├─ 5. 候选检索
│ a) 对每个窗口嵌入做 ANN 检索 → Top-50 × num_windows
│ b) 合并候选并去重 → Top-100
│ c) 精排: 精确相似度计算 → Top-10
├─ 6. (Optional) 时间对齐验证
│ - 对 Top-10 候选提取频谱图峰值
│ - 计算与 Query 的时间偏移直方图
│ - 一致性验证 → 更新置信度
├─ 7. 置信度校准
│ - 计算 query_embs 与各候选嵌入的最大相似度
│ - Z-score 标准化: score_z = (score - μ_candidates) / σ_candidates
│ - 应用阈值 (score_z > 2.0 或直接阈值 > 0.7)
└─ 8. 输出结果
```
### 8.2 流式推理 (Streaming)
对于长音频流 (如直播、电台监听),支持流式识别:
```
音频流输入 (16kHz, 实时)
├─ 环形缓冲区 (Ring Buffer, 15s 容量)
├─ 每积累 2.5s 新音频 → 触发一次识别
├─ 取: 缓冲区末尾 5s 作为当前 Query
├─ 嵌入 → ANN 检索 (使用缓存减少重复计算)
├─ 结果缓存与平滑: 连续 N 次命中同一歌曲 → 确认输出
└─ 重复
```
### 8.3 拒绝策略 (Rejection)
当 Query 不在库中时,应可靠地拒绝(低误报率):
| 策略 | 实现 |
|------|------|
| 绝对阈值 | max_score < 0.5 → 拒绝 |
| 相对阈值 | max_score - second_score < 0.15 → 拒绝 |
| 分布阈值 | max_score < μ_candidates + 2·σ_candidates → 拒绝 |
| 混合策略 | 三者加权组合 |
| 验证分支 | 增加"非歌分类"头,判断输入是否为有效音乐 |
### 8.4 缓存策略
```
Query → 特征 Cache (LRU):
- Key: audio_hash (MD5 of first 2s)
- Value: (query_embedding, timestamp)
- TTL: 30 分钟
- Max size: 10K entries
热门歌曲 Cache:
- 频繁命中的歌曲嵌入常驻内存
- 使用 LFU eviction
```
---
## 9. 使用方法
### 9.1 安装
```bash
# 克隆仓库
git clone <repo-url> && cd acr-engine
# 创建环境
conda create -n acr python=3.11 && conda activate acr
# 安装依赖
pip install -r requirements.txt
# 可选: GPU 版 Faiss
pip install faiss-gpu
# 安装 torchaudio (含 CUDA)
pip install torch torchaudio --index-url https://download.pytorch.org/whl/cu121
```
### 9.2 数据导入
```bash
# 批量导入歌曲到曲库
python scripts/ingest.py \
--input /data/music_library/ \
--format mp3 \
--recursive \
--metadata metadata.csv
# 导入单曲
python scripts/ingest.py --input song.mp3 --song-id "song_001"
```
### 9.3 训练
```bash
# 完整训练流程
python train.py \
--config configs/default.yaml \
--data /data/acr/ \
--output /models/acr/ \
--epochs 200 \
--gpus 4
# 继续训练 (从 checkpoint)
python train.py --resume /models/acr/checkpoint_epoch_100.ckpt
# 哼唱微调
python train.py \
--config configs/humming_finetune.yaml \
--resume /models/acr/pretrained.ckpt \
--data /data/humming/
```
### 9.4 索引构建
```bash
# 构建 Faiss 索引
python scripts/build_index.py \
--model /models/acr/best.ckpt \
--songs /data/songs/ \
--output /index/acr_index.faiss \
--index-type "IVF4096,PQ16" \
--gpu
```
### 9.5 API 服务启动
```bash
# 启动 REST API (HTTP)
python serve.py \
--model /models/acr/best.ckpt \
--index /index/acr_index.faiss \
--port 8088 \
--workers 4
# 启动 gRPC 服务 (推荐生产使用)
python serve.py --mode grpc --port 50051
# 使用 Docker Compose
docker-compose up -d
```
### 9.6 客户端调用
**Python 客户端**:
```python
import requests
url = "http://localhost:8088/v1/recognize"
files = {"audio": open("query.wav", "rb")}
params = {"top_n": 5, "mode": "auto"}
resp = requests.post(url, files=files, params=params)
print(resp.json())
# {
# "candidates": [
# {"song_id": "...", "title": "...", "artist": "...",
# "confidence": 0.92, "match_type": "bgm"}
# ],
# "processing_time_ms": 45.2
# }
```
**命令行**:
```bash
# 识别本地音频文件
python cli.py recognize --audio query.mp3 --top-n 5
# 录音识别 (麦克风)
python cli.py recognize --mic --duration 5
# 流式识别 (文件)
python cli.py stream --input live_audio.wav --interval 2.5
```
### 9.7 SDK 集成
```
Python: pip install acr-sdk
Go: go get github.com/xxx/acr-go
Rust: cargo add acr-rs
Java: Maven: com.xxx:acr-client:1.0
```
**Python SDK 使用示例**:
```python
from acr_sdk import ACRClient
client = ACRClient(endpoint="localhost:50051", mode="grpc")
# 识别
result = client.recognize("query.wav", mode="humming")
print(f"Song: {result.title}, Confidence: {result.confidence:.2f}")
# 批量入库
client.ingest("/data/new_songs/")
# 删除
client.delete_song("song_001")
```
---
## 10. SOTA 调研与对比
### 10.1 学术界 SOTA
| 方法 | 年份 | 核心思想 | 哼唱支持 | Recall@1 (BGM) | Recall@1 (Humming) |
|------|------|---------|---------|---------------|-------------------|
| **Shazam** (Wang) | 2003 | 谱峰哈希指纹 | ❌ | ~85%* | N/A |
| **SoundHound** | 2006 | 旋律轮廓+指纹 | ✅ | ~88%* | ~75%* |
| **Dejavu** | 2015 | Shazam 开源实现 | ❌ | ~82% | N/A |
| **MatchNet** | 2018 | Siamese CNN + Triplet | ❌ | ~90% | N/A |
| **CLAP** (LAION) | 2023 | 对比语言-音频预训练 | ❌ | ~87% | N/A |
| **AudioMAE** | 2023 | 掩码自编码器预训练 | ❌ | ~85% | N/A |
| **Contrastive Audio** (Oord) | 2018 | CPC + 对比学习 | ❌ | ~86% | N/A |
| **HummingBird** | 2024 | Chroma + 对比学习 | ✅ | ~91% | ~82% |
| **Singer** (ByteDance) | 2024 | 多任务对比学习 | ✅ | ~93% | ~85% |
| **Ours** | 2026 | CNN-Tfm + SupCon + 哼唱融合 | ✅ | ≥92% | ≥83% |
*\* 为公开披露的估计值,非学术基准*
### 10.2 工业界产品对比
| 产品 | 识别速度 | BGM 准确率 | 哼唱准确率 | 曲库规模 | 延迟 |
|------|---------|-----------|-----------|---------|------|
| **Shazam (Apple)** | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ❌ | 亿级 | ~2s |
| **SoundHound** | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | 千万级 | ~3s |
| **网易云音乐** | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | 千万级 | ~2s |
| **QQ音乐** | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ | 千万级 | ~2s |
| **Google Sound Search** | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ | 亿级 | ~3s |
| **Ours** | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | 百万级(初期) | ≤0.5s |
### 10.3 本方案的边际优势 (vs 现有方案)
1. **哼唱融合训练**:通过专用的哼唱增强和对比学习策略,哼唱识别准确率显著优于纯指纹方案
2. **混合架构**:CNN-Transformer 比纯 CNN 有更好的序列建模能力,比纯 Transformer 更高效
3. **级联检索**:ANN 粗筛 + 精确重排 + 时间对齐验证,兼顾速度与精度
4. **数据增强系统**:全面的增强策略涵盖 BGM、哼唱、录音三大场景
5. **可扩展性**:增量索引支持动态歌库,无需重训练
---
## 11. Roadmap
### 11.1 阶段规划
```
Phase 0: 基础建设 (Week 1-2)
├── 环境搭建与依赖配置
├── 数据探索与预处理 pipeline
├── 基础特征提取模块 (Mel, Chroma, CQT)
├── 数据增强模块 (audiomentations pipeline)
└── 基线模型: Shazam 式指纹法 (Dejavu fork)
Phase 1: V1 MVP (Week 3-6)
├── CNN-Transformer 模型实现
├── SupConLoss 训练管线
├── 基础数据收集 (FMA + MUSDB18 + GTZAN)
├── 训练 100K Query-Reference 对的模型
├── Faiss 索引构建 Pipeline
├── REST API + gRPC 服务
└── 本地 CLI 工具
Phase 2: 哼唱支持 (Week 7-10)
├── 哼唱数据收集 (内部录制 + MIR-QBSH)
├── 哼唱增强 Pipeline
├── Chroma 分支 + 旋律轮廓编码
├── 哼唱-原曲对比学习微调
├── 哼唱专用评估集构建
└── 哼唱模式 API 支持
Phase 3: 生产优化 (Week 11-14)
├── 模型量化 (INT8 / FP16)
├── ONNX Runtime / TensorRT 部署
├── 级联检索策略优化
├── 缓存系统实现 (LRU + LFU)
├── 流式识别支持
├── 负载测试与性能调优
├── Docker + K8s 部署配置
└── CI/CD Pipeline
Phase 4: 进阶能力 (Week 15-20)
├── 分布式曲库 (Index Sharding)
├── 多语言歌曲支持
├── 歌曲翻唱/Remix 识别
├── 歌曲定位 (识别到歌曲中具体位置)
├── 歌词时间轴对齐
├── Web dashboard (曲库管理 + 监控)
├── 增量学习 (在线模型更新)
└── 边缘端部署 (移动端/嵌入式)
Phase 5: 持续迭代 (Week 21+)
├── 用户反馈环路
├── A/B 测试框架
├── 模型持续训练 (CT)
├── 数据处理自动化
├── 新 SOTA 方法集成
├── 商业合作接入
└── 合规与版权管理
```
### 11.2 里程碑
| 里程碑 | 时间 | 交付物 | 验收标准 |
|--------|------|--------|---------|
| M0: 基础准备 | Week 2 | 开发环境、数据管线 | 增强管线吞吐 ≥ 200/秒 |
| M1: V1 MVP | Week 6 | 可运行的识别引擎 | Recall@1 ≥ 85% (BGM) |
| M2: 哼唱上线 | Week 10 | 哼唱识别能力 | Recall@1 ≥ 75% (Humming) |
| M3: 生产就绪 | Week 14 | 高性能服务 | P50 ≤ 100ms, QPS ≥ 500 |
| M4: 进阶能力 | Week 20 | 企业级平台 | 多场景覆盖, 曲库 100 万+ |
---
## 12. Checklist
### 12.1 数据准备
- [ ] 确定数据来源并获取授权
- [ ] 下载并组织原始歌曲库 (≥ 100K songs)
- [ ] 统一转为 16kHz mono WAV 格式
- [ ] 实现数据增强管线 (全部增强策略)
- [ ] 生成训练 Query-Reference 对 (≥ 5M pairs)
- [ ] 构建哼唱数据集 (≥ 10K 段)
- [ ] 分割 train/val/test (80/10/10)
- [ ] 验证数据分布多样性 (流派、语言、年代)
- [ ] 实现数据加载器 (支持在线增强)
- [ ] 数据版本控制 (DVC / HuggingFace Datasets)
### 12.2 模型开发
- [ ] 实现基础 CNN-Transformer 骨干
- [ ] 实现训练循环 (SupConLoss + 辅助损失)
- [ ] 实现哼唱分支 (Chroma + F0 融合)
- [ ] 实现多尺度滑窗匹配
- [ ] 实现基准模型 (Shazam + Dejavu)
- [ ] 实现对比实验框架
- [ ] 超参数搜索 (学习率、温度、嵌入维度等)
- [ ] 训练收敛验证
### 12.3 索引与检索
- [ ] 实现 Faiss 索引构建管线
- [ ] 实现 ANN + 精确重排的级联检索
- [ ] 实现时间对齐验证
- [ ] 实现置信度校准与拒绝策略
- [ ] 索引增量更新 (增删歌曲)
- [ ] 索引持久化与加载优化
### 12.4 服务部署
- [ ] 实现 REST API (FastAPI / Flask)
- [ ] 实现 gRPC API
- [ ] 模型导出 (ONNX / TorchScript)
- [ ] 模型量化 (INT8 / FP16)
- [ ] 实现流式识别
- [ ] 实现缓存系统
- [ ] 负载测试 & 性能调优
- [ ] Docker 镜像构建
- [ ] Docker Compose / K8s 配置文件
- [ ] 监控与告警 (Prometheus + Grafana)
- [ ] 日志系统 (结构化日志)
- [ ] CI/CD Pipeline
### 12.5 质量保障
- [ ] 单元测试 (核心模块覆盖率 ≥ 80%)
- [ ] 集成测试 (端到端识别流程)
- [ ] 性能基准测试 (延迟、吞吐、内存)
- [ ] 鲁棒性测试 (噪声、压缩、哼唱变化)
- [ ] 回归测试 (每次模型更新)
- [ ] 评估集标注与维护
- [ ] 安全审计 (注入、权限、数据泄露)
### 12.6 文档与交付
- [x] 设计文档 (本文件)
- [ ] API 文档 (Swagger / OpenAPI)
- [ ] 部署文档 (Docker, K8s, 环境要求)
- [ ] 用户手册 (SDK 使用指南)
- [ ] 训练文档 (数据、超参数、实验记录)
- [ ] 运维手册 (监控、日志、故障排查)
- [ ] 演示 / demos
---
## 13. Changelog
### [v1.0] — 2026-06-02
#### Added
- 初始设计文档创建
- 完整架构设计 (双塔对比学习 + Faiss 检索)
- 数据增强策略 (12+ 种操作)
- 哼唱识别模块设计
- SOTA 调研对比表
- Roadmap (Phase 0-5)
- Checklist (6 大模块)
### [Planned] — v1.1
#### Planned
- 实验基准数据
- 训练收敛曲线与指标
- 模型参数量与推理延迟详细报告
- 消融实验结果
- 用户反馈收集结果
### [Planned] — v2.0
#### Planned
- 分布式曲库方案
- 边缘端部署方案
- 在线学习模块
- 歌词时间轴识别
---
## 14. Handoff 交付清单
### 14.1 交付物概要
| 类别 | 交付物 | 责任人 | 验收人 |
|------|--------|-------|--------|
| 设计 | ACR 设计文档 (本文) | 架构师 | 技术负责人 |
| 数据 | 训练数据集 & 评估集 | 数据工程师 | 算法工程师 |
| 代码 | 模型训练代码 | 算法工程师 | 架构师 |
| 代码 | API 服务 & CLI 工具 | 后端工程师 | 架构师 |
| 部署 | Docker / K8s 配置 | DevOps | 运维 |
| 文档 | API 文档 & 用户手册 | 技术写作 | 产品经理 |
| 测试 | 测试报告 & 性能基准 | QA | 技术负责人 |
### 14.2 验收标准
```
[ ] 端到端识别流程通过: 输入音频 → 输出正确歌曲
[ ] Recall@1 ≥ 90% (BGM 场景, 干净音频)
[ ] Recall@1 ≥ 80% (哼唱场景)
[ ] P50 延迟 ≤ 100ms (单机器, 百万曲库)
[ ] P99 延迟 ≤ 500ms
[ ] 并发 QPS ≥ 100 (单机器, 4 CPU cores)
[ ] 曲库增量更新 ≤ 1s/曲
[ ] 所有单元测试通过 (覆盖率 ≥ 80%)
[ ] 安全审计无高危漏洞
[ ] 文档完整性审查通过
```
### 14.3 风险与缓解
| 风险 | 概率 | 影响 | 缓解措施 |
|------|------|-----|---------|
| 版权音乐数据获取困难 | 高 | 高 | 优先使用开源数据集; 探索合成数据 |
| 哼唱数据不足 | 中 | 高 | 合成哼唱 + Mid-to-Audio 生成 |
| 噪声下准确率不达标 | 中 | 中 | 更激进的数据增强; 模型集成 |
| 大曲库检索延迟 | 低 | 中 | 多级索引; GPU 加速检索 |
| 模型过拟合 | 低 | 中 | 强正则化; 大规模数据; Dropout |
| 哼唱与 BGM 模式冲突 | 中 | 中 | 双模式 / 级联识别 |
### 14.4 移交步骤
1. **代码移交**:所有代码推送到主仓库,PR 审核通过,CI 绿色
2. **模型移交**:最佳模型 checkpoint + 导出 ONNX/TorchScript
3. **数据移交**:训练数据、评估数据、数据管线代码
4. **索引移交**:Faiss 索引文件 + 元数据
5. **部署移交**:Docker 镜像推送到 Registry,K8s 配置文件就绪
6. **文档移交**:所有文档整理到 `/docs/` 目录
7. **演示移交**:运行 demo 脚本,展示端到端识别流程
8. **培训移交**:对运维/开发人员进行 2 小时技术培训
---
## 15. 参考与引用
### 15.1 学术论文
| 主题 | 论文 | 年份 |
|------|------|------|
| 音频指纹 (Shazam) | Wang, A. "An Industrial-Strength Audio Search Algorithm" | 2003 |
| 对比学习 (SimCLR) | Chen et al. "A Simple Framework for Contrastive Learning" | 2020 |
| 监督对比学习 | Khosla et al. "Supervised Contrastive Learning" | 2020 |
| 频谱图增强 (SpecAug) | Park et al. "SpecAugment: A Simple Augmentation Method" | 2019 |
| 语音谱图 Transformer | Gong et al. "AST: Audio Spectrogram Transformer" | 2021 |
| CLAP | Wu et al. "Large-scale Contrastive Language-Audio Pretraining" | 2023 |
| AudioMAE | Huang et al. "Masked Autoencoders that Listen" | 2023 |
| CPC for Audio | Oord et al. "Representation Learning with Contrastive Predictive Coding" | 2018 |
| 哼唱识别综述 | Sharma et al. "Query-by-Humming: A Survey" | 2023 |
| CREPE | Kim et al. "CREPE: A Convolutional Representation for Pitch Estimation" | 2018 |
### 15.2 开源项目
| 项目 | 说明 | 链接 |
|------|------|------|
| **Dejavu** | Shazam 指纹法 Python 实现 | https://github.com/worldveil/dejavu |
| **Faiss** | 向量相似度搜索库 (Meta) | https://github.com/facebookresearch/faiss |
| **CLAP** | 对比语言-音频预训练 (LAION) | https://github.com/LAION-AI/CLAP |
| **torchaudio** | PyTorch 音频工具包 | https://github.com/pytorch/audio |
| **audiomentations** | 音频数据增强库 | https://github.com/iver56/audiomentations |
| **librosa** | 音频分析库 | https://github.com/librosa/librosa |
| **marsyas** | 音频处理框架 | https://github.com/marsyas/marsyas |
| **Essentia** | 音频分析库 (UPF) | https://github.com/MTG/essentia |
### 15.3 数据集
| 数据集 | 规模 | 用途 | 许可 |
|--------|------|------|------|
| FMA (Free Music Archive) | 106,574 曲 | 基础歌曲库 | CC |
| MUSDB18 | 150 曲 (多轨) | 音源分离 | 研究 |
| GTZAN | 1,000 曲 | 流派分类 (基线) | 研究 |
| MIR-QBSH | ~4,800 哼唱 | 哼唱识别 | 研究 |
| Medley-solos-DB | 21,574 片段 | 音色分析 | CC |
| AudioSet (Google) | 2M+ 片段 | 预训练/多任务 | YouTube |
---
## 附录 A: 快速开始 Demo
```python
#!/usr/bin/env python
"""ACR Engine Quick Demo"""
from acr_engine import ACRPipeline
# 初始化
pipeline = ACRPipeline(
model_path="models/acr/best.ckpt",
index_path="index/acr_index.faiss",
mode="auto"
)
# 批量导入
pipeline.ingest_directory("data/samples/")
# 识别
for query_path in ["query_bgm.wav", "query_hum.wav", "query_noisy.wav"]:
result = pipeline.recognize(query_path)
print(f"{query_path}: {result.title} ({result.confidence:.2%})")
```
## 附录 B: 配置模板 (configs/default.yaml)
```yaml
model:
name: cnn_transformer
embed_dim: 256
backbone:
cnn_channels: [32, 64, 128, 256]
transformer_layers: 4
nhead: 8
dim_feedforward: 1024
humming_branch:
enabled: true
fusion: late
chroma_bins: 12
f0_embed_dim: 64
data:
sample_rate: 16000
n_mels: 128
n_fft: 1024
hop_length: 512
max_duration: 10.0
min_duration: 3.0
window_size: 5.0
window_stride: 2.5
augmentation:
noise:
enable: true
snr_range: [5, 30]
pitch_shift:
enable: true
semitones_range: [-6, 6]
time_stretch:
enable: true
rate_range: [0.85, 1.15]
mp3_compression:
enable: true
bitrate_range: [32, 128]
spec_augment:
enable: true
time_mask_max: 50
freq_mask_max: 16
training:
batch_size: 512
epochs: 200
lr: 0.0003
weight_decay: 0.01
warmup_steps: 5000
temperature: 0.07
loss:
supcon_weight: 1.0
arcface_weight: 0.3
triplet_weight: 0.1
optimizer: adamw
scheduler: cosine
mixed_precision: bf16
gradient_clip: 1.0
index:
type: "IVF4096,PQ16"
metric: cosine
train_on_gpu: true
nprobe: 64
serving:
host: "0.0.0.0"
port: 8088
workers: 4
max_query_duration: 30.0
cache_size: 10000
reject_threshold: 0.5
top_n: 5
logging:
level: INFO
format: json
output: stdout
```
# Changelist / 2026-06-02
## 本次补充交付(2026-06-02 16:12 UTC)
### 目标
把当前工作切换成“可交接、可暂停、可恢复”的状态。
### 本次纳入交付的内容
| 类别 | 内容 |
|---|---|
| 状态 | 当前 dual-axis 仍以 `hum_focus` 为最佳候选 |
| 文档 | `CHANGELOG``session-handoff``delivery-handoff` 已补齐最新快照 |
| 约束 | 继续保留相对路径文档跳转,不碰大数据与训练产物 |
| 续跑 | 新 session 可直接从 handoff 接上继续做训练/评测/优化 |
### 这次交付的意义
1. 先把当前成果冻结,避免上下文丢失。
2. 给新 session 留一个最短恢复路径。
3. 后续可以无缝继续补数据集、改切片、提准确率。
---
## 本次补充交付(2026-06-02 15:09 UTC)
### 目标
把当前状态从“仍在稳定推进”升级为“已确认异常退出、需要排查”的交接包。
### 本次纳入交付的内容
| 类别 | 内容 |
|---|---|
| 证据 | `PID=431703``PID=424691` 均已退出 |
| 状态 | observable 目录仍停在 `chromaprint_progress.json + chromaprint.pkl` |
| 风险 | 没有 `reference_*`,没有 `evaluate.py`,没有明确 traceback |
| 文档 | `CHANGELOG``changelist``delivery handoff``session handoff``AGENT memory` |
### 文件级变更
| 文件 | 说明 |
|---|---|
| [./CHANGELOG.md](./CHANGELOG.md) | 补记 build-index 异常退出 checkpoint |
| [./delivery-handoff-2026-06-02.md](./delivery-handoff-2026-06-02.md) | 顶部改写为异常排查接管包 |
| [./session-handoff.md](./session-handoff.md) | 顶部快照切到“进程已退出、无下游产物” |
| [../AGENT.md](../AGENT.md) | 更新长期记忆,避免新 session 误判为仍在运行 |
### 当前最重要的 fresh evidence
- 观测时间:`2026-06-02 15:09:19 UTC`
- `ps -p 431703`:无存活进程
- `ps -p 424691`:无存活进程
- `pgrep -af 'run_demo.py build-index|evaluate.py ...'`:未发现接续进程
- observable 目录仅有:
- `chromaprint.pkl`
- `chromaprint_progress.json`
- 末次 progress:
- `status=building`
- `refs_done=4420/8000`
- 未出现:
- `reference_*`
- `evaluate.py`
### 重要决策
1. 当前已不应继续把它描述成“仅仅线性慢”。
2. 下一轮工作应转向 **build-index 异常退出排查**
3. 新提交已经有意义,因为状态从“运行中”变成了“已退出且无下游产物”。
## 本次追加交付(2026-06-02 15:18 UTC)
### 新增代码修复
| 文件 | 变更 |
|---|---|
| [../acr-engine/run_demo.py](../acr-engine/run_demo.py) | `build-index` / demo 关键日志统一 `flush=True` |
| [../acr-engine/src/engines/chromaprint_matcher.py](../acr-engine/src/engines/chromaprint_matcher.py) | chromaprint 阶段 progress 日志 `flush=True` |
| [../acr-engine/src/engines/ecapa_embedder.py](../acr-engine/src/engines/ecapa_embedder.py) | embedding/reference 阶段关键日志 `flush=True` |
### 新增验证证据
- 极小样本复现:`/tmp/chroma_repro_tiny12`
- 结果:`RC=1`
- 现在日志已实时落盘,不再是 `0 bytes`
- `[build-index] starting chromaprint index ...`
- `[build-reference-index] start: refs=12 ...`
- `ValueError: No reference embeddings were produced ...`
### 结论
- 当前已修复“失败时日志完全不可见”的可观测性问题。
- 下一轮 root cause 排查可以直接依赖实时日志,而不再需要盲等。
## 本次追加交付(2026-06-02 15:22 UTC)
### 新增代码修复
| 文件 | 变更 |
|---|---|
| [../acr-engine/src/engines/chromaprint_matcher.py](../acr-engine/src/engines/chromaprint_matcher.py) | 坏音频/缺失音频跳过;progress 增加 `skipped_refs` |
| [../acr-engine/src/engines/ecapa_embedder.py](../acr-engine/src/engines/ecapa_embedder.py) | 坏音频/缺失音频跳过;progress 增加 `skipped_refs` |
### 新增验证证据
- 最小容错复现:`/tmp/chroma_skip_repro`
- 输入:`1 good mp3 + 1 bad mp3`
- 结果:`RC=0`
- 验证点:
- 日志可见 `skip decode failure`
- `chromaprint_progress.json``status=complete`
- `reference_progress.json``status=complete`
- 两个 progress 文件都记录 `skipped_refs=1`
- 最终成功产出 `reference_embs.npy` / `reference_ids.npy`
### 结论
- 当前已验证:单个坏 MP3 不再拖垮整轮 `build-index`
- 下一轮应回到真实路径复现,确认主问题是否就是由坏 MP3 触发。
## 本次追加交付(2026-06-02 15:29 UTC)
### 新增运行证据
| 类别 | 内容 |
|---|---|
| rerun | fixed real-path 200-ref rerun 仍在前台运行:`session 19709` |
| chromaprint | `200/200` 完成,`skipped_refs=0` |
| reference | 已进入 embedding/reference 阶段,并完成 `25/200` checkpoint |
| 产物 | 已落盘 `reference_progress.json``reference_embs.partial.npy``reference_ids.partial.npy` |
### 当前最重要的 fresh evidence
- 观测时间:`2026-06-02 15:29:17 UTC`
- 输出目录:`/tmp/fma_realpath_small_rerun_index2`
- `chromaprint_progress.json`
- `status=complete`
- `refs_done=200/200`
- `hashes=57577`
- `postings=187446`
- `skipped_refs=0`
- `reference_progress.json`
- `status=building`
- `refs_done=25/200`
- `windows_done=256`
- `skipped_refs=0`
- 已出现:
- `reference_embs.partial.npy`
- `reference_ids.partial.npy`
### 结论
- 这次 fixed rerun 已经证明:修复后的真实路径样本不再卡死在 chromaprint 阶段。
- 当前最有价值的下一步,变为继续盯 `reference_*` 完成或捕获新的明确失败证据。
## 本次追加交付(2026-06-02 15:35 UTC)
### 新增运行证据
| 类别 | 内容 |
|---|---|
| chromaprint | `200/200` 完成,`skipped_refs=0` |
| reference | `200/200` 完成,`windows_done=2068` |
| 产物 | `reference_embs.npy``reference_ids.npy` 已完整落盘 |
| shape | `embedding_shape=[2068, 192]` |
### 当前最重要的 fresh evidence
- 观测时间:`2026-06-02 15:35:19 UTC`
- 输出目录:`/tmp/fma_realpath_small_rerun_index2`
- `reference_progress.json`
- `status=complete`
- `refs_done=200/200`
- `windows_done=2068`
- `embedding_shape=[2068, 192]`
- `skipped_refs=0`
- 最终产物:
- `reference_embs.npy``1588352 bytes`
- `reference_ids.npy``74576 bytes`
- stdout 明确出现:
- `Built reference index: 2068 windows, embeddings shape (2068, 192)`
- `[done] embedding index built: 2068 refs`
### 结论
- 当前已确认:修复后的真实路径 rerun 不仅能进入 reference 阶段,而且能完整产出最终 embedding index。
- 下一轮最高价值工作应切到:评测链是否自动衔接,以及必要时补显式 evaluate smoke。
## 本次追加交付(2026-06-02 15:40 UTC)
### 新增运行证据
| 类别 | 内容 |
|---|---|
| evaluate | 显式 `evaluate.py` smoke 已完成 |
| query 规模 | `num_queries=35`(overlap 中全部非 reference query) |
| 指标 | `top1=0.8571`, `topk=1.0` |
| by_type | `clean: n=35, top1=0.8571, topk=1.0` |
### 当前最重要的 fresh evidence
- 观测时间:`2026-06-02 15:40:30 UTC`
- 结果文件:`/tmp/fma_realpath_small_rerun_eval/eval_top50.json`
- 评测结果:
- `split=test`
- `num_queries=35`
- `top1=0.8571`
- `topk=1.0`
- query 数说明:
- overlap test items = `235`
-`reference` query = `35`
- 所以 `--max-queries 50` 实际评到 `35`
### 结论
- 当前已不只是建索引成功,而是已经拿到首份真实路径 `build-index -> evaluate` 闭环证据。
- 下一轮应把重点切到:更大评测规模与 hard case / confusion 评测。
## 本次追加交付(2026-06-02 15:43 UTC)
### 新增运行证据
| 类别 | 内容 |
|---|---|
| hard-case smoke | `synthetic_v2 + models_v6 + index_v6` 显式评测完成 |
| 总体 | `num_queries=16`, `top1=0.6875`, `topk=1.0` |
| hard case | `humming_like top1=0.25`, `confused top1=0.0` |
| 结论 | 当前短板已明确落在 hard-case top1,而不是 clean/topk |
### 当前最重要的 fresh evidence
- 观测时间:`2026-06-02 15:43:17 UTC`
- 结果文件:`/tmp/synthetic_v2_eval_v6_top16.json`
- 评测结果:
- `top1=0.6875`
- `topk=1.0`
- `humming_like: n=4, top1=0.25, topk=1.0`
- `confused: n=1, top1=0.0, topk=1.0`
- manifest 审计结果:
- real-path FMA external smoke 只有 `clean` query
- synthetic_v2 才包含 `augmented` / `humming_like` / `confused`
### 结论
- 当前已经不仅知道“系统能跑通”,还知道“最该优化哪里”:hard-case 的 top1。
- 下一轮更有价值的是围绕 `humming_like` / `confused` 做输入层、切片、混淆增强与 hard negative 优化。
## 本次追加交付(2026-06-02 15:45 UTC)
### 新增运行证据
| 类别 | 内容 |
|---|---|
| baseline sweep | `v3~v6` 已完成统一 hard-case sweep |
| 总体最佳 | `v6`: `top1=0.65`, `topk=0.95` |
| humming_like 最佳 | `v5`: `top1=0.5` |
| confused 最佳 | `v3` / `v6`: `top1=0.25` |
### 当前最重要的 fresh evidence
- 观测时间:`2026-06-02 15:45:18 UTC`
- 汇总文件:`/tmp/synth_v2_baseline_sweep/summary.json`
- 统一评测集:`data/synthetic_v2`
- 结果摘录:
- `v3`: overall `0.6/0.75`, hard-case `hum=0.0`, `conf=0.25`
- `v4`: overall `0.4/0.8`, hard-case `hum=0.0`, `conf=0.0`
- `v5`: overall `0.6/0.9`, hard-case `hum=0.5`, `conf=0.0`
- `v6`: overall `0.65/0.95`, hard-case `hum=0.25`, `conf=0.25`
### 结论
- 当前最合理的下一轮实验基线是 `v6`,因为总体最稳。
-`v5``humming_like` 上明显更强,值得做 targeted diff / 吸收。
## 本次追加交付(2026-06-02 15:46 UTC)
### 新增差异审计证据
| 类别 | 内容 |
|---|---|
| v5 来源 | `type-aware hard-case weighting` |
| v6 来源 | `sample-level confused-priority weighting` |
| 解释 | `v5` 更利于 `humming_like``v6` 更利于 `confused` |
| 决策 | 下一轮应做双轴 hard-case weighting / 分治,而不是单轴加权 |
### 当前最重要的 fresh evidence
- `docs/CHANGELOG.md:2954+``v6` = sample-level confused-priority weighting
- `docs/CHANGELOG.md:6805+``v5` = type-aware hard-case weighting
- `docs/sota-research-2026.md:113-114`
- `v5`: `overall=0.60`, `humming_like=0.50`, `confused=0.00`
- `v6`: `overall=0.65`, `humming_like=0.25`, `confused=0.25`
### 结论
- 现在已经不仅知道 `v5/v6` 哪个更强,还知道“为什么”。
- 下一轮应把 `humming_like``confused` 分开建模或分开加权。
## 本次追加交付(2026-06-02 15:47 UTC)
### 新增代码能力
| 文件 | 变更 |
|---|---|
| [../acr-engine/src/data/dataset.py](../acr-engine/src/data/dataset.py) | hard-case 采样权重与 pair 权重改为配置驱动 |
| [../acr-engine/train.py](../acr-engine/train.py) | 训练链路透传 dual-axis 权重配置 |
| [../acr-engine/configs/default.yaml](../acr-engine/configs/default.yaml) | 增加 `sample_type_weights` / `pair_type_weights` 默认配置 |
### 当前最重要的 fresh evidence
- `python -m py_compile train.py src/data/dataset.py`:通过
- `train.py --data data/synthetic_v2 --device cpu --epochs 1 --batch-size 4 --dry-run`:通过
- 自定义权重实例化检查:
- `dataset_len=96`
- `unique_songs=16`
- `sample_multiplicity_minmax=6/6`
- `hard_weight=[5.0, 1.0]`
### 结论
- dual-axis hard-case weighting 已从“设计建议”升级为“代码中可直接调参实验”的状态。
- 下一轮可直接围绕 `sample_type_weights``pair_type_weights` 做最小实验。
## 本次追加交付(2026-06-02 15:56 UTC)
### 新增运行证据
| 类别 | 内容 |
|---|---|
| dual-axis smoke | `train -> build-index -> evaluate` 完整跑通 |
| 训练输出 | `/tmp/dualaxis_smoke/models/best_model.pt` |
| 索引输出 | `/tmp/dualaxis_smoke/index/` |
| 评测输出 | `/tmp/dualaxis_smoke/eval.json` |
| 结果 | `top1=0.5`, `topk=0.9` |
| hard-case | `humming_like=0.0`, `confused=0.25` |
### 当前最重要的 fresh evidence
- `num_queries=20`
- `clean: n=8, top1=0.875, topk=1.0`
- `augmented: n=4, top1=0.5, topk=0.75`
- `humming_like: n=4, top1=0.0, topk=0.75`
- `confused: n=4, top1=0.25, topk=1.0`
### 结论
- 目前这组 dual-axis 配置证明了“可配置实验链路”是通的。
- 但它没有带来 `humming_like` 改善,说明后续搜索需要更细:该拆分 `sample_type_weights``pair_type_weights` 的取值粒度。
## 本次追加交付(2026-06-02 16:03 UTC)
### 新增运行证据
| 候选 | top1 | topk | humming_like top1 | confused top1 | 结论 |
|---|---:|---:|---:|---:|---|
| hum_focus | 0.7 | 0.85 | 0.5 | 0.25 | 当前最优 |
| hum_balanced | 0.65 | 0.95 | 0.25 | 0.25 | 只回到 v6 水平 |
### 当前最重要的 fresh evidence
- 观测时间:`2026-06-02 16:03:13 UTC`
- `hum_focus` 结果文件:`/tmp/dualaxis_sweep/hum_focus/eval.json`
- `hum_balanced` 结果文件:`/tmp/dualaxis_sweep/hum_balanced/eval.json`
- 对比结论:`hum_focus``humming_like` 上优于 `hum_balanced`,且总体更优。
### 结论
- 当前 dual-axis 线的最佳候选已收敛为 `hum_focus`
- 下一轮应围绕 `hum_focus` 做微调搜索,而不是回退到 `v6` 或扩大盲搜范围。
## 本次交付包追加更新(2026-06-02 16:03 UTC)
### 交付结论
当前最新里程碑已经从“dual-axis 首轮可跑通”推进到 **dual-axis 候选已收敛到 hum_focus**
- 远程基线当前为:`9c3f182`(更新前)
- `hum_focus` 当前优于 `hum_balanced``v6` 基线
- 因此下一轮应围绕 `hum_focus` 做微调,而不是回退或盲搜
### 当前最新事实
#### dual-axis 对比结果
- `hum_focus`
- `top1=0.7`
- `topk=0.85`
- `humming_like=0.5`
- `confused=0.25`
- `hum_balanced`
- `top1=0.65`
- `topk=0.95`
- `humming_like=0.25`
- `confused=0.25`
### 当前判断
- `hum_focus` 是目前最值得继续迭代的 dual-axis 起点。
- 下一阶段建议是以 `hum_focus` 为锚点做小步搜索,优先保住 `humming_like` 优势。
## 本次交付包追加更新(2026-06-02 16:11 UTC)
### 交付结论
最新的 `hum_guard` 复核结果已经确认:
- 它没有超过 `hum_focus`
- `topk` 持平,但 `top1` 更低
- 所以下一轮仍应围绕 `hum_focus` 微调
### fresh evidence
- `num_queries=20`
- `top1=0.6`
- `topk=0.85`
- `humming_like top1=0.5`
- `confused top1=0.0`
---
## 本次交付包追加更新(2026-06-02 16:12 UTC)
### 交付结论
当前已经完成“先交付、后续续跑”的冻结动作:
- 交接文档已补齐最新快照
- 新 session 可直接从这些文件继续
- 当前最重要的优化方向仍是 `hum_focus`
### 当前可直接继承的内容
- 训练数据规范
- pgvector 导出规范
- FMA / 开源数据接入说明
- SOTA 研究和切片策略说明
### 重启后建议顺序
1.`docs/session-handoff.md`
2.`docs/CHANGELOG.md`
3. 继续做 `hum_focus` 小步搜索
4. 再做训练 / 评测 / 提交闭环
---
## 本次交付包追加更新(2026-06-02 15:56 UTC)
### 交付结论
当前最新里程碑已经从“dual-axis 参数化完成”推进到 **dual-axis smoke 首次端到端评测完成**
- 远程基线当前为:`6279850`(更新前)
- 训练、建索引、评测全部跑通
- 但这组权重没有改善 `humming_like`,说明接下来要做更细粒度搜索
### 当前最新事实
#### dual-axis smoke 结果
- 观测时间:`2026-06-02 15:56:02 UTC`
- 结果文件:`/tmp/dualaxis_smoke/eval.json`
- 评测结果:
- `num_queries=20`
- `top1=0.5`
- `topk=0.9`
- `clean=0.875`
- `augmented=0.5`
- `humming_like=0.0`
- `confused=0.25`
### 当前判断
- dual-axis 入口是可用的,但当前试验组合不是更优解。
- 下一阶段应进入更细粒度的权重搜索,而不是直接扩大规模。
---
## 本次交付包追加更新(2026-06-02 15:47 UTC)
### 交付结论
当前最新里程碑已经从“知道该做 dual-axis”推进到 **dual-axis hard-case weighting 已在代码中参数化**
- 远程基线当前为:`7812b58`(更新前)
- `sample_type_weights``pair_type_weights` 已可配置
- 训练 dry-run 已通过
- 因此下一轮可直接做最小调参实验,而不是再先改代码结构
### 当前最新事实
#### 代码实现位置
- `src/data/dataset.py`
- `sample_type_weights` 控制 song-level 采样重复度
- `pair_type_weights` 控制 pair-level `hard_weight`
- `train.py`:从 `training` 配置透传
- `configs/default.yaml`:提供默认 dual-axis 配置
#### fresh verification
- `python -m py_compile train.py src/data/dataset.py`:通过
- `train.py --data data/synthetic_v2 --device cpu --epochs 1 --batch-size 4 --dry-run`:通过
- 自定义权重实例化检查:
- `dataset_len=96`
- `sample_multiplicity_minmax=6/6`
- `hard_weight=[5.0, 1.0]`
### 当前判断
- 现在已经具备一个最小、低风险、可反复实验的 dual-axis 入口。
- 下一阶段最值得做的是直接搜索 `humming_like` / `confused` 的权重组合,而不是继续做只读分析。
---
## 本次交付包追加更新(2026-06-02 15:46 UTC)
### 交付结论
当前最新里程碑已经从“确定 v6/v5 谁更适合作为基线”推进到 **解释清楚它们为什么会这样表现**
- 远程基线当前为:`93dfa15`(更新前)
- `v5` 的关键机制是 `type-aware hard-case weighting`
- `v6` 的关键机制是 `sample-level confused-priority weighting`
- 因此下一轮最合理的不是继续盲 sweep,而是做 `humming_like``confused` 的双轴分治策略
### 当前最新事实
#### v5 / v6 差异来源
- `v5`
- 历史记录位置:`docs/CHANGELOG.md:6805+`
- 定义:`type-aware hard-case weighting`
- 结果:`humming_like top1=0.50`, `confused top1=0.00`
- `v6`
- 历史记录位置:`docs/CHANGELOG.md:2954+`
- 定义:`sample-level confused-priority weighting`
- 结果:`humming_like top1=0.25`, `confused top1=0.25`
- 汇总解释:`docs/sota-research-2026.md:113-114`
### 当前判断
- `v5``v6` 的差异已经可解释,不再是黑箱经验差异。
- 下一阶段最值得做的是:
1. 设计双轴 hard-case weighting;
2.`humming_like``confused` 分开控制;
3. 再用现有双轨验证链回归测试。
---
## 本次交付包追加更新(2026-06-02 15:45 UTC)
### 交付结论
当前最新里程碑已经从“知道 hard-case 有缺口”推进到 **知道哪套历史基线最值得作为下一轮优化起点**
- 远程基线当前为:`d4961b1`(更新前)
- `v6` 是当前总体最优基线:`top1=0.65`, `topk=0.95`
- `v5``humming_like` 上更强:`top1=0.5`
- 因此下一轮不该盲改,而应以 `v6` 为主基线,对比吸收 `v5` 的 hard-case 优势
### 当前最新事实
#### hard-case baseline sweep
- 观测时间:`2026-06-02 15:45:18 UTC`
- 汇总:`/tmp/synth_v2_baseline_sweep/summary.json`
- 结果:
- `v3`: overall `top1=0.6`, `topk=0.75`; `humming_like=0.0`, `confused=0.25`
- `v4`: overall `top1=0.4`, `topk=0.8`; `humming_like=0.0`, `confused=0.0`
- `v5`: overall `top1=0.6`, `topk=0.9`; `humming_like=0.5`, `confused=0.0`
- `v6`: overall `top1=0.65`, `topk=0.95`; `humming_like=0.25`, `confused=0.25`
### 当前判断
- `v6` 适合作为下一轮总体优化主基线。
- `v5` 适合作为 `humming_like` 对照基线。
- 下一阶段最值得做的是:
1. 审计 `v5``v6` 的配置/数据/切片差异;
2.`v5``humming_like` 优势迁移到 `v6`
3. 再用真实路径 clean + synthetic hard-case 双轨复测。
---
## 本次交付包追加更新(2026-06-02 15:43 UTC)
### 交付结论
当前最新里程碑已经从“real-path clean 闭环跑通”推进到 **hard-case 短板已被明确量化**
- 远程基线当前为:`81704ac`(更新前)
- real-path FMA smoke 已证明 `clean` 闭环可跑通
- synthetic hard-case smoke 已证明当前主要短板在 `humming_like` / `confused` 的 top1
- 因此下一阶段不应重复 clean smoke,而应聚焦 hard-case 鲁棒性优化
### 当前最新事实
#### hard-case smoke 结果
- 观测时间:`2026-06-02 15:43:17 UTC`
- 组合:`data/synthetic_v2` + `data/models_v6/best_model.pt` + `data/index_v6/reference`
- 结果文件:`/tmp/synthetic_v2_eval_v6_top16.json`
- 评测结果:
- `num_queries=16`
- `top1=0.6875`
- `topk=1.0`
- `clean: n=7, top1=1.0, topk=1.0`
- `augmented: n=4, top1=0.75, topk=1.0`
- `humming_like: n=4, top1=0.25, topk=1.0`
- `confused: n=1, top1=0.0, topk=1.0`
#### 关键解释
- real-path FMA external smoke manifest 目前只有 `clean` query:
- external test = `1613 clean`
- rerun overlap test = `35 clean`
- 当前仓库里能提供 `humming_like` / `confused` 的现成评测集是 `data/synthetic_v2`
### 当前判断
- 真实路径闭环已经足够证明工程链可运行。
- 下一阶段的收益最高点已经收敛到:
1. `humming_like` top1 提升;
2. `confused` top1 提升;
3. 将 hard-case 生成/标注引入真实开放数据评测链。
---
## 本次交付包追加更新(2026-06-02 15:40 UTC)
### 交付结论
当前最新里程碑已经从“reference index 完成”推进到 **fixed real-path 200-ref rerun 已拿到首份显式 evaluate 指标**
- 远程基线当前为:`9371e94`(更新前)
- real-path `200-ref` index 已完整完成
- 显式 `evaluate.py` smoke 已完成
- 当前首份结果:`top1=0.8571`, `topk=1.0`, `num_queries=35`
- 因此主线已从“索引能否跑通”进入“评测质量与 hard case 扩展”阶段
### 当前最新事实
#### evaluate smoke 路径
- 观测时间:`2026-06-02 15:40:30 UTC`
- 结果文件:`/tmp/fma_realpath_small_rerun_eval/eval_top50.json`
- 评测结果:
- `split=test`
- `num_queries=35`
- `top1=0.8571`
- `topk=1.0`
- `by_type.clean`: `n=35`, `top1=0.8571`, `topk=1.0`
- query 数来源说明:
- 200-ref catalog 与现有 external smoke test overlap = `235` items
- 其中非 `reference` query = `35`
- 所以 `--max-queries 50` 实际只评到 `35`
### 当前判断
- 当前已经拥有一条完整可复用的真实路径 smoke 证据链:
`chromaprint complete -> reference complete -> evaluate complete`
- 下一阶段更值得做的是:
1. 扩大评测 query 数与 reference 规模;
2. 引入 `confused` / `humming_like` / hard negative 评测。
---
## 本次交付包追加更新(2026-06-02 15:35 UTC)
### 交付结论
当前最新里程碑已经从“进入 reference 阶段”推进到 **fixed real-path 200-ref rerun 已完整产出最终 embedding/reference index**
- 远程基线当前为:`41c4d7c`(更新前)
- chromaprint 已完整完成:`200/200`
- reference 已完整完成:`200/200`
- 最终产物 `reference_embs.npy` / `reference_ids.npy` 已落盘
- 因此主问题已从“能否穿过建索引核心阶段”转向“后续 evaluate / identify 链如何衔接验证”
### 当前最新事实
#### fixed real-path rerun 路径
- 观测时间:`2026-06-02 15:35:19 UTC`
- 输出目录:`/tmp/fma_realpath_small_rerun_index2`
- `chromaprint_progress.json`
- `status=complete`
- `refs_done=200 / 200`
- `hashes=57577`
- `postings=187446`
- `skipped_refs=0`
- `reference_progress.json`
- `status=complete`
- `refs_done=200 / 200`
- `windows_done=2068`
- `elapsed_sec=410.046`
- `embedding_shape=[2068, 192]`
- `skipped_refs=0`
- 当前已出现最终产物:
- `reference_embs.npy`
- `reference_ids.npy`
### 当前判断
- 这条 fixed rerun 已经给出强证据:`flush=True` 与坏音频 skip tolerance 修复后,真实路径样本可以完整跑完两段核心建索引流程。
- 下一阶段应集中验证:
1. 是否自动衔接到 evaluate / identify;
2. 若没有,补一轮显式 evaluate smoke。
---
## 本次交付包追加更新(2026-06-02 15:29 UTC)
### 交付结论
当前最新里程碑不是新的失败,而是 **fixed real-path 200-ref rerun 已明确跨入 reference/embedding 阶段**
- 远程基线当前为:`707449b`
- chromaprint 已完整完成:`200/200`
- reference 阶段已写出首个 checkpoint:`25/200`
- 已出现 `reference_progress.json` 与 partial numpy 产物
- 因此下一 session 不应再把这条 rerun 当作“停在 chromaprint 无下游文件”的旧状态
### 当前最新事实
#### fixed real-path rerun 路径
- 前台 session:`19709`
- 观测时间:`2026-06-02 15:29:17 UTC`
- 输出目录:`/tmp/fma_realpath_small_rerun_index2`
- `chromaprint_progress.json`
- `status=complete`
- `refs_done=200 / 200`
- `hashes=57577`
- `postings=187446`
- `skipped_refs=0`
- `reference_progress.json`
- `status=building`
- `refs_done=25 / 200`
- `windows_done=256`
- `elapsed_sec=52.567`
- `eta_sec=367.967`
- `skipped_refs=0`
- 当前已出现:
- `reference_embs.partial.npy`
- `reference_ids.partial.npy`
### 当前判断
- `flush=True` 与坏音频 skip tolerance 修复之后,真实路径 rerun 已穿过 `chromaprint -> reference` 阶段边界。
- 当前最高优先级不再是重复证明 chromaprint 完成,而是继续盯 reference 阶段是否:
1. 完整落盘 `reference_embs.npy` / `reference_ids.npy`;或
2. 暴露新的明确 traceback / failure evidence。
### 建议的新 session 接管顺序
1. 先看 [./session-handoff.md](./session-handoff.md) 顶部新快照
2. 读取前台 `session 19709` 最新输出
3. 检查 `/tmp/fma_realpath_small_rerun_index2/` 是否已从 partial 转为 final 产物
---
# Delivery Handoff / 2026-06-02
## 本次交付包(2026-06-02 15:09 UTC)
### 交付结论
这次新增的关键交付,不再是单纯的进度观察,而是一个**新的异常状态检查点**
- 远程基线已推进到:`cdf33bb`
- observable chromaprint smoke 与 legacy 全量 FMA `build-index` 进程都已退出
- 但两者都**没有**进入 `reference_*` / `evaluate.py`
- 因此下一 session 的首要任务,已从“盯进度”切换为“排查 `build-index` 异常退出”
### 当前最新事实
#### observable 路径
- 原进程:`PID=431703`
- 最后观测时间:`2026-06-02 15:09:19 UTC`
- 当前 `ps -p 431703`:无存活进程
- 当前目录仅有:
- `chromaprint.pkl`
- `chromaprint_progress.json`
- 最后 progress 状态:
- `status=building`
- `refs_done=4420 / 8000`
- `elapsed_sec=3964.861`
- `hashes=357373`
- `postings=3774363`
- 当前**仍未出现**
- `reference_progress.json`
- `reference_embs.partial.npy`
- `reference_ids.partial.npy`
- `reference_embs.npy`
- `reference_ids.npy`
- `evaluate.py`
#### legacy 全量 FMA 路径
- 原进程:`PID=424691`
- 当前 `ps -p 424691`:无存活进程
- 当前目录仍只有:
- `/tmp/fma_real_smoke_stopcheck/fma_index_smoke`
- 仍未看到 index artifact 或 `evaluate.py`
#### 当前判断
- 这不再是“CPU-only 长时间构建但仍在推进”的状态。
- 现在更像是:**`build-index` 在 chromaprint 阶段中途退出,但没有留下显式下游产物**
#### 已完成的低风险修复
- 已把 `run_demo.py``chromaprint_matcher.py``ecapa_embedder.py` 的关键日志改为 `flush=True`
- 极小样本 `/tmp/chroma_repro_tiny12` 已验证:失败时日志与 traceback 可实时落盘,不再保持 `0 bytes`
- 这意味着下一 session 继续排查时,日志可作为一手证据,而不是黑箱。
#### 已完成的坏音频容错修复
- 已为 chromaprint/reference 两个建索引阶段增加单文件容错:坏 MP3 / 缺失音频会被记录并跳过。
- 最小复现 `/tmp/chroma_skip_repro` 已验证:
- `RC=0`
- `skip decode failure` 日志可见
- `reference_embs.npy` / `reference_ids.npy` 成功产出
- progress 中记录 `skipped_refs=1`
- 这说明:单个坏 MP3 不再拖垮整轮 `build-index`
## 新 session 接管顺序
1. 先看 [./session-handoff.md](./session-handoff.md)
2. 再看 [./changelist-2026-06-02.md](./changelist-2026-06-02.md)
3. 然后优先做 3 件事:
1. 复盘 `run_demo.py build-index` 的退出路径与异常处理
2. 检查是否存在未捕获 OOM / shell termination / silent failure
3. 在更小样本上复现“chromaprint 中途退出但无后续文件”的行为
## 当前卡点
1. 关键进程已经退出,但没有明确 traceback 留存。
2. observable 与 legacy 两条路径都停在“没有 `reference_*` / 没有 `evaluate.py`”的中间态。
3. 工作树仍有大量数据噪音,提交时必须只显式暂存文档/代码文件。
## 本次交付包含的关键文档
- [./CHANGELOG.md](./CHANGELOG.md)
- [./changelist-2026-06-02.md](./changelist-2026-06-02.md)
- [./session-handoff.md](./session-handoff.md)
- [../AGENT.md](../AGENT.md)
## 本次明确不提交
- `acr-engine/data/raw/*`
- `acr-engine/data/external_smoke/*`
- `/tmp/*`
- checkpoint / index artifacts
- `__pycache__`
# External Manifest Template
适用于 FMA / Jamendo / CCMusic / ModelScope 白名单数据集。
## catalog.csv 最小字段
```csv
song_id,audio_path,duration,source_dataset
track_0001,raw/track_0001.wav,12.5,fma
```
转换命令:
```bash
python src/data/manifest_tools.py csv-to-catalog catalog.csv manifests/catalog.json
```
## 输出 catalog.json 结构
```json
{
"song_id": "track_0001",
"audio_path": "raw/track_0001.wav",
"duration": 12.5,
"type": "reference",
"source_dataset": "fma"
}
```
# Open Dataset Integration Plan
## Recommended order
1. **FMA small**
- URL: https://github.com/mdeff/fma
- Why: easiest small realistic music subset for retrieval experiments
2. **MTG-Jamendo**
- URL: https://github.com/MTG/mtg-jamendo-dataset
- Why: larger CC-licensed corpus with scriptable upstream tooling
3. **QBSH / humming corpora**
- Why: add after retrieval baseline is stable
## Repo strategy
- Keep external dataset ingestion optional
- Convert external tracks into:
- `catalog.json` for searchable references
- query segment manifests for evaluation
- Start with small local subsets before full-corpus scaling
# ACR 项目 Roadmap
> 更新:2026-06-02
## Phase 0:原型跑通(当前阶段)
### 目标
完成一个端到端可运行的本地 demo。
### 范围
- [x] 合成数据生成
- [x] 数据增强
- [x] ECAPA embedding 模型
- [x] 传统指纹匹配器
- [x] HybridEngine
- [x] 最小训练入口
- [x] 最小识别入口
- [x] 文档补全
### 验收标准
- 能生成数据
- 能训练至少 1 epoch
- 能建立 reference 索引
- 能对测试片段输出 Top-K 候选
---
## Phase 1:研究验证
### 目标
验证不同场景下识别效果是否可接受。
### 任务
- [ ] 增加 top-1 / top-5 / MRR 评估脚本
- [ ] 对 clean / noisy / stretched / pitch-shifted 分开评测
- [ ] 增加 query-by-humming 专项评测集
- [ ] 加入更稳健的 negative sampling
- [ ] 补充 checkpoint / config versioning
---
## Phase 2:工程化
### 目标
把原型升级为可复现实验项目。
### 任务
- [ ] 增加 `Makefile``justfile`
- [ ] 增加 `pytest` 基础测试
- [ ] 增加日志与指标记录
- [ ] 增加模型导出与加载规范
- [ ] 增加 CLI 参数校验
- [ ] 增加 Docker 运行方式
---
## Phase 3:产品化 PoC
### 目标
提供可被业务方调用的服务接口。
### 任务
- [ ] FastAPI 服务化
- [ ] 上传音频并返回候选歌曲
- [ ] 曲库增量入库命令
- [ ] 元数据管理接口
- [ ] 结果缓存与批量检索
---
## Phase 4:大规模检索
### 目标
支持百万级以上曲库。
### 任务
- [ ] 接入 Faiss / HNSW
- [ ] embedding 分片与压缩
- [ ] 双层召回 + 精排
- [ ] 在线索引更新
- [ ] 冷热分层存储
---
## Phase 5:真实业务能力
### 目标
逼近真实听歌识曲产品。
### 任务
- [ ] 真实版权音频数据接入
- [ ] 哼唱专项模型/旋律塔
- [ ] 多模态融合(旋律 + 声纹 + 指纹)
- [ ] 在线 A/B 评估
- [ ] 监控与质量回流
......@@ -5,267 +5,204 @@
> 1. 当前项目已经走到哪里
> 2. 应该先读哪些文档
> 3. 应该从哪一步开始推进
> 4. 哪些是当前稳定结论,哪些还只是待验证假设
> 4. 哪些是稳定结论,哪些还是待验证缺口
---
## 首选启动流程(最短路径)
## 0. 下次启动先做什么
下次启动如果目标是“先判断当前 host 能不能继续推进 Phase-1”,不要先手工翻很多文档,先直接跑
先执行
```bash
cd /workspace/acr-engine
/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
/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
```
当前这条命令的 fresh evidence 已有:
也可以用包装脚本:`acr-engine/scripts/start_phase1_shortest_path.sh 'postgres://d2:d2pass@127.0.0.1:5432/d2'`
当前 fresh evidence:
- `executed_count = 4`
- `all_passed = true`
它会一次性执行:
这条 runner 会一次性执行:
1. `prereq_audit`
2. `worker_contract_smoke`
3. `semantic_vector_negative_matrix`
4. `asset_level_upsert_validation`
### 跑完之后怎么判断
如果结果仍是当前状态:
如果结果仍是:
- `downloads_root_exists = false`
- `ready_jobs = 0`
- exact = `failed/unreadable_audio_assets`
- semantic = `4/4 failed`
那么说明:
> 当前不该继续怀疑 PostgreSQL contract,而应该优先解决 **音频挂载** 与 **模型 runtime 依赖**。
如果未来这条 runner 开始失败,才优先检查:
- planner 报告是否变了
- validation scripts 是否回归
- schema / worker contract 是否被破坏
## 一页结论
当前项目主线已经从“原型是否能跑通”切到:
> **为版权保护场景建设一个可演进的音乐 ACR / 检索系统**,
> 目标是让 `100w` 音频、约 `30w` 歌曲能够在未来通过
> `canonical_song / work / recording / recording_asset / audio_window`
> 这条主数据链,以及 `model_registry / feature_set_registry`
> 这套模型注册机制,稳定支撑检索、归属、升级与回滚。
当前已经完成的关键交付:
- 文档体系已重构为“角色化阅读路径”
- SOTA 演进路径已明确:**Phase-1 先走 encoder-only**
- PostgreSQL 主数据与特征注册 DDL 已落地为推荐版 schema
- Phase-1 实施 checklist 和 model/feature/reference set 初始化手册已补齐
- `acr_test` schema 上已经真实完成 Phase-1 `model_registry / feature_set_registry / reference_set_registry` bootstrap 验证
则说明当前优先级仍然是:
1.`/workspace/downloads` 挂载
2.`torch / torchaudio / transformers / speechbrain`
当前最重要的下一步不是继续写方案,而是:
1. **按 schema v2 落 PostgreSQL 主数据模型**
2. **把 reference set / audio_window / feature_set 初始化做起来**
3. **接入 MERT / MuQ 的 encoder-only 抽特征链**
4. **跑通 fingerprint lane + semantic lane 的第一版聚合闭环**
而不是回头怀疑 PostgreSQL contract。
---
## 下次启动先读什么
## 1. 当前项目一句话状态
### 最短阅读顺序(推荐)
1. [docs/README.md](./README.md)
2. [docs/acr-architecture.md](./acr-architecture.md)
3. [docs/sota-evolution-guide.md](./sota-evolution-guide.md)
4. [docs/postgresql-data-model.md](./postgresql-data-model.md)
5. [docs/phase1-implementation-checklist.md](./phase1-implementation-checklist.md)
6. [docs/model-feature-registry-bootstrap.md](./model-feature-registry-bootstrap.md)
7. [docs/phase1-worker-contract.md](./phase1-worker-contract.md)
8. [docs/CHANGELOG.md](./CHANGELOG.md)
项目已经从“原型能否跑通”转为:
如果只想快速恢复上下文,至少读前 5 个。
> **面向版权保护 / 听歌识曲 / 版本归属的可演进音乐 ACR 系统。**
---
当前目标是让 `100w` 音频、约 `30w` 歌曲能通过稳定的数据主链和模型注册机制,支撑检索、归属、升级与回滚。
## 当前稳定结论(可以直接继承)
---
### 1. 技术方向
- **当前 ECAPA 路线保留为 baseline,不再作为长期主底座。**
- **Phase-1 主推 encoder-only foundation 路线。**
- exact lane:`Chromaprint`
- semantic lane 主 baseline:`MERT-v1-95M`
- semantic lane challenger:`MuQ`
- **Phase-2 才考虑 version / cover lane。**
- **Phase-3 再进入工业化检索/重排/治理。**
## 2. 当前稳定结论
### 2. 数据主链
后续主数据一律围绕:
### 技术路线
- exact lane:`Chromaprint`
- semantic baseline:`MERT-v1-95M`
- semantic challenger:`MuQ`
- `ECAPA`:historical baseline
- Phase-1:先走 **encoder-only**,先不用微调底座
### 数据主链
```text
canonical_song -> work -> recording -> recording_asset -> audio_window
```
不要再退回到仅有 `song_id` 的扁平结构。
### 3. 模型/特征主链
后续 encoder、feature、索引一律围绕:
### 模型主链
```text
model_registry -> feature_set_registry -> audio_embedding / audio_fingerprint -> retrieval_index_registry
```
不要设计成固定列:
- `mert_embedding`
- `muq_embedding`
- `ecapa_embedding`
### 4. reference 集合
当前结论是:
- 需要显式 `reference_set_registry`
- `is_reference=true` 仍然保留,但不再足够表达生产切换
- 未来热 reference 集、A/B、回滚、encoder 升级都要依赖 reference set 版本化
### reference set 结论
- 保留 `is_reference=true`
- 但生产切换必须依赖 `reference_set_registry / reference_set_member`
- 后续 A/B、热切换、回滚都围绕 reference set 版本化进行
---
## 本轮新增/修改的关键文件
## 3. 当前已经完成的关键交付
### 主文档
- [docs/README.md](./README.md)
- [docs/acr-architecture.md](./acr-architecture.md)
- [docs/sota-evolution-guide.md](./sota-evolution-guide.md)
- [docs/postgresql-data-model.md](./postgresql-data-model.md)
- [docs/phase1-implementation-checklist.md](./phase1-implementation-checklist.md)
- [docs/model-feature-registry-bootstrap.md](./model-feature-registry-bootstrap.md)
### 文档与设计
- 文档主入口已收敛到 `README -> start-here -> session-handoff`
- SOTA 演进路径已明确
- PostgreSQL 主数据与特征模型已固定为 v2 推荐方案
- Phase-1 实施 checklist / registry bootstrap / worker contract 文档已齐备
### SQL / schema
- `acr-engine/sql/acr_pg_schema_v2.sql`
### PostgreSQL / live contract
- `acr-engine/sql/acr_pg_schema_v2.sql` 已落地
- `model_registry / feature_set_registry / reference_set_registry` 已 live bootstrap 验证
- `audio_embedding` 的 asset-level 幂等 upsert 已 live 验证
- semantic vector-table 负例矩阵已 live 验证
- planner validation commands 已可被 runner 一键执行
### 历史/补充说明(仍有参考价值)
- [docs/sota-research-2026.md](./sota-research-2026.md)
- [docs/production-encoder-freeze-and-embedding-strategy.md](./production-encoder-freeze-and-embedding-strategy.md)
- [docs/training-data-and-pgvector-guide.md](./training-data-and-pgvector-guide.md)
### worker / script
- `run_chromaprint_job.py` 已具备真实写入路径
- `run_embedding_job.py` 已具备 preflight failure contract
- `run_phase1_prereq_audit_live.py` 已能输出 host 前置条件审计
- `run_planner_validation_commands_live.py` 已收敛最短验证链路
---
## 当前推荐的启动动作
## 路线 A:如果下次 session 继续“补文档/补设计”
优先顺序:
1.**数据导入手册**:100w 音频如何映射到 `canonical_song/work/recording/recording_asset`
2.**检索聚合设计文档**:fingerprint lane + semantic lane 的分数融合与 song/work 聚合规则
3.**索引与版本治理文档**:reference set / feature set / index set 的上线切换规则
## 路线 B:如果下次 session 开始“进入实现”
直接按下面顺序推进:
1. 建库执行 `acr-engine/sql/acr_pg_schema_v2.sql`
2. 初始化 `canonical_song / work / recording / recording_asset`
3. 初始化 `reference_set_registry`
4. 生成 `audio_window`
5. 初始化 `model_registry / feature_set_registry`
6. 接入 MERT / MuQ encoder-only 抽特征
7. 构建 semantic index
8. 跑通 query -> candidate -> canonical_song 闭环
## 4. 当前明确的 blocker
---
### 环境 blocker
- `/workspace/downloads` 缺失
- 缺少 `torch`
- 缺少 `torchaudio`
- 缺少 `transformers`
- 缺少 `speechbrain`
## 下次 session 第一条可直接复制执行的检查命令
### 能力 blocker
- 还未真实跑通 `MERT / MuQ` inference
- 还未完成线上融合策略
- 还未接入更大规模真实 reference set
```bash
cd /workspace
sed -n '1,220p' docs/README.md
sed -n '1,260p' docs/phase1-implementation-checklist.md
sed -n '1,260p' docs/model-feature-registry-bootstrap.md
sed -n '1,260p' docs/postgresql-data-model.md
```
因此当前最该优先推进的是:
> **把环境补齐,再把 semantic lane 从 guarded failure 推到真实抽特征。**
---
如果要直接看 schema:
## 5. 下次启动先读什么
```bash
cd /workspace
sed -n '1,320p' acr-engine/sql/acr_pg_schema_v2.sql
```
按这个顺序即可:
1. [README.md](./README.md)
2. [start-here.md](./start-here.md)
3. [acr-architecture.md](./acr-architecture.md)
4. [postgresql-data-model.md](./postgresql-data-model.md)
5. [phase1-implementation-checklist.md](./phase1-implementation-checklist.md)
6. [model-feature-registry-bootstrap.md](./model-feature-registry-bootstrap.md)
7. [phase1-worker-contract.md](./phase1-worker-contract.md)
8. [CHANGELOG.md](./CHANGELOG.md)
---
## 当前实现与未来实现的边界
### 当前仓库已经有的东西
- `Chromaprint` 原型链
- `ECAPA` embedding baseline
- hybrid engine 原型
- 早期 pgvector prototype schema
## 6. 下次启动优先动作
### 当前还没做完的东西
- PostgreSQL v2 schema 的实际落库
- Phase-1 的 reference set 初始化
- MERT / MuQ encoder-only 特征抽取与入库
- semantic lane 的第一版 production-oriented 聚合
### 路线 A:继续环境恢复
1. 检查 `/workspace/downloads` 是否已挂载
2. 检查 `torch / torchaudio / transformers / speechbrain` 是否已可导入
3. 重跑 planner validation runner
4. 确认 `ready_jobs` 是否从 `0` 开始提升
所以:
### 路线 B:继续语义特征抽取实现
1. 查看 `acr-engine/workers/run_embedding_job.py`
2. 保持现有失败语义 contract
3. 接入真实 inference adapter
4. 复用现有 `audio_embedding` upsert 逻辑
> 当前项目的“方案层”已经足够启动实现,
> 下次 session 不应再从头讨论“要不要 song/work/recording”,
> 而应该直接进入 **Schema -> Reference Set -> Feature Set -> Extraction -> Retrieval** 的执行链。
### 路线 C:继续数据规模化落库
1. 查看 [postgresql-data-model.md](./postgresql-data-model.md)
2. 查看 [postgres_db_schema_samples.md](./postgres_db_schema_samples.md)
3. 规划 100w 音频导入批次
4. 固定 `reference_set` / `feature_set` / `index` 版本治理
---
## 当前验证状态
## 7. 当前不要再重复讨论的结论
### 已验证
- 新文档结构已补齐并接入 README
- Phase-1 方案、PostgreSQL 设计、实施 checklist、registry bootstrap 均已提交
- architect 审核结论:**APPROVED**
- 代码已推送远端
- PostgreSQL `acr_test` live 路径已再次验证:`recording` / `audio_window` / `audio_embedding` 三类 lineage trigger 均有真实负例证据
- 机械校验已补齐:`live_pgvector_music20_eval.py``py_compile` 通过,相关变更 `diff --check` 通过
- PostgreSQL `acr_test` schema 上已真实写入 Phase-1 registry bootstrap:`chromaprint / mert / muq / ecapa` + 5 组 feature set + `phase1_hot_reference_v1`
- Phase-1 registry bootstrap 已有幂等性证据:同 schema 连续执行两次后,`model_registry=5 / feature_set_registry=6 / reference_set_registry=2` 保持不变
- PostgreSQL `acr_test` schema 上已真实创建 5 条 `feature_extraction_job`,后续 MERT / MuQ 接入可直接从 pending jobs 启动
- PostgreSQL `acr_test` schema 上已真实生成 Phase-1 extraction execution plan,当前顺序是 `chromaprint -> mert -> mert-long -> muq -> ecapa`
- extraction plan 报告里已包含 `command_suggestions / primary_command`,下次可直接从 plan 抄 worker 命令模板
- Phase-1 worker 入口已真实落地:`run_chromaprint_job.py / run_embedding_job.py / mark_job_status.py`
- 下一阶段已经不是“补 planner”,而是把 dry-run worker 替换为真实 extractor,并把 `audio_fingerprint / audio_embedding` 写入做成幂等执行
- semantic lane 也已完成 live failure contract:`run_embedding_job.py` 现在会同时暴露 `unreadable_audio_assets``model_runtime_unavailable`,而不是把失败伪装成 completed
- `audio_embedding` 已补上 window / asset 双路唯一键,后续真实 encoder 只需替换 inference adapter 即可复用同一 upsert 合同
- `scripts/run_phase1_embedding_preflight_matrix_live.py` 已跑通,4 条 semantic jobs(mert/muq/ecapa)在 `acr_test` 上都被稳定标记为 `preflight_failed`;当前共性 blocker 已收敛为 `/workspace/downloads` 缺失 + 语义模型 runtime 缺失
- `scripts/validate_audio_embedding_asset_upsert_live.py` 已在隔离 schema `acr_asset_upsert_test` 上验证 `uq_audio_embedding_feature_asset`:重复 insert 会被唯一键拒绝,upsert 会复用同一 `embedding_id`,说明 asset-level 幂等键也已有真实证据
- `scripts/run_phase1_worker_contract_smoke_live.py` 已提供一条命令的全局 smoke:当前 exact lane = `failed/unreadable_audio_assets`,semantic lane = `4/4 failed`,共性 blocker 已固化为音频挂载缺失 + 语义模型 runtime 缺失
- `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`
- `scripts/run_phase1_prereq_audit_live.py` 已给出当前 host 的先决条件审计:`downloads_root_exists=false``ready_jobs=0/5`,并把 `torch/torchaudio/transformers/speechbrain` 的缺失状态按 job 落成 JSON 报告
- `phase1_extraction_plan_report.json` 现已附带 `validation_commands`,下次 session 可以直接从 planner 复制 `prereq_audit / worker_contract_smoke / semantic_vector_negative_matrix / asset_level_upsert_validation` 四类命令
- `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`
- `scripts/run_planner_validation_commands_live.py` 已把这 4 条 validation commands 收敛成通用 runner;当前 `planner_validation_commands_runner_report.json` 显示 `executed_count=4``all_passed=true`
- `phase1_hot_reference_v1``acr_test` 里已经真实补齐 `20` 个 reference members,因此 worker dry-run 当前看到的 scope 已是 `20 recordings / 20 assets / 20 windows`
- worker contract 现在已有基础前置状态保护;重复执行同一 chromaprint dry-run job 会被 `expected_status=pending` 明确拒绝,证据见 `phase1_worker_double_claim_guard_report.json`
- exact lane 的 `run_chromaprint_job.py` 已具备非 dry-run 写入路径;当前在 `acr_test` 的 live 结果是因为 `/workspace/downloads/...` 缺失而明确 `failed`,不是继续假装 `completed`
### 未验证 / 仍是缺口
- **未实际跑 MERT / MuQ encoder-only 特征抽取**
- **semantic / cover 等后续 lane 仍主要停留在 dry-run;exact lane 已接上真实 `audio_fingerprint` 写入路径,但当前容器缺 reference 音频挂载,live 结果仍停在可审计失败**
- **还未落更大规模的生产 reference set 真实业务数据(当前仅验证了 `acr_test` 下的 20-song live members)**
- **未定义最终线上分数融合细则**
- **type_8 / type_16 还没有进入当前 live JSONL 的 PostgreSQL 实测链**
- **当前容器里缺少 `/workspace/downloads`,因此暂时无法直接从业务样本目录继续补 type_8 / type_16 live query**
因此下次 session 应优先从这些未验证缺口里挑一条推进,而不是重复写总方案。
- 不要回退到只有 `song_id` 的扁平表
- 不要把 embedding 设计成固定列
- 不要在 Phase-1 先讨论重新训练底座
- 不要把当前问题误判成 PostgreSQL schema 问题
---
## 最近相关提交
## 8. 关键文件入口
### 文档
- [README.md](./README.md)
- [start-here.md](./start-here.md)
- [postgresql-data-model.md](./postgresql-data-model.md)
- [phase1-worker-contract.md](./phase1-worker-contract.md)
按当前 handoff 相关主线,最近重要提交是:
- `a549d1d` — Clarify the ACR evolution path and freeze a production-grade data model
- `e514a6c` — Keep the new ACR architecture guide clean for follow-up edits
- `4b23f54` — Make the Phase-1 ACR plan executable for each delivery role
- `0679481` — Attach runnable command templates to the extraction plan
### 代码与脚本
- `acr-engine/sql/acr_pg_schema_v2.sql`
- `acr-engine/workers/run_chromaprint_job.py`
- `acr-engine/workers/run_embedding_job.py`
- `acr-engine/scripts/run_planner_validation_commands_live.py`
- `acr-engine/scripts/run_phase1_prereq_audit_live.py`
如果下次需要追踪文档补充点,可以从这三个提交开始看。
---
## 9. 当前验证状态摘要
### 已验证
- planner validation runner 可执行且 `all_passed = true`
- exact lane 当前会诚实落成 `failed/unreadable_audio_assets`
- semantic lane 当前会诚实落成 `preflight_failed`
- asset-level embedding upsert 幂等合同已验证
- vector table 负例矩阵已验证
- prerequisites audit 已验证
### 未验证
- MERT / MuQ 真实 inference
- 更大规模生产 reference set 导入
- 最终线上融合与重排策略
---
## 一句话交接
## 一句话 handoff
> **下次启动不要再从“要不要换模型、要不要重构数据结构”开始讨论。**
> 这些方向已经定了。直接从 **PostgreSQL v2 schema 落库 + Phase-1 worker/extractor 执行链** 开始推进。
> 下次接手不要再从总方案开始,先跑 runner;若结果仍显示 downloads/runtime 缺失,就优先补环境,再推进 semantic lane 真实抽特征。
......
# Start Here / 新同学接手入口
> 目标:让新来的同学在 **10 分钟内**知道:先跑什么、先读什么、当前卡在哪、下一步该做什么。
---
## 1. 先执行这条命令
```bash
cd /workspace/acr-engine
/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
```
也可以用包装脚本:`acr-engine/scripts/start_phase1_shortest_path.sh 'postgres://d2:d2pass@127.0.0.1:5432/d2'`
### 当前 fresh evidence
- `executed_count = 4`
- `all_passed = true`
### 这条命令会执行
1. `prereq_audit`
2. `worker_contract_smoke`
3. `semantic_vector_negative_matrix`
4. `asset_level_upsert_validation`
### 看到下面这些结果时应该如何判断
如果你看到:
- `downloads_root_exists = false`
- `ready_jobs = 0`
- exact lane = `failed/unreadable_audio_assets`
- semantic lane = `4/4 failed`
说明当前优先级是:
1. 挂载 `/workspace/downloads`
2. 安装 `torch / torchaudio / transformers / speechbrain`
也就是说:
> 当前首要问题是运行环境前置条件,不是 PostgreSQL schema,也不是 worker contract 设计错误。
---
## 2. 接手时只读这 5 份文档
1. [README.md](./README.md)
2. [session-handoff.md](./session-handoff.md)
3. [acr-architecture.md](./acr-architecture.md)
4. [postgresql-data-model.md](./postgresql-data-model.md)
5. [phase1-implementation-checklist.md](./phase1-implementation-checklist.md)
如果你负责算法或检索,再补:
- [sota-evolution-guide.md](./sota-evolution-guide.md)
- [model-feature-registry-bootstrap.md](./model-feature-registry-bootstrap.md)
- [phase1-worker-contract.md](./phase1-worker-contract.md)
---
## 3. 用一句话理解项目
我们在做的是一个面向 **版权保护 / 听歌识曲 / 版本归属** 的音乐 ACR 系统,
目标是从 `100w` 音频、约 `30w` 歌曲中,快速定位正确的 `song_id / work / recording` 归属。
---
## 4. 当前主线方案
### 检索主线
- exact lane:`Chromaprint`
- semantic lane baseline:`MERT-v1-95M`
- semantic lane challenger:`MuQ`
- historical baseline:`ECAPA`
### 数据主线
```text
canonical_song -> work -> recording -> recording_asset -> audio_window
```
### 模型主线
```text
model_registry -> feature_set_registry -> audio_embedding / audio_fingerprint -> retrieval_index_registry
```
---
## 5. 当前哪些已经稳定
- PostgreSQL v2 schema 已落地
- registry bootstrap 已有 live 验证
- worker contract 已有 live 验证
- exact / semantic 的失败语义已可审计
- planner 已能输出 validation commands
- planner validation runner 已可一键执行
## 6. 当前哪些还没完成
- 还没有真正跑通 MERT / MuQ inference
- 当前 host 没有 `/workspace/downloads`
- 当前 host 缺 `torch / torchaudio / transformers / speechbrain`
- 还没完成最终线上融合策略
- 还没接入更大规模真实 reference set
---
## 7. 如果你现在继续推进,按这个顺序
### 路线 A:先解环境
1. 挂载 `/workspace/downloads`
2. 安装 semantic runtime 依赖
3. 重跑 planner validation runner
4. 确认 `ready_jobs` 是否开始恢复
### 路线 B:先解实现
1. 阅读 [phase1-worker-contract.md](./phase1-worker-contract.md)
2. 阅读 `acr-engine/workers/run_embedding_job.py`
3. 用真实 inference adapter 替换 guarded failure path
4. 保持当前 PostgreSQL contract 不变
### 路线 C:先解数据
1. 阅读 [postgresql-data-model.md](./postgresql-data-model.md)
2. 阅读 [postgres_db_schema_samples.md](./postgres_db_schema_samples.md)
3. 准备更大的 reference set
4. 保持 `reference_set_registry / reference_set_member` 版本化
---
## 8. 当前不建议优先做的事
- 不要重新讨论要不要 `song/work/recording` 分层
- 不要回退到只有 `song_id` 的扁平表
- 不要先讨论重新训练底座
- 不要把当前问题误判成 PostgreSQL contract 设计问题
---
## 9. 仓库常用入口
### 文档
- [README.md](./README.md)
- [session-handoff.md](./session-handoff.md)
- [postgresql-data-model.md](./postgresql-data-model.md)
- [phase1-worker-contract.md](./phase1-worker-contract.md)
### 脚本
- `acr-engine/scripts/run_planner_validation_commands_live.py`
- `acr-engine/scripts/run_phase1_prereq_audit_live.py`
- `acr-engine/scripts/run_phase1_worker_contract_smoke_live.py`
- `acr-engine/scripts/run_embedding_vector_table_negative_matrix_live.py`
- `acr-engine/scripts/validate_audio_embedding_asset_upsert_live.py`
---
## 一句话结论
> 新同学接手时,先跑 runner,再读 5 份核心文档;当前首要问题是环境前置条件,不是 schema/contract 本身。