Freeze the production encoder before scaling the music index
Document the production decision to stabilize the embedding space before onboarding a 300k-song catalog, and record the migration rules for future encoder upgrades. Constraint: 300k-song production rollout makes embedding churn expensive and risky Rejected: keep iterating encoder before defining a production embedding version | would force repeated full-vector rebuilds and unstable rollout criteria Confidence: high Scope-risk: narrow Directive: Treat encoder changes as versioned index migrations, not in-place model swaps Tested: reviewed rendered markdown content, docs index link, changelog entry, and git diff for the three touched docs Not-tested: git push / remote sync outcome depends on repository remote state
Showing
3 changed files
with
653 additions
and
0 deletions
| 1 | ### Stage: production encoder freeze FAQ and rollout guidance | ||
| 2 | |||
| 3 | 完成项: | ||
| 4 | - 新增文档: | ||
| 5 | - `docs/production-encoder-freeze-and-embedding-strategy.md` | ||
| 6 | - 文档内容覆盖: | ||
| 7 | - 为什么当前应先冻结 encoder | ||
| 8 | - 当前结构的泛化能力边界 | ||
| 9 | - 外置模型权重后如何给其他歌曲直接使用 | ||
| 10 | - wav/mp3/flac/ogg 集合如何快速进入 manifest -> build-index -> evaluate 链路 | ||
| 11 | - 30 万首生产曲库下 embedding/version/index 的治理建议 | ||
| 12 | - encoder 升级后哪些数据必须重建、哪些元数据可以保留 | ||
| 13 | - docs 入口已补充: | ||
| 14 | - `docs/README.md` 新增该答疑文档链接 | ||
| 15 | |||
| 16 | 结论: | ||
| 17 | - 当前阶段先冻结 `encoder v1` 是更稳妥的生产决策 | ||
| 18 | - 生产环境应把模型文件、embedding 版本、reference 索引与评测报告解耦管理 | ||
| 19 | - 后续新 encoder 应走“离线 shadow build -> A/B -> 切换”的升级路径,而不是直接覆盖旧 embedding 库 | ||
| 20 | |||
| 1 | ## 2026-06-02 16:11 UTC / hum_guard fresh eval did not beat hum_focus | 21 | ## 2026-06-02 16:11 UTC / hum_guard fresh eval did not beat hum_focus |
| 2 | 22 | ||
| 3 | - 对 `/tmp/dualaxis_sweep/hum_guard/eval.json` 做了最新复核 | 23 | - 对 `/tmp/dualaxis_sweep/hum_guard/eval.json` 做了最新复核 | ... | ... |
| ... | @@ -91,6 +91,7 @@ cd /workspace/acr-engine | ... | @@ -91,6 +91,7 @@ cd /workspace/acr-engine |
| 91 | - [数据规范](./dataset-spec.md) | 91 | - [数据规范](./dataset-spec.md) |
| 92 | - [开放数据工作流](./open-dataset-workflow.md) | 92 | - [开放数据工作流](./open-dataset-workflow.md) |
| 93 | - [训练数据与 pgvector 指南](./training-data-and-pgvector-guide.md) | 93 | - [训练数据与 pgvector 指南](./training-data-and-pgvector-guide.md) |
| 94 | - [生产 Encoder 冻结与 Embedding 策略答疑](./production-encoder-freeze-and-embedding-strategy.md) | ||
| 94 | - [数据来源与接入](./dataset-sources-and-licensing.md) | 95 | - [数据来源与接入](./dataset-sources-and-licensing.md) |
| 95 | - [工业评测规范](./industrial-benchmark-spec.md) | 96 | - [工业评测规范](./industrial-benchmark-spec.md) |
| 96 | 97 | ... | ... |
| 1 | # Production Encoder Freeze & Embedding Strategy / 生产 Encoder 冻结与 Embedding 策略答疑 | ||
| 2 | |||
| 3 | > 更新:2026-06-03 | ||
| 4 | > 关联文档:[持续开发交接文档](./session-handoff.md) · [训练数据与 pgvector 指南](./training-data-and-pgvector-guide.md) · [开放数据工作流](./open-dataset-workflow.md) · [服务接口](./service-api.md) | ||
| 5 | |||
| 6 | ## 一页结论 | ||
| 7 | |||
| 8 | 围绕你当前最关心的生产问题,可以先压缩成 6 句话: | ||
| 9 | |||
| 10 | 1. **当前先冻结 encoder 是正确决定。** 对 30 万首生产曲库来说,先稳定 embedding 空间,比继续频繁改模型更重要。 | ||
| 11 | 2. **当前结构具备泛化能力。** 线上识别主路径是“固定 encoder 抽 embedding + reference 检索”,不是只能识别训练时见过的 closed-set 分类标签。 | ||
| 12 | 3. **模型权重可以外置复用。** 你可以把当前 `best_model.pt` 当成独立 encoder,用在别的 wav/mp3/flac/ogg 歌曲集合上。 | ||
| 13 | 4. **如果 encoder 变了,向量库就必须重建。** 歌曲元数据不用重做,但所有旧 embedding / ANN index / pgvector 向量都应视为旧版本。 | ||
| 14 | 5. **30 万首场景下必须做 embedding 版本化。** 不建议“直接覆盖旧库”,而应并行维护 `encoder_version=v1/v2/...`。 | ||
| 15 | 6. **最稳的上线策略是:先冻结 v1,上线使用;新模型只做离线 shadow build + A/B,收益足够大再切换。** | ||
| 16 | |||
| 17 | --- | ||
| 18 | |||
| 19 | ## 1. 当前项目进度:已经走到哪里 | ||
| 20 | |||
| 21 | ## 1.1 当前状态 | ||
| 22 | |||
| 23 | 根据 [持续开发交接文档](./session-handoff.md),当前项目已经从“原型是否能跑通”进入“真实数据验证 + 工程化推进”阶段: | ||
| 24 | |||
| 25 | - synthetic 数据链路已跑通:生成、训练、建索引、识别、评测都已具备 | ||
| 26 | - 开放数据链路已闭环:`inspect-local -> prepare-local -> validate-local -> train -> build-index -> evaluate -> generate_artifacts` | ||
| 27 | - 当前最佳候选方向已收敛到 `hum_focus` | ||
| 28 | - 真实 FMA smoke 已跨过训练,进入了 `build-index` 阶段 | ||
| 29 | |||
| 30 | 这说明当前不是“从零开始想方案”,而是已经具备: | ||
| 31 | |||
| 32 | 1. **一个可以独立抽 embedding 的 encoder** | ||
| 33 | 2. **一个可以对 reference 曲库建索引的 pipeline** | ||
| 34 | 3. **一个可以对 query 做识别的 hybrid 检索链路** | ||
| 35 | |||
| 36 | ## 1.2 当前最适合的策略 | ||
| 37 | |||
| 38 | 在这个阶段,最重要的不是继续频繁换 encoder,而是: | ||
| 39 | |||
| 40 | ```mermaid | ||
| 41 | flowchart TD | ||
| 42 | A[已有可运行模型与索引链] --> B[冻结生产 Encoder v1] | ||
| 43 | B --> C[完成 30 万首建库与使用] | ||
| 44 | C --> D[收集真实线上/离线问题] | ||
| 45 | D --> E[离线评估新 Encoder v2] | ||
| 46 | E --> F[证明显著收益后再迁移] | ||
| 47 | ``` | ||
| 48 | |||
| 49 | 也就是:**先让一版可用的 embedding 体系稳定下来,再做后续升级。** | ||
| 50 | |||
| 51 | --- | ||
| 52 | |||
| 53 | ## 2. 当前结构是否有泛化能力 | ||
| 54 | |||
| 55 | ## 2.1 简短回答 | ||
| 56 | |||
| 57 | **有。** | ||
| 58 | |||
| 59 | 但这里的“泛化”要分成两层理解: | ||
| 60 | |||
| 61 | | 泛化层次 | 当前是否支持 | 说明 | | ||
| 62 | |---|---|---| | ||
| 63 | | 新歌曲入库后可被识别 | 支持 | 只要用同一 encoder 生成 reference embedding 即可 | | ||
| 64 | | 完全未知分布上保持稳定高精度 | 尚未完全证明 | 当前更多是结构可行、真实大规模效果还需继续验证 | | ||
| 65 | |||
| 66 | ## 2.2 为什么说当前结构具备泛化能力 | ||
| 67 | |||
| 68 | 当前识别主链路不是: | ||
| 69 | - “输入 query -> 分类头直接输出某个固定 song class” | ||
| 70 | |||
| 71 | 而是: | ||
| 72 | - “输入 query -> encoder 抽 embedding -> 在 reference embedding 库中做相似度检索” | ||
| 73 | |||
| 74 | 结构图如下: | ||
| 75 | |||
| 76 | ```mermaid | ||
| 77 | flowchart LR | ||
| 78 | Q[query wav/mp3 片段] --> E1[冻结 Encoder v1] | ||
| 79 | E1 --> QE[query embedding] | ||
| 80 | QE --> S[similarity search] | ||
| 81 | |||
| 82 | R[30 万首 reference 曲库] --> E2[同一个冻结 Encoder v1] | ||
| 83 | E2 --> RE[reference embeddings] | ||
| 84 | RE --> S | ||
| 85 | |||
| 86 | S --> O[候选歌曲 + 分数] | ||
| 87 | ``` | ||
| 88 | |||
| 89 | 这种结构天然支持: | ||
| 90 | |||
| 91 | - 新歌曲加入 reference 曲库 | ||
| 92 | - 不重训模型的情况下扩歌库 | ||
| 93 | - 针对 query 做检索而不是固定类分类 | ||
| 94 | |||
| 95 | ## 2.3 但泛化能力的上限受什么影响 | ||
| 96 | |||
| 97 | 当前真实效果主要还受这些因素制约: | ||
| 98 | |||
| 99 | 1. **训练数据分布** | ||
| 100 | - 目前 hard case 已关注 `humming_like` / `confused` | ||
| 101 | - 但你的线上 30 万首曲库是否和当前训练/验证分布一致,仍需要真实数据验证 | ||
| 102 | |||
| 103 | 2. **reference 建库方式** | ||
| 104 | - 当前 reference 端是 **5 秒窗口 + 2.5 秒 stride** 的重叠滑窗 | ||
| 105 | - 这对片段识别是好的,但代价是窗口数上升、建库成本变高 | ||
| 106 | |||
| 107 | 3. **query 形式差异** | ||
| 108 | - 无损整曲、压缩 mp3、录音片段、截短片段、混响/手机采样等都会影响效果 | ||
| 109 | |||
| 110 | 4. **混合检索策略** | ||
| 111 | - 当前不是纯 embedding 检索,而是 `chromaprint + embedding + melody rerank` 的 hybrid | ||
| 112 | - 这对鲁棒性是加分项,但也意味着线上治理时要同时考虑指纹索引和向量索引 | ||
| 113 | |||
| 114 | --- | ||
| 115 | |||
| 116 | ## 3. 为什么当前先冻结 Encoder | ||
| 117 | |||
| 118 | ## 3.1 业务原因 | ||
| 119 | |||
| 120 | 你现在的生产环境里有 **30 万首歌曲**。这会带来一个决定性的工程事实: | ||
| 121 | |||
| 122 | > **一旦 encoder 改了,就不是“换个模型文件”这么简单,而是整套向量空间都可能变。** | ||
| 123 | |||
| 124 | 如果还没冻结 encoder,就会出现这些问题: | ||
| 125 | |||
| 126 | - 今天建的 30 万 embedding,明天可能全部作废 | ||
| 127 | - pgvector / Faiss / Milvus / 自研 ANN 索引都要全量重建 | ||
| 128 | - 离线评测和线上灰度无法稳定对齐 | ||
| 129 | - 回滚困难:你很难知道 query 是按哪个模型算的,reference 又是按哪个模型建的 | ||
| 130 | |||
| 131 | ## 3.2 工程原因 | ||
| 132 | |||
| 133 | 冻结 encoder 后,你才能稳定以下这些对象: | ||
| 134 | |||
| 135 | | 资产 | 是否应随 encoder 冻结 | 原因 | | ||
| 136 | |---|---|---| | ||
| 137 | | `best_model.pt` | 是 | 它决定向量空间 | | ||
| 138 | | `n_mels/sample_rate/window/stride` | 是 | 这些决定 embedding 分布 | | ||
| 139 | | `embedding_dim` | 是 | 向量表结构和索引依赖它 | | ||
| 140 | | reference embeddings | 是 | 必须和 query embedding 同版本 | | ||
| 141 | | ANN index / pgvector 索引 | 是 | 建立在具体 embedding 空间上 | | ||
| 142 | |||
| 143 | ## 3.3 当前建议的冻结定义 | ||
| 144 | |||
| 145 | 建议把当前生产 encoder 冻结为一组明确配置,而不是只记一个文件名。 | ||
| 146 | |||
| 147 | 推荐至少记录这些字段: | ||
| 148 | |||
| 149 | ```yaml | ||
| 150 | encoder_version: ecapa_hum_focus_v1 | ||
| 151 | checkpoint_path: /abs/path/to/best_model.pt | ||
| 152 | embedding_dim: 192 | ||
| 153 | sample_rate: 16000 | ||
| 154 | n_mels: 128 | ||
| 155 | n_fft: 512 | ||
| 156 | hop_length: 160 | ||
| 157 | reference_window_sec: 5.0 | ||
| 158 | reference_stride_sec: 2.5 | ||
| 159 | query_runtime_window_sec: 5.0 | ||
| 160 | feature_family: mel | ||
| 161 | index_family: hybrid_chromaprint_ecapa | ||
| 162 | status: frozen_for_production | ||
| 163 | ``` | ||
| 164 | |||
| 165 | --- | ||
| 166 | |||
| 167 | ## 4. 模型权重能否外置,给其他歌曲使用 | ||
| 168 | |||
| 169 | ## 4.1 简短回答 | ||
| 170 | |||
| 171 | **可以,而且应该这样做。** | ||
| 172 | |||
| 173 | 你可以把当前冻结好的 `best_model.pt` 视为一个独立的音乐 embedding encoder,用来处理: | ||
| 174 | |||
| 175 | - 新增歌曲入库 | ||
| 176 | - 旧歌库全量建 embedding | ||
| 177 | - 任意 query 音频片段识别 | ||
| 178 | - 后续 pgvector / ANN 向量服务对接 | ||
| 179 | |||
| 180 | ## 4.2 外置使用时的推荐组织方式 | ||
| 181 | |||
| 182 | 推荐把“模型”和“索引产物”分开管理: | ||
| 183 | |||
| 184 | ```mermaid | ||
| 185 | flowchart TD | ||
| 186 | A[models/] --> A1[ecapa_hum_focus_v1/best_model.pt] | ||
| 187 | A --> A2[ecapa_hum_focus_v1/encoder_manifest.yaml] | ||
| 188 | |||
| 189 | B[indexes/] --> B1[ecapa_hum_focus_v1/chromaprint.pkl] | ||
| 190 | B --> B2[ecapa_hum_focus_v1/reference_embs.npy] | ||
| 191 | B --> B3[ecapa_hum_focus_v1/reference_ids.npy] | ||
| 192 | B --> B4[ecapa_hum_focus_v1/index_metadata.json] | ||
| 193 | |||
| 194 | C[metadata/] --> C1[song_catalog.csv] | ||
| 195 | C --> C2[manifests/catalog.json] | ||
| 196 | ``` | ||
| 197 | |||
| 198 | ## 4.3 外置后能做什么 | ||
| 199 | |||
| 200 | ### 场景 A:直接给新歌曲建库 | ||
| 201 | |||
| 202 | - 你有一批新歌(wav/mp3/flac/ogg) | ||
| 203 | - 不重训 | ||
| 204 | - 用冻结 encoder 直接建 reference embedding | ||
| 205 | - 加入曲库识别 | ||
| 206 | |||
| 207 | ### 场景 B:给 query 片段做识别 | ||
| 208 | |||
| 209 | - 你有 5~10 秒左右的查询片段 | ||
| 210 | - 用同一 encoder 抽 query embedding | ||
| 211 | - 在 reference 库做相似度匹配 | ||
| 212 | |||
| 213 | ### 场景 C:离线批量生成 pgvector/ANN 数据 | ||
| 214 | |||
| 215 | - 你可以把 reference embeddings 作为离线产物导出 | ||
| 216 | - 再灌入 PostgreSQL + pgvector / Faiss / Milvus / 自研检索服务 | ||
| 217 | |||
| 218 | --- | ||
| 219 | |||
| 220 | ## 5. 你手头有无损、压缩、片段等 wav/mp3 文件集合,应该怎么直接使用 | ||
| 221 | |||
| 222 | ## 5.1 总体原则 | ||
| 223 | |||
| 224 | 你手头的文件不需要先人工区分“是不是训练专用格式”。 | ||
| 225 | |||
| 226 | 当前最重要的是把它们统一进入这套结构: | ||
| 227 | |||
| 228 | ```mermaid | ||
| 229 | flowchart LR | ||
| 230 | A[原始 wav/mp3/flac/ogg] --> B[标准化目录] | ||
| 231 | B --> C[manifest] | ||
| 232 | C --> D[reference 建库] | ||
| 233 | C --> E[query 验证] | ||
| 234 | D --> F[线上识别/检索] | ||
| 235 | ``` | ||
| 236 | |||
| 237 | ## 5.2 建议先分三类素材 | ||
| 238 | |||
| 239 | | 类别 | 作用 | 建议处理方式 | | ||
| 240 | |---|---|---| | ||
| 241 | | 完整歌曲 / 主版本 | 做 reference | 全部入库 | | ||
| 242 | | 截断片段 / 业务 query 样本 | 做评测 query | 固定留作测试集 | | ||
| 243 | | 低码率/手机录音/混响压缩片段 | 做 hard case query | 用来验证鲁棒性 | | ||
| 244 | |||
| 245 | ## 5.3 最短直接使用流程 | ||
| 246 | |||
| 247 | ### 第 1 步:冻结 encoder v1 | ||
| 248 | |||
| 249 | 先不要继续换模型,先把当前决定好的 checkpoint 固定下来。 | ||
| 250 | |||
| 251 | ### 第 2 步:准备音频目录 | ||
| 252 | |||
| 253 | 例如: | ||
| 254 | |||
| 255 | ```text | ||
| 256 | input_music/ | ||
| 257 | song_a.flac | ||
| 258 | song_b.mp3 | ||
| 259 | song_c.wav | ||
| 260 | ... | ||
| 261 | ``` | ||
| 262 | |||
| 263 | ### 第 3 步:检查目录是否适合进入当前链路 | ||
| 264 | |||
| 265 | ```bash | ||
| 266 | cd /root/vprecog/acr-engine | ||
| 267 | /usr/local/miniconda3/bin/python src/data/manifest_tools.py inspect-audio-dir \ | ||
| 268 | /abs/path/to/input_music \ | ||
| 269 | --query-duration 8.0 \ | ||
| 270 | --eval-ratio 0.2 | ||
| 271 | ``` | ||
| 272 | |||
| 273 | ### 第 4 步:生成统一 manifest | ||
| 274 | |||
| 275 | ```bash | ||
| 276 | cd /root/vprecog/acr-engine | ||
| 277 | /usr/local/miniconda3/bin/python src/data/manifest_tools.py audio-dir-to-splits \ | ||
| 278 | /abs/path/to/input_music \ | ||
| 279 | /abs/path/to/output_dataset \ | ||
| 280 | --source-dataset prod_music \ | ||
| 281 | --eval-ratio 0.2 \ | ||
| 282 | --query-duration 8.0 \ | ||
| 283 | --query-strategy hybrid \ | ||
| 284 | --query-stride 2.5 | ||
| 285 | ``` | ||
| 286 | |||
| 287 | 建议说明: | ||
| 288 | - `query-duration=8.0`:适合作为线下验证 query 长度 | ||
| 289 | - `query-strategy=hybrid`:更贴近当前项目已有的音乐感知切片方向 | ||
| 290 | - `query-stride=2.5`:如果你希望验证覆盖率更高,可以生成更多 query | ||
| 291 | |||
| 292 | ### 第 5 步:用冻结 encoder 建 reference index | ||
| 293 | |||
| 294 | ```bash | ||
| 295 | cd /root/vprecog/acr-engine | ||
| 296 | /usr/local/miniconda3/bin/python run_demo.py build-index \ | ||
| 297 | --data /abs/path/to/output_dataset/manifests \ | ||
| 298 | --model /abs/path/to/frozen/best_model.pt \ | ||
| 299 | --output /abs/path/to/output_index \ | ||
| 300 | --device cpu | ||
| 301 | ``` | ||
| 302 | |||
| 303 | ### 第 6 步:做离线识别验证 | ||
| 304 | |||
| 305 | ```bash | ||
| 306 | cd /root/vprecog/acr-engine | ||
| 307 | /usr/local/miniconda3/bin/python evaluate.py \ | ||
| 308 | --data /abs/path/to/output_dataset/manifests \ | ||
| 309 | --model /abs/path/to/frozen/best_model.pt \ | ||
| 310 | --index-prefix /abs/path/to/output_index/reference \ | ||
| 311 | --split test \ | ||
| 312 | --device cpu \ | ||
| 313 | --fast-eval \ | ||
| 314 | --output-json /abs/path/to/output_reports/eval.json | ||
| 315 | ``` | ||
| 316 | |||
| 317 | ### 第 7 步:确认后再推到生产向量库 | ||
| 318 | |||
| 319 | 当离线评测满足最低要求后,再把 reference embedding 导入生产检索系统,而不是一上来直接刷 30 万首正式库。 | ||
| 320 | |||
| 321 | --- | ||
| 322 | |||
| 323 | ## 6. 如果要快速微调,应该怎么做 | ||
| 324 | |||
| 325 | ## 6.1 原则 | ||
| 326 | |||
| 327 | **“快速微调”不等于“马上用 30 万首全量重训”。** | ||
| 328 | |||
| 329 | 对你当前场景,最合理的是: | ||
| 330 | |||
| 331 | 1. 先冻结生产 encoder v1 | ||
| 332 | 2. 用一个代表性子集训练/微调候选 v2 | ||
| 333 | 3. 只在离线环境评估 v2 | ||
| 334 | 4. 证明收益大于迁移成本,才考虑升级生产 encoder | ||
| 335 | |||
| 336 | ## 6.2 推荐的微调子集组成 | ||
| 337 | |||
| 338 | 建议优先抽一个 **几千到几万首规模的代表性集合**,覆盖: | ||
| 339 | |||
| 340 | - 无损高质量版本 | ||
| 341 | - 常见压缩版本(mp3/aac 等) | ||
| 342 | - 短片段 | ||
| 343 | - 开头/中段/结尾片段 | ||
| 344 | - 旋律近似、编曲相似的易混淆歌曲 | ||
| 345 | - 手机采样 / 录屏 / 二次压缩音频 | ||
| 346 | - 业务上最常见失败样本 | ||
| 347 | |||
| 348 | ## 6.3 推荐微调流程 | ||
| 349 | |||
| 350 | ```mermaid | ||
| 351 | flowchart TD | ||
| 352 | A[冻结 Encoder v1] --> B[抽代表性子集] | ||
| 353 | B --> C[生成 manifests] | ||
| 354 | C --> D[训练 v2 候选] | ||
| 355 | D --> E[建 v2 索引] | ||
| 356 | E --> F[固定测试集评测] | ||
| 357 | F --> G{收益显著?} | ||
| 358 | G -- 否 --> H[继续使用 v1] | ||
| 359 | G -- 是 --> I[准备 30 万首离线重刷 v2] | ||
| 360 | ``` | ||
| 361 | |||
| 362 | ## 6.4 微调时的判断标准 | ||
| 363 | |||
| 364 | 不要只看训练 loss,至少要看: | ||
| 365 | |||
| 366 | | 指标 | 作用 | | ||
| 367 | |---|---| | ||
| 368 | | top1 / topk | 基本识别率 | | ||
| 369 | | hard-case 命中率 | 看压缩/片段/混淆样本提升是否真实 | | ||
| 370 | | 新增模型对旧强项的回退 | 防止“补一个洞,漏一大片” | | ||
| 371 | | 全量建库速度 | 看新模型是否导致生产成本显著上升 | | ||
| 372 | | 线上 query 延迟 | 看推理成本是否可接受 | | ||
| 373 | |||
| 374 | ## 6.5 微调后的发布原则 | ||
| 375 | |||
| 376 | 微调完成后不要立刻替换 v1,而要: | ||
| 377 | |||
| 378 | 1. 标记为 `encoder_version=v2_candidate` | ||
| 379 | 2. 只做离线建库和评测 | ||
| 380 | 3. 在真实样本上和 v1 做 A/B | ||
| 381 | 4. 显著更优后再升级 | ||
| 382 | |||
| 383 | --- | ||
| 384 | |||
| 385 | ## 7. 如果 embedding 变了,哪些数据必须重建 | ||
| 386 | |||
| 387 | ## 7.1 要区分“元数据”和“向量数据” | ||
| 388 | |||
| 389 | | 数据类型 | 是否需要重建 | 说明 | | ||
| 390 | |---|---|---| | ||
| 391 | | 歌曲主数据(song_id/路径/业务标签) | 通常不需要 | 这些不依赖向量空间 | | ||
| 392 | | manifest | 通常不需要全重做 | 除非你的切片策略/数据治理规则也变了 | | ||
| 393 | | reference embeddings | 必须重建 | 因为 encoder 变了 | | ||
| 394 | | query embeddings 缓存 | 必须重建 | 否则和 reference 不同空间 | | ||
| 395 | | pgvector 行数据 | 必须重建 | 向量本体变了 | | ||
| 396 | | ANN 索引(Faiss/Milvus/HNSW/IVF 等) | 必须重建 | 建立在旧向量之上 | | ||
| 397 | | chromaprint 索引 | 不一定 | 只要指纹算法不变,可独立复用 | | ||
| 398 | |||
| 399 | ## 7.2 为什么必须重建 | ||
| 400 | |||
| 401 | 因为向量相似度检索默认假设: | ||
| 402 | |||
| 403 | > query embedding 和 reference embedding 来自同一个特征空间。 | ||
| 404 | |||
| 405 | 如果 query 用的是 `encoder v2`,reference 还停留在 `encoder v1`,就会出现: | ||
| 406 | |||
| 407 | - 分数不可比 | ||
| 408 | - recall 明显下降 | ||
| 409 | - 线上结果随机波动 | ||
| 410 | - A/B 结论失真 | ||
| 411 | |||
| 412 | ## 7.3 推荐的迁移策略 | ||
| 413 | |||
| 414 | 不要“原地覆盖旧 embedding”,而应采用双版本并行: | ||
| 415 | |||
| 416 | ```mermaid | ||
| 417 | flowchart LR | ||
| 418 | A[Encoder v1] --> B[index_v1] | ||
| 419 | C[Encoder v2] --> D[index_v2] | ||
| 420 | E[Query] --> F{使用哪个版本?} | ||
| 421 | F --> B | ||
| 422 | F --> D | ||
| 423 | ``` | ||
| 424 | |||
| 425 | 推荐步骤: | ||
| 426 | |||
| 427 | 1. 保留 `v1` 生产库不动 | ||
| 428 | 2. 离线刷 `v2` 的 30 万 embedding | ||
| 429 | 3. 建 `v2` 的 ANN / pgvector 索引 | ||
| 430 | 4. 用相同 query 集对比 v1/v2 | ||
| 431 | 5. 确认收益后切主流量 | ||
| 432 | 6. 回滚时直接切回 v1 | ||
| 433 | |||
| 434 | --- | ||
| 435 | |||
| 436 | ## 8. 30 万首生产环境推荐的版本化方案 | ||
| 437 | |||
| 438 | ## 8.1 推荐最小字段 | ||
| 439 | |||
| 440 | ### 歌曲元数据表 | ||
| 441 | |||
| 442 | | 字段 | 说明 | | ||
| 443 | |---|---| | ||
| 444 | | `song_id` | 稳定歌曲 ID | | ||
| 445 | | `audio_uri` | 原始音频路径/对象存储地址 | | ||
| 446 | | `duration_sec` | 时长 | | ||
| 447 | | `codec/container` | 格式信息 | | ||
| 448 | | `catalog_status` | 是否可入 reference 库 | | ||
| 449 | | `business_tags` | 业务标签 | | ||
| 450 | |||
| 451 | ### embedding 表 | ||
| 452 | |||
| 453 | | 字段 | 说明 | | ||
| 454 | |---|---| | ||
| 455 | | `song_id` | 对应歌曲 | | ||
| 456 | | `encoder_version` | 如 `ecapa_hum_focus_v1` | | ||
| 457 | | `window_index` | 第几个 reference window | | ||
| 458 | | `offset_sec` | 窗口起点 | | ||
| 459 | | `embedding_dim` | 例如 192 | | ||
| 460 | | `embedding` | 向量本体 | | ||
| 461 | | `built_at` | 构建时间 | | ||
| 462 | | `source_audio_hash` | 原音频指纹/摘要,便于查重与失效控制 | | ||
| 463 | |||
| 464 | ### index manifest | ||
| 465 | |||
| 466 | | 字段 | 说明 | | ||
| 467 | |---|---| | ||
| 468 | | `encoder_version` | 当前索引对应的 encoder | | ||
| 469 | | `checkpoint_path` | 模型文件 | | ||
| 470 | | `feature_config` | mel/n_mels/sample_rate 等 | | ||
| 471 | | `reference_window_sec` | 例如 5.0 | | ||
| 472 | | `reference_stride_sec` | 例如 2.5 | | ||
| 473 | | `catalog_size` | 曲库规模 | | ||
| 474 | | `num_reference_windows` | 总窗口数 | | ||
| 475 | | `built_at` | 构建时间 | | ||
| 476 | |||
| 477 | ## 8.2 推荐目录结构 | ||
| 478 | |||
| 479 | ```text | ||
| 480 | prod_artifacts/ | ||
| 481 | models/ | ||
| 482 | ecapa_hum_focus_v1/ | ||
| 483 | best_model.pt | ||
| 484 | encoder_manifest.yaml | ||
| 485 | |||
| 486 | indexes/ | ||
| 487 | ecapa_hum_focus_v1/ | ||
| 488 | chromaprint.pkl | ||
| 489 | chromaprint_progress.json | ||
| 490 | reference_embs.npy | ||
| 491 | reference_ids.npy | ||
| 492 | index_metadata.json | ||
| 493 | |||
| 494 | reports/ | ||
| 495 | ecapa_hum_focus_v1/ | ||
| 496 | eval.json | ||
| 497 | hard_case_eval.json | ||
| 498 | ``` | ||
| 499 | |||
| 500 | --- | ||
| 501 | |||
| 502 | ## 9. 当前建议的生产操作手册 | ||
| 503 | |||
| 504 | ## 9.1 目标 | ||
| 505 | |||
| 506 | 当前目标不是继续改模型,而是先完成: | ||
| 507 | |||
| 508 | 1. 冻结 encoder v1 | ||
| 509 | 2. 用 v1 支撑第一版 30 万首曲库建库 | ||
| 510 | 3. 建立版本化规范 | ||
| 511 | 4. 为后续 v2 升级预留迁移机制 | ||
| 512 | |||
| 513 | ## 9.2 分步操作 | ||
| 514 | |||
| 515 | ### Phase 1:冻结与归档 | ||
| 516 | |||
| 517 | - [ ] 选定当前生产 checkpoint | ||
| 518 | - [ ] 为该 checkpoint 生成 `encoder_manifest.yaml` | ||
| 519 | - [ ] 记录 `encoder_version` | ||
| 520 | - [ ] 固定 reference window / stride / mel 配置 | ||
| 521 | - [ ] 禁止直接覆盖此 checkpoint | ||
| 522 | |||
| 523 | ### Phase 2:小规模真实集验证 | ||
| 524 | |||
| 525 | - [ ] 抽 1k~10k 首真实歌曲做第一次建库 | ||
| 526 | - [ ] 抽真实 query 集做评测 | ||
| 527 | - [ ] 统计 top1/topk/hard-case 结果 | ||
| 528 | - [ ] 验证索引构建速度、磁盘占用、查询延迟 | ||
| 529 | |||
| 530 | ### Phase 3:30 万首全量离线建库 | ||
| 531 | |||
| 532 | - [ ] 清洗 song_id 与元数据 | ||
| 533 | - [ ] 生成标准 catalog/manifests | ||
| 534 | - [ ] 用冻结 encoder v1 批量生成 reference embeddings | ||
| 535 | - [ ] 生成 chromaprint / 向量索引 | ||
| 536 | - [ ] 导入生产检索服务 | ||
| 537 | |||
| 538 | ### Phase 4:上线与观测 | ||
| 539 | |||
| 540 | - [ ] 上线 v1 | ||
| 541 | - [ ] 记录 query 失败样本 | ||
| 542 | - [ ] 归档 hard-case | ||
| 543 | - [ ] 为 v2 微调准备离线样本集 | ||
| 544 | |||
| 545 | ### Phase 5:未来升级 | ||
| 546 | |||
| 547 | - [ ] 训练 `v2_candidate` | ||
| 548 | - [ ] 离线全量重刷 `index_v2` | ||
| 549 | - [ ] 做离线 A/B | ||
| 550 | - [ ] 收益显著后再切换主版本 | ||
| 551 | |||
| 552 | --- | ||
| 553 | |||
| 554 | ## 10. 常见问题 FAQ | ||
| 555 | |||
| 556 | ## 10.1 我现在有一大堆 wav/mp3,可以直接用吗? | ||
| 557 | |||
| 558 | **可以。** | ||
| 559 | |||
| 560 | 先不要纠结格式本身,先把它们组织成统一音频目录,再生成 manifests,再用冻结 encoder 建 reference index。 | ||
| 561 | |||
| 562 | ## 10.2 无损和压缩版本要不要分开? | ||
| 563 | |||
| 564 | **建议保留来源信息,但 reference 主库优先保留“主版本”。** | ||
| 565 | |||
| 566 | 如果同一首歌有多个编码版本: | ||
| 567 | - 主版本作为 reference 主资产 | ||
| 568 | - 其他压缩版本优先作为评测 query / hard case | ||
| 569 | |||
| 570 | 这样更利于真实评估鲁棒性。 | ||
| 571 | |||
| 572 | ## 10.3 片段文件可以直接拿来做 query 吗? | ||
| 573 | |||
| 574 | **可以。** | ||
| 575 | |||
| 576 | 尤其适合作为: | ||
| 577 | - clean query | ||
| 578 | - compressed query | ||
| 579 | - hard case query | ||
| 580 | |||
| 581 | 但如果要把它当训练样本,最好仍然能回溯到稳定的 `song_id` 和原 reference。 | ||
| 582 | |||
| 583 | ## 10.4 如果后面发现 encoder 不够好怎么办? | ||
| 584 | |||
| 585 | 不要直接替换现网。正确做法是: | ||
| 586 | |||
| 587 | 1. 保持 v1 不动 | ||
| 588 | 2. 离线训练 v2 | ||
| 589 | 3. 离线重刷 v2 的全量 embedding | ||
| 590 | 4. 对比 v1/v2 | ||
| 591 | 5. 确认收益后再切 | ||
| 592 | |||
| 593 | ## 10.5 现在有没有必要立刻上全量 30 万首? | ||
| 594 | |||
| 595 | **建议先做一轮中等规模验证,再上全量。** | ||
| 596 | |||
| 597 | 推荐先做: | ||
| 598 | - 1k 首小验证 | ||
| 599 | - 1w~5w 首中等规模验证 | ||
| 600 | - 验证速度/精度/存储后,再上 30 万 | ||
| 601 | |||
| 602 | ## 10.6 现阶段最重要的一句话建议是什么? | ||
| 603 | |||
| 604 | > **先冻结 encoder v1,把 embedding/version/index 治理做好,再讨论 v2。** | ||
| 605 | |||
| 606 | --- | ||
| 607 | |||
| 608 | ## 11. 最终建议 | ||
| 609 | |||
| 610 | 对你现在的阶段,我的建议优先级是: | ||
| 611 | |||
| 612 | 1. **冻结当前 encoder** | ||
| 613 | 2. **建立 embedding 版本化规范** | ||
| 614 | 3. **先做小到中规模真实集建库验证** | ||
| 615 | 4. **再推进 30 万首全量建库** | ||
| 616 | 5. **把新模型升级变成“离线重刷 + A/B + 切换”的标准动作** | ||
| 617 | |||
| 618 | 这样做的好处是: | ||
| 619 | |||
| 620 | - 你现在就能开始用 | ||
| 621 | - 后面也不会因为继续调模型把生产库拖乱 | ||
| 622 | - 未来升级有明确路径,不会出现“模型变了,数据全乱了”的问题 | ||
| 623 | |||
| 624 | ## Sources | ||
| 625 | - [持续开发交接文档](./session-handoff.md) | ||
| 626 | - [训练数据与 pgvector 指南](./training-data-and-pgvector-guide.md) | ||
| 627 | - [开放数据工作流](./open-dataset-workflow.md) | ||
| 628 | - [服务接口](./service-api.md) | ||
| 629 | - [acr-engine/train.py](../acr-engine/train.py) | ||
| 630 | - [acr-engine/run_demo.py](../acr-engine/run_demo.py) | ||
| 631 | - [acr-engine/src/engines/ecapa_embedder.py](../acr-engine/src/engines/ecapa_embedder.py) | ||
| 632 | - [acr-engine/src/data/manifest_tools.py](../acr-engine/src/data/manifest_tools.py) |
-
Please register or sign in to post a comment