Commit 69843933 69843933efecfbfff4cdcfcfb1b3eb0329384489 by cnb.bofCdSsphPA

Add a FAISS-first local ACR workflow for music20 samples

Constraint: local validation should stay lightweight and use /workspace sample files while production retrieval remains pgvector-backed
Rejected: making ChromaDB the default local backend | chromadb is not installed in the current environment and FAISS is already available
Confidence: high
Scope-risk: narrow
Directive: keep local dev workflows explicitly separated from production pgvector flows in docs and scripts
Tested: /usr/local/miniconda3/bin/python -m unittest discover -s acr-engine/tests -v; /usr/local/miniconda3/bin/python acr-engine/scripts/local_music20_acr.py --downloads-dir /workspace/downloads --song-limit 20 --backend faiss --output acr-engine/data/local_eval/music20_summary.json
Not-tested: chromadb backend execution without installation; live pgvector database execution path
1 parent 4806664b
......@@ -94,6 +94,29 @@ cd acr-engine
python evaluate.py --data data/synthetic --model data/models/best_model.pt --index-prefix data/index/reference --split test --device cpu
```
## 本地 20 首歌流程与生产向量库约定
- 本地小样本(如 `/workspace/downloads` 的 20 首歌流程)优先使用 **FAISS**
- 若后续本机安装了 `chromadb`,可作为可选对照后端,但不是默认依赖。
- 生产环境统一保留 **pgvector** 作为正式向量存储与检索底座。
本地 20 首歌流程:
```bash
cd acr-engine
/usr/local/miniconda3/bin/python scripts/local_music20_acr.py \
--downloads-dir /workspace/downloads \
--song-limit 20 \
--backend faiss \
--output data/local_eval/music20_summary.json
```
说明:
- `query_type=1/7/8/16` 会在一个汇总 JSON 里统一输出。
- 默认本地后端为 `faiss`
- 若使用 `--backend chromadb` 且环境缺少 `chromadb`,脚本会明确报错提示。
- 生产向量化链路仍走 `scripts/export_manifest_to_pgvector_json.py` 与后续 pgvector 入库。
## 当前提升方向
- 更强合成混淆样本(confused / humming_like)
......
{
"backend": "faiss",
"purpose": "Local 20-song ACR sanity flow for development; production remains pgvector.",
"downloads_dir": "/workspace/downloads",
"song_limit": 20,
"duration_sec": 8.0,
"sr": 22050,
"evaluations": [
{
"query_type": 1,
"reference_type": 11,
"song_count": 20,
"file_count": 40,
"topk": 3,
"metrics": {
"top1": 1.0,
"top3": 1.0
},
"results": [
{
"song_id": "100",
"query_path": "/workspace/downloads/100/type_1/BQ0000095-1.mp3",
"reference_path": "/workspace/downloads/100/type_11/93dfdeb0-7da5-42a8-9c71-cf12af57dd191650256918.wav",
"rank": 1,
"candidates": [
{
"rank": 1,
"song_id": "100",
"score": 0.9999855160713196
},
{
"rank": 2,
"song_id": "116",
"score": 0.9527432918548584
},
{
"rank": 3,
"song_id": "103",
"score": 0.9517078399658203
}
]
},
{
"song_id": "101",
"query_path": "/workspace/downloads/101/type_1/7679087a-c16c-4d0f-851f-b10f61b2032d1650364264.mp3",
"reference_path": "/workspace/downloads/101/type_11/83c0c07f-4f96-4ff4-998c-58db910f3cfa1650256915.wav",
"rank": 1,
"candidates": [
{
"rank": 1,
"song_id": "101",
"score": 0.9999996423721313
},
{
"rank": 2,
"song_id": "118",
"score": 0.9811710715293884
},
{
"rank": 3,
"song_id": "116",
"score": 0.9800198078155518
}
]
},
{
"song_id": "102",
"query_path": "/workspace/downloads/102/type_1/8fd5d3e8-e214-4d07-a283-1c5f6ac061f21650376142.mp3",
"reference_path": "/workspace/downloads/102/type_11/43440ec5-70b4-4d50-8683-d3e41cad29411650256908.wav",
"rank": 1,
"candidates": [
{
"rank": 1,
"song_id": "102",
"score": 0.9999971389770508
},
{
"rank": 2,
"song_id": "113",
"score": 0.9651333093643188
},
{
"rank": 3,
"song_id": "118",
"score": 0.9586168527603149
}
]
},
{
"song_id": "103",
"query_path": "/workspace/downloads/103/type_1/BQ0000092-1.mp3",
"reference_path": "/workspace/downloads/103/type_11/19876dbb-fffc-40f8-9530-9322c9ed77681650256912.wav",
"rank": 1,
"candidates": [
{
"rank": 1,
"song_id": "103",
"score": 0.9976630210876465
},
{
"rank": 2,
"song_id": "116",
"score": 0.9769654273986816
},
{
"rank": 3,
"song_id": "109",
"score": 0.965166449546814
}
]
},
{
"song_id": "104",
"query_path": "/workspace/downloads/104/type_1/BQ0000091-1.mp3",
"reference_path": "/workspace/downloads/104/type_11/4c1d3e22-045f-445b-ab87-ba1ae3ee09b31650256912.wav",
"rank": 1,
"candidates": [
{
"rank": 1,
"song_id": "104",
"score": 0.999987781047821
},
{
"rank": 2,
"song_id": "109",
"score": 0.9496555328369141
},
{
"rank": 3,
"song_id": "116",
"score": 0.9238482713699341
}
]
},
{
"song_id": "105",
"query_path": "/workspace/downloads/105/type_1/BQ0000090-1.mp3",
"reference_path": "/workspace/downloads/105/type_11/57e61cde-4410-4751-93e9-d7a4ecece5791650256910.wav",
"rank": 1,
"candidates": [
{
"rank": 1,
"song_id": "105",
"score": 0.9999495148658752
},
{
"rank": 2,
"song_id": "106",
"score": 0.9606355428695679
},
{
"rank": 3,
"song_id": "116",
"score": 0.944517195224762
}
]
},
{
"song_id": "106",
"query_path": "/workspace/downloads/106/type_1/BQ0000089-1.mp3",
"reference_path": "/workspace/downloads/106/type_11/bf61426c-67b7-4cf1-a9e7-f78cf519a0021650256910.wav",
"rank": 1,
"candidates": [
{
"rank": 1,
"song_id": "106",
"score": 0.9999995231628418
},
{
"rank": 2,
"song_id": "105",
"score": 0.9609931707382202
},
{
"rank": 3,
"song_id": "114",
"score": 0.9195822477340698
}
]
},
{
"song_id": "107",
"query_path": "/workspace/downloads/107/type_1/BQ0000088-1.mp3",
"reference_path": "/workspace/downloads/107/type_11/296bbc25-617c-4368-9a69-357aeec394381650256910.wav",
"rank": 1,
"candidates": [
{
"rank": 1,
"song_id": "107",
"score": 0.9978529810905457
},
{
"rank": 2,
"song_id": "116",
"score": 0.9719059467315674
},
{
"rank": 3,
"song_id": "101",
"score": 0.9612845182418823
}
]
},
{
"song_id": "108",
"query_path": "/workspace/downloads/108/type_1/BQ0000087-1.mp3",
"reference_path": "/workspace/downloads/108/type_11/d7e28fe6-4ad6-4243-b66b-d90ff5ca1e491650256909.wav",
"rank": 1,
"candidates": [
{
"rank": 1,
"song_id": "108",
"score": 0.9989668726921082
},
{
"rank": 2,
"song_id": "117",
"score": 0.931882381439209
},
{
"rank": 3,
"song_id": "116",
"score": 0.9296072721481323
}
]
},
{
"song_id": "109",
"query_path": "/workspace/downloads/109/type_1/d47d92f7-a39d-4e83-b5a2-05f98f3b74b3.mp3",
"reference_path": "/workspace/downloads/109/type_11/84acef9b-2a74-44bc-9eff-5ca7969ac9b61650256909.wav",
"rank": 1,
"candidates": [
{
"rank": 1,
"song_id": "109",
"score": 0.9808862209320068
},
{
"rank": 2,
"song_id": "116",
"score": 0.9763683676719666
},
{
"rank": 3,
"song_id": "103",
"score": 0.9724475741386414
}
]
},
{
"song_id": "110",
"query_path": "/workspace/downloads/110/type_1/BQ0000085-1.mp3",
"reference_path": "/workspace/downloads/110/type_11/2197b39e-23e2-4a66-b07e-dd672eab214a1650256908.wav",
"rank": 1,
"candidates": [
{
"rank": 1,
"song_id": "110",
"score": 0.9998435378074646
},
{
"rank": 2,
"song_id": "107",
"score": 0.9448647499084473
},
{
"rank": 3,
"song_id": "109",
"score": 0.9418830275535583
}
]
},
{
"song_id": "111",
"query_path": "/workspace/downloads/111/type_1/BQ0000084-1.mp3",
"reference_path": "/workspace/downloads/111/type_11/7f5256e8-de5f-41c5-bf76-419e05df72d81650256908.wav",
"rank": 1,
"candidates": [
{
"rank": 1,
"song_id": "111",
"score": 0.9993308186531067
},
{
"rank": 2,
"song_id": "110",
"score": 0.924956738948822
},
{
"rank": 3,
"song_id": "107",
"score": 0.913865327835083
}
]
},
{
"song_id": "112",
"query_path": "/workspace/downloads/112/type_1/BQ0000083-1.mp3",
"reference_path": "/workspace/downloads/112/type_11/34acd523-3c01-443d-ac3d-4ad7b9e2246f1650256907.wav",
"rank": 1,
"candidates": [
{
"rank": 1,
"song_id": "112",
"score": 0.9999276399612427
},
{
"rank": 2,
"song_id": "118",
"score": 0.9651827216148376
},
{
"rank": 3,
"song_id": "101",
"score": 0.9411808848381042
}
]
},
{
"song_id": "113",
"query_path": "/workspace/downloads/113/type_1/BQ0000082-1.mp3",
"reference_path": "/workspace/downloads/113/type_11/6d9438af-5d83-434b-bb20-76e28d0bbc4e1650256907.wav",
"rank": 1,
"candidates": [
{
"rank": 1,
"song_id": "113",
"score": 0.999977707862854
},
{
"rank": 2,
"song_id": "102",
"score": 0.9643173217773438
},
{
"rank": 3,
"song_id": "118",
"score": 0.9469178915023804
}
]
},
{
"song_id": "114",
"query_path": "/workspace/downloads/114/type_1/BQ0000081-1.mp3",
"reference_path": "/workspace/downloads/114/type_11/0238ecbf-b234-470e-82e4-f3b80a267d771650256906.wav",
"rank": 1,
"candidates": [
{
"rank": 1,
"song_id": "114",
"score": 0.9999734163284302
},
{
"rank": 2,
"song_id": "109",
"score": 0.9544920325279236
},
{
"rank": 3,
"song_id": "116",
"score": 0.9441098570823669
}
]
},
{
"song_id": "115",
"query_path": "/workspace/downloads/115/type_1/BQ0000080-1.mp3",
"reference_path": "/workspace/downloads/115/type_11/aabad0ff-13de-4786-aa9c-40e1f957ed9f1650256906.wav",
"rank": 1,
"candidates": [
{
"rank": 1,
"song_id": "115",
"score": 0.999998927116394
},
{
"rank": 2,
"song_id": "109",
"score": 0.9597340822219849
},
{
"rank": 3,
"song_id": "116",
"score": 0.9441829919815063
}
]
},
{
"song_id": "116",
"query_path": "/workspace/downloads/116/type_1/BQ0000079-1.mp3",
"reference_path": "/workspace/downloads/116/type_11/da34f6ff-39e7-4dde-8265-e1bb01b6263e1650256901.wav",
"rank": 1,
"candidates": [
{
"rank": 1,
"song_id": "116",
"score": 0.9999432563781738
},
{
"rank": 2,
"song_id": "109",
"score": 0.9809496998786926
},
{
"rank": 3,
"song_id": "101",
"score": 0.9800974130630493
}
]
},
{
"song_id": "117",
"query_path": "/workspace/downloads/117/type_1/BQ0000078-1.mp3",
"reference_path": "/workspace/downloads/117/type_11/1e1599e6-ebbd-4ceb-a81d-a320331ef6e31650256901.wav",
"rank": 1,
"candidates": [
{
"rank": 1,
"song_id": "117",
"score": 0.9999651312828064
},
{
"rank": 2,
"song_id": "118",
"score": 0.9473282098770142
},
{
"rank": 3,
"song_id": "101",
"score": 0.9408854246139526
}
]
},
{
"song_id": "118",
"query_path": "/workspace/downloads/118/type_1/BQ0000077-1.mp3",
"reference_path": "/workspace/downloads/118/type_11/db64461e-d752-4cf3-ab1d-56ff9232823d1650256901.wav",
"rank": 1,
"candidates": [
{
"rank": 1,
"song_id": "118",
"score": 0.9999653100967407
},
{
"rank": 2,
"song_id": "101",
"score": 0.9815313816070557
},
{
"rank": 3,
"song_id": "116",
"score": 0.9717569351196289
}
]
},
{
"song_id": "119",
"query_path": "/workspace/downloads/119/type_1/BQ0000076-1.mp3",
"reference_path": "/workspace/downloads/119/type_11/180dfa7d-836a-449c-990f-a3bf39c11da11650256898.wav",
"rank": 1,
"candidates": [
{
"rank": 1,
"song_id": "119",
"score": 0.9999881982803345
},
{
"rank": 2,
"song_id": "109",
"score": 0.974808394908905
},
{
"rank": 3,
"song_id": "118",
"score": 0.9480958580970764
}
]
}
]
},
{
"query_type": 7,
"reference_type": 11,
"song_count": 20,
"file_count": 40,
"topk": 3,
"metrics": {
"top1": 0.45,
"top3": 0.65
},
"results": [
{
"song_id": "111",
"query_path": "/workspace/downloads/111/type_7/75cd601b-7604-4b37-8132-cfab39e7c644.mp3",
"reference_path": "/workspace/downloads/111/type_11/7f5256e8-de5f-41c5-bf76-419e05df72d81650256908.wav",
"rank": 4,
"candidates": [
{
"rank": 1,
"song_id": "1566",
"score": 0.967636227607727
},
{
"rank": 2,
"song_id": "116",
"score": 0.9610425233840942
},
{
"rank": 3,
"song_id": "1232",
"score": 0.9582047462463379
}
]
},
{
"song_id": "116",
"query_path": "/workspace/downloads/116/type_7/d7098db6-fed3-485f-906e-e55e42187f0c.mp3",
"reference_path": "/workspace/downloads/116/type_11/da34f6ff-39e7-4dde-8265-e1bb01b6263e1650256901.wav",
"rank": 1,
"candidates": [
{
"rank": 1,
"song_id": "116",
"score": 0.9527724981307983
},
{
"rank": 2,
"song_id": "1411",
"score": 0.9431514739990234
},
{
"rank": 3,
"song_id": "1551",
"score": 0.9387646913528442
}
]
},
{
"song_id": "1232",
"query_path": "/workspace/downloads/1232/type_7/0bf7dd0a-c761-4695-ae48-f3eb19606e66.mp3",
"reference_path": "/workspace/downloads/1232/type_11/2a9e9334-a6da-4229-be28-dfd3d74ac8001650256614.wav",
"rank": 1,
"candidates": [
{
"rank": 1,
"song_id": "1232",
"score": 0.9828177690505981
},
{
"rank": 2,
"song_id": "1529",
"score": 0.9734008312225342
},
{
"rank": 3,
"song_id": "127",
"score": 0.9728921055793762
}
]
},
{
"song_id": "1248",
"query_path": "/workspace/downloads/1248/type_7/67db54b7-7d5d-45f5-a502-089c3d9ae768.mp3",
"reference_path": "/workspace/downloads/1248/type_11/9b5ec70a-ebec-4053-b983-8dde96fd35931650256654.wav",
"rank": 1,
"candidates": [
{
"rank": 1,
"song_id": "1248",
"score": 0.9654114842414856
},
{
"rank": 2,
"song_id": "1557",
"score": 0.9396299123764038
},
{
"rank": 3,
"song_id": "1413",
"score": 0.9305849075317383
}
]
},
{
"song_id": "127",
"query_path": "/workspace/downloads/127/type_7/c2a6df6f-53fb-498c-ba9e-9c235858afdb.mp3",
"reference_path": "/workspace/downloads/127/type_11/0f7c2e4e-7adc-4574-99a2-d9ba16ac91751650256886.wav",
"rank": 4,
"candidates": [
{
"rank": 1,
"song_id": "1538",
"score": 0.9620548486709595
},
{
"rank": 2,
"song_id": "1557",
"score": 0.9539428949356079
},
{
"rank": 3,
"song_id": "1248",
"score": 0.9378949403762817
}
]
},
{
"song_id": "139",
"query_path": "/workspace/downloads/139/type_7/cdfb0c16-ded3-4ea0-950d-aad9db32a623.mp3",
"reference_path": "/workspace/downloads/139/type_11/26701fc6-0649-4c25-9027-8569f3ccd8c31650256860.wav",
"rank": 1,
"candidates": [
{
"rank": 1,
"song_id": "139",
"score": 0.9671847820281982
},
{
"rank": 2,
"song_id": "1524",
"score": 0.9634047746658325
},
{
"rank": 3,
"song_id": "1551",
"score": 0.9607867002487183
}
]
},
{
"song_id": "1411",
"query_path": "/workspace/downloads/1411/type_7/11c9c322-4f9a-4352-98c4-45676571ad0f.mp3",
"reference_path": "/workspace/downloads/1411/type_11/9a95c2e7-9eb4-4961-b77d-3f7a3db509e31650256687.wav",
"rank": 1,
"candidates": [
{
"rank": 1,
"song_id": "1411",
"score": 0.9772824645042419
},
{
"rank": 2,
"song_id": "149",
"score": 0.9645872116088867
},
{
"rank": 3,
"song_id": "1551",
"score": 0.9318547248840332
}
]
},
{
"song_id": "1413",
"query_path": "/workspace/downloads/1413/type_7/0809e02c-ef1a-4cb3-a157-7d68ce80f450.mp3",
"reference_path": "/workspace/downloads/1413/type_11/c1837d1f-3580-42ed-a421-6bee7d7deeed1650256690.wav",
"rank": 3,
"candidates": [
{
"rank": 1,
"song_id": "1538",
"score": 0.9844843149185181
},
{
"rank": 2,
"song_id": "1557",
"score": 0.9749652743339539
},
{
"rank": 3,
"song_id": "1413",
"score": 0.9692580699920654
}
]
},
{
"song_id": "1417",
"query_path": "/workspace/downloads/1417/type_7/d810f778-a5f5-4361-bc98-8a1f0dacc436.mp3",
"reference_path": "/workspace/downloads/1417/type_11/a0ccdd48-9b17-4f10-8326-1f7cd3a482371650256706.wav",
"rank": 1,
"candidates": [
{
"rank": 1,
"song_id": "1417",
"score": 0.9710202217102051
},
{
"rank": 2,
"song_id": "139",
"score": 0.9527145624160767
},
{
"rank": 3,
"song_id": "1524",
"score": 0.9493513703346252
}
]
},
{
"song_id": "144",
"query_path": "/workspace/downloads/144/type_7/f24ab0b1-eb00-46b1-ba20-95f67f7e46aa.mp3",
"reference_path": "/workspace/downloads/144/type_11/59d8f5ce-3446-4d07-b2fe-b9e92d6c27d61650256849.wav",
"rank": 4,
"candidates": [
{
"rank": 1,
"song_id": "1566",
"score": 0.8859690427780151
},
{
"rank": 2,
"song_id": "1248",
"score": 0.8855512142181396
},
{
"rank": 3,
"song_id": "1529",
"score": 0.880099892616272
}
]
},
{
"song_id": "146",
"query_path": "/workspace/downloads/146/type_7/5b36aaa4-ee1e-4a4e-850f-7b11e4ea6ead.mp3",
"reference_path": "/workspace/downloads/146/type_11/6d1d68c0-c4f4-4619-a6d5-1a3663977df71650256843.wav",
"rank": 4,
"candidates": [
{
"rank": 1,
"song_id": "116",
"score": 0.9712613224983215
},
{
"rank": 2,
"song_id": "1538",
"score": 0.96543288230896
},
{
"rank": 3,
"song_id": "139",
"score": 0.9634105563163757
}
]
},
{
"song_id": "149",
"query_path": "/workspace/downloads/149/type_7/a5edfa85-901f-48b4-84b7-5dbf95e6abe6.mp3",
"reference_path": "/workspace/downloads/149/type_11/a2bd0149-1656-443b-a462-935a06038bff1650256842.wav",
"rank": 1,
"candidates": [
{
"rank": 1,
"song_id": "149",
"score": 0.9712207913398743
},
{
"rank": 2,
"song_id": "1411",
"score": 0.9420245885848999
},
{
"rank": 3,
"song_id": "1551",
"score": 0.9403735399246216
}
]
},
{
"song_id": "1524",
"query_path": "/workspace/downloads/1524/type_7/1230164367-6195b2805c6c8.mp3",
"reference_path": "/workspace/downloads/1524/type_11/2112741450-6195b26c7b221.wav",
"rank": 2,
"candidates": [
{
"rank": 1,
"song_id": "1413",
"score": 0.954952597618103
},
{
"rank": 2,
"song_id": "1524",
"score": 0.9472723007202148
},
{
"rank": 3,
"song_id": "139",
"score": 0.9455631971359253
}
]
},
{
"song_id": "1529",
"query_path": "/workspace/downloads/1529/type_7/3057076667-6195b157c8452.mp3",
"reference_path": "/workspace/downloads/1529/type_11/3318666279-6195b1453bb4c.wav",
"rank": 4,
"candidates": [
{
"rank": 1,
"song_id": "1557",
"score": 0.9849310517311096
},
{
"rank": 2,
"song_id": "1538",
"score": 0.978501558303833
},
{
"rank": 3,
"song_id": "116",
"score": 0.9784452319145203
}
]
},
{
"song_id": "1538",
"query_path": "/workspace/downloads/1538/type_7/0819b4cc-a233-4af2-809a-ab05c0ac7776.mp3",
"reference_path": "/workspace/downloads/1538/type_11/1453349980-6195b1de8e835.wav",
"rank": 2,
"candidates": [
{
"rank": 1,
"song_id": "1413",
"score": 0.9892231822013855
},
{
"rank": 2,
"song_id": "1538",
"score": 0.9782330989837646
},
{
"rank": 3,
"song_id": "1524",
"score": 0.9660094380378723
}
]
},
{
"song_id": "1551",
"query_path": "/workspace/downloads/1551/type_7/6377f532-0433-4197-9605-9aca077b26cf.mp3",
"reference_path": "/workspace/downloads/1551/type_11/2797850860-619b6d38c9947.wav",
"rank": 1,
"candidates": [
{
"rank": 1,
"song_id": "1551",
"score": 0.9460268020629883
},
{
"rank": 2,
"song_id": "139",
"score": 0.9309369325637817
},
{
"rank": 3,
"song_id": "1524",
"score": 0.9213981628417969
}
]
},
{
"song_id": "1555",
"query_path": "/workspace/downloads/1555/type_7/27ea0429-ac91-4a9d-99c0-aa4206d9bb09.mp3",
"reference_path": "/workspace/downloads/1555/type_11/1594992616-6195b1ba75f86.wav",
"rank": 4,
"candidates": [
{
"rank": 1,
"song_id": "139",
"score": 0.9818602800369263
},
{
"rank": 2,
"song_id": "1417",
"score": 0.9796779155731201
},
{
"rank": 3,
"song_id": "1524",
"score": 0.9765959978103638
}
]
},
{
"song_id": "1557",
"query_path": "/workspace/downloads/1557/type_7/b3f58fb7-fd7f-4171-89e5-03c4af249913.mp3",
"reference_path": "/workspace/downloads/1557/type_11/半抹烟熏 - 封茗囧菌.wav",
"rank": 3,
"candidates": [
{
"rank": 1,
"song_id": "1529",
"score": 0.9679929614067078
},
{
"rank": 2,
"song_id": "116",
"score": 0.9472056031227112
},
{
"rank": 3,
"song_id": "1557",
"score": 0.9455881118774414
}
]
},
{
"song_id": "1566",
"query_path": "/workspace/downloads/1566/type_7/11d4a0c3-c61a-42fd-8e05-6a5ec5d6def8.mp3",
"reference_path": "/workspace/downloads/1566/type_11/203038478-619b71a87115d.wav",
"rank": 1,
"candidates": [
{
"rank": 1,
"song_id": "1566",
"score": 0.9815737009048462
},
{
"rank": 2,
"song_id": "1557",
"score": 0.9664562344551086
},
{
"rank": 3,
"song_id": "1232",
"score": 0.9642168283462524
}
]
},
{
"song_id": "1569",
"query_path": "/workspace/downloads/1569/type_7/2a1013ef-c90a-49fc-98c1-1fc440913eb0.mp3",
"reference_path": "/workspace/downloads/1569/type_11/4036702771-619b70a7e7878.wav",
"rank": 4,
"candidates": [
{
"rank": 1,
"song_id": "1417",
"score": 0.9472358226776123
},
{
"rank": 2,
"song_id": "1551",
"score": 0.9437472820281982
},
{
"rank": 3,
"song_id": "139",
"score": 0.9431149363517761
}
]
}
]
},
{
"query_type": 8,
"reference_type": 11,
"song_count": 15,
"file_count": 30,
"topk": 3,
"metrics": {
"top1": 0.4666666666666667,
"top3": 0.7333333333333333
},
"results": [
{
"song_id": "567134",
"query_path": "/workspace/downloads/567134/type_8/忘记自己 第一段副歌剪辑.wav",
"reference_path": "/workspace/downloads/567134/type_11/忘记自己 MMM.wav",
"rank": 4,
"candidates": [
{
"rank": 1,
"song_id": "567138",
"score": 0.9597984552383423
},
{
"rank": 2,
"song_id": "567281",
"score": 0.9574185013771057
},
{
"rank": 3,
"song_id": "567271",
"score": 0.9435654878616333
}
]
},
{
"song_id": "567138",
"query_path": "/workspace/downloads/567138/type_8/小宝贝推广片段.mp3",
"reference_path": "/workspace/downloads/567138/type_11/小宝贝(手鼓版)_晴天姐妹_OK版.wav",
"rank": 2,
"candidates": [
{
"rank": 1,
"song_id": "567264",
"score": 0.9656863808631897
},
{
"rank": 2,
"song_id": "567138",
"score": 0.9656082391738892
},
{
"rank": 3,
"song_id": "567259",
"score": 0.9642202854156494
}
]
},
{
"song_id": "567165",
"query_path": "/workspace/downloads/567165/type_8/送你一片夏天的海(副歌版).mp3",
"reference_path": "/workspace/downloads/567165/type_11/苏北北-送你一片夏天的海.wav",
"rank": 4,
"candidates": [
{
"rank": 1,
"song_id": "567179",
"score": 0.9562718868255615
},
{
"rank": 2,
"song_id": "567264",
"score": 0.9513835310935974
},
{
"rank": 3,
"song_id": "567916",
"score": 0.9498939514160156
}
]
},
{
"song_id": "567179",
"query_path": "/workspace/downloads/567179/type_8/要多久-剪辑版2.mp3",
"reference_path": "/workspace/downloads/567179/type_11/王泽科-要多久-MMM.wav",
"rank": 1,
"candidates": [
{
"rank": 1,
"song_id": "567179",
"score": 0.9795538187026978
},
{
"rank": 2,
"song_id": "567916",
"score": 0.9502705335617065
},
{
"rank": 3,
"song_id": "567138",
"score": 0.9405353665351868
}
]
},
{
"song_id": "567189",
"query_path": "/workspace/downloads/567189/type_8/晚风的颜色(主歌).mp3",
"reference_path": "/workspace/downloads/567189/type_11/李淼淼&嘿人李逵Noisemakers-晚风的颜色 MMM.wav",
"rank": 1,
"candidates": [
{
"rank": 1,
"song_id": "567189",
"score": 0.9632946252822876
},
{
"rank": 2,
"song_id": "567138",
"score": 0.9404645562171936
},
{
"rank": 3,
"song_id": "567916",
"score": 0.9360995888710022
}
]
},
{
"song_id": "567201",
"query_path": "/workspace/downloads/567201/type_8/勇敢 副歌2 (3).wav",
"reference_path": "/workspace/downloads/567201/type_11/勇敢MMM Final .wav",
"rank": 1,
"candidates": [
{
"rank": 1,
"song_id": "567201",
"score": 0.9567320942878723
},
{
"rank": 2,
"song_id": "567259",
"score": 0.9491016864776611
},
{
"rank": 3,
"song_id": "567271",
"score": 0.9226593375205994
}
]
},
{
"song_id": "567239",
"query_path": "/workspace/downloads/567239/type_8/这个夏天怎么可以没有你 推广片段2(开头主歌).mp3",
"reference_path": "/workspace/downloads/567239/type_11/这个夏天怎么可以没有你 MMM.wav",
"rank": 2,
"candidates": [
{
"rank": 1,
"song_id": "567264",
"score": 0.9888042211532593
},
{
"rank": 2,
"song_id": "567239",
"score": 0.9758810997009277
},
{
"rank": 3,
"song_id": "567916",
"score": 0.9709678888320923
}
]
},
{
"song_id": "567259",
"query_path": "/workspace/downloads/567259/type_8/天宫一日游 推广片段2.mp3",
"reference_path": "/workspace/downloads/567259/type_11/天宫一日游 NEW MMM9.wav",
"rank": 1,
"candidates": [
{
"rank": 1,
"song_id": "567259",
"score": 0.9787400960922241
},
{
"rank": 2,
"song_id": "567271",
"score": 0.9783401489257812
},
{
"rank": 3,
"song_id": "567264",
"score": 0.9548755884170532
}
]
},
{
"song_id": "567263",
"query_path": "/workspace/downloads/567263/type_8/如果我们不能在一起(主歌2).mp3",
"reference_path": "/workspace/downloads/567263/type_11/韩小欠-如果我们不能在一起.wav",
"rank": 4,
"candidates": [
{
"rank": 1,
"song_id": "567271",
"score": 0.9618159532546997
},
{
"rank": 2,
"song_id": "567259",
"score": 0.9609355926513672
},
{
"rank": 3,
"song_id": "567134",
"score": 0.9573717713356018
}
]
},
{
"song_id": "567264",
"query_path": "/workspace/downloads/567264/type_8/如果我们不能在一起(DJheap九天版)副歌.mp3",
"reference_path": "/workspace/downloads/567264/type_11/韩小欠 - 如果我们不能在一起(DJheap九天版).wav",
"rank": 1,
"candidates": [
{
"rank": 1,
"song_id": "567264",
"score": 0.9920860528945923
},
{
"rank": 2,
"song_id": "567916",
"score": 0.9885831475257874
},
{
"rank": 3,
"song_id": "567239",
"score": 0.9782738089561462
}
]
},
{
"song_id": "567271",
"query_path": "/workspace/downloads/567271/type_8/时光寄语(带前缀进副).wav",
"reference_path": "/workspace/downloads/567271/type_11/时光寄语_MMM.wav",
"rank": 1,
"candidates": [
{
"rank": 1,
"song_id": "567271",
"score": 0.9909964203834534
},
{
"rank": 2,
"song_id": "567259",
"score": 0.9836105108261108
},
{
"rank": 3,
"song_id": "567138",
"score": 0.9572499990463257
}
]
},
{
"song_id": "567281",
"query_path": "/workspace/downloads/567281/type_8/赵乾景-野火春风(剪辑版2).wav",
"reference_path": "/workspace/downloads/567281/type_11/赵乾景-野火春风-MMM.wav",
"rank": 4,
"candidates": [
{
"rank": 1,
"song_id": "567418",
"score": 0.9464678168296814
},
{
"rank": 2,
"song_id": "567179",
"score": 0.9336224794387817
},
{
"rank": 3,
"song_id": "567138",
"score": 0.9211266040802002
}
]
},
{
"song_id": "567415",
"query_path": "/workspace/downloads/567415/type_8/将相(主歌版).mp3",
"reference_path": "/workspace/downloads/567415/type_11/海伦-将相.wav",
"rank": 2,
"candidates": [
{
"rank": 1,
"song_id": "567239",
"score": 0.9695478677749634
},
{
"rank": 2,
"song_id": "567415",
"score": 0.9663351774215698
},
{
"rank": 3,
"song_id": "567264",
"score": 0.9626679420471191
}
]
},
{
"song_id": "567418",
"query_path": "/workspace/downloads/567418/type_8/寒鸦 副歌片段.mp3",
"reference_path": "/workspace/downloads/567418/type_11/阿YueYue-寒鸦.wav",
"rank": 2,
"candidates": [
{
"rank": 1,
"song_id": "567179",
"score": 0.9723362922668457
},
{
"rank": 2,
"song_id": "567418",
"score": 0.957268476486206
},
{
"rank": 3,
"song_id": "567138",
"score": 0.9490213394165039
}
]
},
{
"song_id": "567916",
"query_path": "/workspace/downloads/567916/type_8/梁祝 2022【长片段】.mp3",
"reference_path": "/workspace/downloads/567916/type_11/李智恩_ 有余-梁祝2022【MMM】.wav",
"rank": 1,
"candidates": [
{
"rank": 1,
"song_id": "567916",
"score": 0.9856635332107544
},
{
"rank": 2,
"song_id": "567264",
"score": 0.978611946105957
},
{
"rank": 3,
"song_id": "567239",
"score": 0.9704344272613525
}
]
}
]
},
{
"query_type": 16,
"reference_type": 11,
"song_count": 12,
"file_count": 24,
"topk": 3,
"metrics": {
"top1": 0.4166666666666667,
"top3": 0.4166666666666667
},
"results": [
{
"song_id": "569681",
"query_path": "/workspace/downloads/569681/type_16/失去的总是太珍贵(DJ版)_15秒.wav",
"reference_path": "/workspace/downloads/569681/type_11/b208a400b27f8ce254786084db610591.wav",
"rank": 1,
"candidates": [
{
"rank": 1,
"song_id": "569681",
"score": 0.9956467151641846
},
{
"rank": 2,
"song_id": "570345",
"score": 0.9810035228729248
},
{
"rank": 3,
"song_id": "570690",
"score": 0.9807205200195312
}
]
},
{
"song_id": "569738",
"query_path": "/workspace/downloads/569738/type_16/孤单被写成歌 (DJ阿卓版)-剪辑版.mp3",
"reference_path": "/workspace/downloads/569738/type_11/54d71a3a1dd75528d07f301288833bea.wav",
"rank": 1,
"candidates": [
{
"rank": 1,
"song_id": "569738",
"score": 0.9825096130371094
},
{
"rank": 2,
"song_id": "571113",
"score": 0.965214729309082
},
{
"rank": 3,
"song_id": "569681",
"score": 0.9526969790458679
}
]
},
{
"song_id": "569748",
"query_path": "/workspace/downloads/569748/type_16/49a1d25ec19ace09e80b81187ebb0d0b.mp3",
"reference_path": "/workspace/downloads/569748/type_11/98293d1ced1538afeaac8fb2d0627450.wav",
"rank": 4,
"candidates": [
{
"rank": 1,
"song_id": "570690",
"score": 0.9810636639595032
},
{
"rank": 2,
"song_id": "569681",
"score": 0.9782453775405884
},
{
"rank": 3,
"song_id": "570345",
"score": 0.9706552028656006
}
]
},
{
"song_id": "569787",
"query_path": "/workspace/downloads/569787/type_16/九块九爱情-副歌剪辑.mp3",
"reference_path": "/workspace/downloads/569787/type_11/cd311b412dcf2022d4f3218ff9ff2a0e.wav",
"rank": 4,
"candidates": [
{
"rank": 1,
"song_id": "569681",
"score": 0.9725706577301025
},
{
"rank": 2,
"song_id": "570345",
"score": 0.9703218936920166
},
{
"rank": 3,
"song_id": "570690",
"score": 0.9670296311378479
}
]
},
{
"song_id": "569855",
"query_path": "/workspace/downloads/569855/type_16/2604aa1e31c47097c27ef92e7993aa5e.mp3",
"reference_path": "/workspace/downloads/569855/type_11/fd7b9d0ad38ed4a1e8781c024f9e98a3.wav",
"rank": 4,
"candidates": [
{
"rank": 1,
"song_id": "569681",
"score": 0.9718084335327148
},
{
"rank": 2,
"song_id": "571113",
"score": 0.9617775082588196
},
{
"rank": 3,
"song_id": "570690",
"score": 0.9604461193084717
}
]
},
{
"song_id": "570124",
"query_path": "/workspace/downloads/570124/type_16/朋友的礼貌 推广音频_01.wav",
"reference_path": "/workspace/downloads/570124/type_11/49558365b2b2dc4407d57bae50042538.wav",
"rank": 1,
"candidates": [
{
"rank": 1,
"song_id": "570124",
"score": 0.9759569764137268
},
{
"rank": 2,
"song_id": "569681",
"score": 0.9457025527954102
},
{
"rank": 3,
"song_id": "571113",
"score": 0.9330494403839111
}
]
},
{
"song_id": "570345",
"query_path": "/workspace/downloads/570345/type_16/痴情小丑-副歌剪辑.mp3",
"reference_path": "/workspace/downloads/570345/type_11/fef15d6a43a89238ef4c2f0a11da4bdc.wav",
"rank": 4,
"candidates": [
{
"rank": 1,
"song_id": "571113",
"score": 0.9789301753044128
},
{
"rank": 2,
"song_id": "570615",
"score": 0.9712299108505249
},
{
"rank": 3,
"song_id": "569748",
"score": 0.9703583717346191
}
]
},
{
"song_id": "570386",
"query_path": "/workspace/downloads/570386/type_16/eda281acb45e7ee372120854feae9949.mp3",
"reference_path": "/workspace/downloads/570386/type_11/3f329c9cbaa2ac2612040712bfa1fa09.wav",
"rank": 4,
"candidates": [
{
"rank": 1,
"song_id": "569748",
"score": 0.978370726108551
},
{
"rank": 2,
"song_id": "569787",
"score": 0.9759876728057861
},
{
"rank": 3,
"song_id": "571113",
"score": 0.9739384651184082
}
]
},
{
"song_id": "570612",
"query_path": "/workspace/downloads/570612/type_16/刘彧轩-怕-推广片段.mp3",
"reference_path": "/workspace/downloads/570612/type_11/f7e3172620f2ed5830055d9d9e15da0d.wav",
"rank": 4,
"candidates": [
{
"rank": 1,
"song_id": "569681",
"score": 0.959099292755127
},
{
"rank": 2,
"song_id": "571113",
"score": 0.9577440023422241
},
{
"rank": 3,
"song_id": "569738",
"score": 0.9569077491760254
}
]
},
{
"song_id": "570615",
"query_path": "/workspace/downloads/570615/type_16/故事打烊 片段.mp3",
"reference_path": "/workspace/downloads/570615/type_11/8fe62b2057640446295f901d0fc8c668.wav",
"rank": 4,
"candidates": [
{
"rank": 1,
"song_id": "571113",
"score": 0.971631646156311
},
{
"rank": 2,
"song_id": "569738",
"score": 0.959520697593689
},
{
"rank": 3,
"song_id": "569748",
"score": 0.9524401426315308
}
]
},
{
"song_id": "570690",
"query_path": "/workspace/downloads/570690/type_16/ca8e0c234e560d89d98b52eefc50728b.mp3",
"reference_path": "/workspace/downloads/570690/type_11/456050c584f93f406a10bc67979482bb.wav",
"rank": 1,
"candidates": [
{
"rank": 1,
"song_id": "570690",
"score": 0.992263674736023
},
{
"rank": 2,
"song_id": "569681",
"score": 0.9891844987869263
},
{
"rank": 3,
"song_id": "571113",
"score": 0.9690903425216675
}
]
},
{
"song_id": "571113",
"query_path": "/workspace/downloads/571113/type_16/杨小壮-《痴情小丑》伯格DJ版-副歌.wav",
"reference_path": "/workspace/downloads/571113/type_11/4a568a7e0dbd2566b219af738e9fded9.wav",
"rank": 1,
"candidates": [
{
"rank": 1,
"song_id": "571113",
"score": 0.9814494848251343
},
{
"rank": 2,
"song_id": "569681",
"score": 0.9789079427719116
},
{
"rank": 3,
"song_id": "570345",
"score": 0.9653943777084351
}
]
}
]
}
]
}
\ No newline at end of file
#!/usr/bin/env /usr/local/miniconda3/bin/python
"""Run a FAISS-first local ACR eval on up to 20 songs from /workspace/downloads.
Purpose:
- keep small-sample validation inside acr-engine
- default to FAISS for local dev
- optionally allow ChromaDB when installed
- preserve pgvector as the production path (not used here)
"""
from __future__ import annotations
import argparse
import json
from pathlib import Path
from typing import Dict, List
import faiss
import librosa
import numpy as np
DEFAULT_DOWNLOADS = Path('/workspace/downloads')
DEFAULT_OUTPUT = Path('/root/vprecog/acr-engine/data/local_eval/music20_summary.json')
SUPPORTED_QUERY_TYPES = (1, 7, 8, 16)
REFERENCE_TYPE = 11
def parse_args() -> argparse.Namespace:
ap = argparse.ArgumentParser()
ap.add_argument('--downloads-dir', default=str(DEFAULT_DOWNLOADS))
ap.add_argument('--song-limit', type=int, default=20)
ap.add_argument('--duration', type=float, default=8.0)
ap.add_argument('--sr', type=int, default=22050)
ap.add_argument('--topk', type=int, default=3)
ap.add_argument('--backend', choices=['faiss', 'chromadb'], default='faiss')
ap.add_argument('--output', default=str(DEFAULT_OUTPUT))
return ap.parse_args()
def first_file(path: Path) -> Path | None:
files = sorted(p for p in path.iterdir() if p.is_file()) if path.exists() else []
return files[0] if files else None
def collect_pairs(downloads_dir: Path, song_limit: int, query_type: int) -> List[Dict[str, str]]:
pairs = []
for song_dir in sorted(p for p in downloads_dir.iterdir() if p.is_dir()):
ref = first_file(song_dir / f'type_{REFERENCE_TYPE}')
qry = first_file(song_dir / f'type_{query_type}')
if ref and qry:
pairs.append({
'song_id': song_dir.name,
'reference_path': str(ref),
'query_path': str(qry),
})
if len(pairs) >= song_limit:
break
return pairs
def load_audio(path: str, sr: int, duration: float) -> np.ndarray:
y, _ = librosa.load(path, sr=sr, mono=True, duration=duration)
target_len = int(sr * duration)
if len(y) < target_len:
y = np.pad(y, (0, target_len - len(y)))
else:
y = y[:target_len]
return y.astype(np.float32)
def embed_chroma(path: str, sr: int, duration: float) -> np.ndarray:
y = load_audio(path, sr=sr, duration=duration)
chroma = librosa.feature.chroma_stft(y=y, sr=sr, n_chroma=12)
feat = np.concatenate([chroma.mean(axis=1), chroma.std(axis=1)], axis=0).astype(np.float32)
norm = np.linalg.norm(feat)
if norm > 0:
feat = feat / norm
return feat
def run_faiss(ref_matrix: np.ndarray, qry_matrix: np.ndarray, topk: int):
index = faiss.IndexFlatIP(ref_matrix.shape[1])
index.add(ref_matrix)
return index.search(qry_matrix, topk)
def run_chromadb(ref_matrix: np.ndarray, qry_matrix: np.ndarray, topk: int):
try:
import chromadb # type: ignore
except Exception as exc: # pragma: no cover - env-dependent
raise SystemExit(f'ChromaDB backend requested but unavailable: {exc}')
client = chromadb.EphemeralClient()
collection = client.create_collection('music20_local_eval')
ref_ids = [str(i) for i in range(len(ref_matrix))]
collection.add(ids=ref_ids, embeddings=ref_matrix.tolist())
result = collection.query(query_embeddings=qry_matrix.tolist(), n_results=topk)
distances = np.asarray(result['distances'], dtype=np.float32)
idxs = np.asarray([[int(x) for x in row] for row in result['ids']], dtype=np.int32)
sims = 1.0 - distances
return sims, idxs
def evaluate_query_type(downloads_dir: Path, song_limit: int, query_type: int, sr: int, duration: float, topk: int, backend: str):
pairs = collect_pairs(downloads_dir, song_limit, query_type=query_type)
if not pairs:
return {
'query_type': query_type,
'reference_type': REFERENCE_TYPE,
'song_count': 0,
'file_count': 0,
'topk': topk,
'metrics': {'top1': 0.0, 'top3': 0.0},
'results': [],
'note': 'No matching query/reference pairs found.',
}
ref_vecs = [embed_chroma(item['reference_path'], sr, duration) for item in pairs]
qry_vecs = [embed_chroma(item['query_path'], sr, duration) for item in pairs]
ref_ids = [item['song_id'] for item in pairs]
ref_matrix = np.vstack(ref_vecs).astype(np.float32)
qry_matrix = np.vstack(qry_vecs).astype(np.float32)
if backend == 'faiss':
sims, idxs = run_faiss(ref_matrix, qry_matrix, topk)
else:
sims, idxs = run_chromadb(ref_matrix, qry_matrix, topk)
ranks = []
results = []
for i, item in enumerate(pairs):
candidates = []
rank = None
for j in range(topk):
ref_idx = int(idxs[i, j])
cand_song_id = ref_ids[ref_idx]
score = float(sims[i, j])
candidates.append({'rank': j + 1, 'song_id': cand_song_id, 'score': score})
if cand_song_id == item['song_id'] and rank is None:
rank = j + 1
if rank is None:
rank = topk + 1
ranks.append(rank)
results.append({
'song_id': item['song_id'],
'query_path': item['query_path'],
'reference_path': item['reference_path'],
'rank': rank,
'candidates': candidates,
})
top1 = sum(1 for r in ranks if r == 1) / len(ranks)
top3 = sum(1 for r in ranks if r <= min(3, topk)) / len(ranks)
return {
'query_type': query_type,
'reference_type': REFERENCE_TYPE,
'song_count': len(pairs),
'file_count': len(pairs) * 2,
'topk': topk,
'metrics': {'top1': top1, 'top3': top3},
'results': results,
}
def main() -> None:
args = parse_args()
downloads_dir = Path(args.downloads_dir)
out = Path(args.output)
out.parent.mkdir(parents=True, exist_ok=True)
summary = {
'backend': args.backend,
'purpose': 'Local 20-song ACR sanity flow for development; production remains pgvector.',
'downloads_dir': str(downloads_dir),
'song_limit': args.song_limit,
'duration_sec': args.duration,
'sr': args.sr,
'evaluations': [],
}
for query_type in SUPPORTED_QUERY_TYPES:
summary['evaluations'].append(
evaluate_query_type(downloads_dir, args.song_limit, query_type, args.sr, args.duration, args.topk, args.backend)
)
out.write_text(json.dumps(summary, ensure_ascii=False, indent=2), encoding='utf-8')
print(json.dumps(summary, ensure_ascii=False, indent=2))
if __name__ == '__main__':
main()
import tempfile
import unittest
from pathlib import Path
from scripts.local_music20_acr import collect_pairs, first_file
class LocalMusic20AcrTests(unittest.TestCase):
def test_first_file_returns_none_for_missing_dir(self):
with tempfile.TemporaryDirectory() as tmp:
self.assertIsNone(first_file(Path(tmp) / 'missing'))
def test_collect_pairs_uses_reference_and_query_types(self):
with tempfile.TemporaryDirectory() as tmp:
root = Path(tmp)
song = root / '1'
(song / 'type_11').mkdir(parents=True)
(song / 'type_7').mkdir(parents=True)
((song / 'type_11') / 'ref.wav').write_bytes(b'r')
((song / 'type_7') / 'query.mp3').write_bytes(b'q')
pairs = collect_pairs(root, song_limit=20, query_type=7)
self.assertEqual(len(pairs), 1)
self.assertEqual(pairs[0]['song_id'], '1')
self.assertTrue(pairs[0]['reference_path'].endswith('ref.wav'))
self.assertTrue(pairs[0]['query_path'].endswith('query.mp3'))
if __name__ == '__main__':
unittest.main()
## 2026-06-03 20-song local ACR workflow in acr-engine
- 新增 `acr-engine/scripts/local_music20_acr.py`,在 `acr-engine` 内提供基于 `/workspace/downloads` 的本地 20 首歌 ACR 小样本流程。
- 本地流程默认优先使用 **FAISS**`chromadb` 作为可选对照后端;生产环境继续保留 **pgvector**
- 新增 `acr-engine/tests/test_local_music20_acr.py`,覆盖本地配对逻辑。
- 新增 `acr-engine/data/local_eval/music20_summary.json`,记录 `type_1/7/8/16 -> type_11` 的本地 20-song 汇总结果。
- 更新 `acr-engine/README.md`,明确“本地 FAISS / 可选 ChromaDB / 生产 pgvector”的分层约定。
Fresh evidence:
- `/usr/local/miniconda3/bin/python -m unittest discover -s acr-engine/tests -v` => `Ran 2 tests, OK`
- `/usr/local/miniconda3/bin/python acr-engine/scripts/local_music20_acr.py --downloads-dir /workspace/downloads --song-limit 20 --backend faiss --output acr-engine/data/local_eval/music20_summary.json` 跑通
- 汇总结果:
- `type_1 -> type_11`: `top1=1.0`, `top3=1.0`
- `type_7 -> type_11`: `top1=0.45`, `top3=0.65`
- `type_8 -> type_11`: `top1=0.4667`, `top3=0.7333`
- `type_16 -> type_11`: `top1=0.4167`, `top3=0.4167`
### Stage: production encoder freeze FAQ and rollout guidance
完成项:
......