歌曲作曲结构去重系统V2优化方案.md 4.41 KB

歌曲作曲结构去重系统 V2 优化方案

1 V1 评估基线

测试集:20 首歌 × 5 种变换 + 20 条负样本,共 120 条。

指标 V1 结果
Accuracy 0.6917
Precision 1.0000
Recall 0.6300
F1 0.7730
假阳性(FP) 0
漏判(FN) 37

按变换类型分解:

变换类型 V1 Accuracy 说明
lowpass(低通滤波) 1.00 音色变化,CENS 完全应对
negative(不同曲) 1.00 假阳性为零,区分度良好
tempo_fast(加速 10%) 0.80 时间压缩,部分吸收
pitch_down(降半音) 0.50 转调鲁棒性不足
tempo_slow(减速 10%) 0.45 时间拉伸,信息密度变化大
pitch_up(升半音) 0.40 转调鲁棒性最差

核心结论:

  • 精确率满分,系统不会误判不同歌曲,可以放心部署
  • 主要缺陷集中在转调(pitch)和减速(tempo_slow),合计贡献了 37 条漏判中的约 30 条
  • V1 的主音对齐(np.roll 到能量最大音级)对连续半音偏移效果有限

2 问题根因分析

2.1 转调(pitch_up / pitch_down)失败的根本原因

ffmpeg asetrate 变调是连续音高偏移(非整数半音),而 CENS 的 12 个 bin 是离散的。np.roll 只能对齐整数个半音,偏移量不是整数半音时无法对齐,导致相似度显著下降(失败样本 top1 相似度集中在 0.78~0.90,未过阈值)。

2.2 减速(tempo_slow)失败的根本原因

时间拉伸后每帧重复内容增多,resample 到 128 帧时对应的音乐内容在时间轴上与原版错位。问题本质是时间对齐失败,而非特征表达力不足——多尺度拼接解决的是后者,对前者无效。唯一有效的解法是允许时间轴弹性匹配的 DTW。


3 V2 优化方案

3.1 转调鲁棒性:12 路循环对齐

方案: 查询时对特征矩阵穷举 12 种半音偏移(np.roll(chroma, -k, axis=0),k=0..11),取与库中向量相似度最高的那一路作为最终相似度。

实现位置: service.pyquery() 方法,特征提取本身不变。

代价: 每次查询变为 12 次向量检索,pgvector 单次检索延迟约 10ms 级别,12 路合计约 100ms,可接受。

预期提升: pitch_up / pitch_down accuracy 从 0.4/0.5 提升至接近 1.0。

# 伪代码示意
best: dict[int, float] = {}
for shift in range(12):
    shifted = np.roll(chroma, -shift, axis=0).flatten()
    for song_id, sim in query_vector(shifted, top_k):
        best[song_id] = max(best.get(song_id, -1.0), sim)

3.2 速度变化鲁棒性:DTW 精排

方案: Cosine 召回 Top-K 后,用 DTW 对原始 12×128 矩阵做精排,替换纯相似度阈值判断。

实现:

from scipy.spatial.distance import cdist

def dtw_distance(chroma_a: np.ndarray, chroma_b: np.ndarray) -> float:
    # chroma shape: (12, 128),按列(时间帧)计算帧间欧氏距离矩阵,再做 DTW
    ...

适用场景: 对 tempo 变化(±20% 以内)效果显著,对大幅转调效果有限(需配合 3.1)。

部署策略: 不修改数据库结构,仅在召回后增加一个 Python 计算步骤。

预期提升: tempo_slow accuracy 从 0.45 提升至 0.85 以上。


3.3 调性估计升级(可选)

方案: 用 Krumhansl-Schmuckler 调性轮廓替代"能量最大音级"作为主音估计,使 np.roll 对齐更精准。

评估方式: 先跑 3.1(穷举 12 路),若效果已满足需求则跳过本项。


4 优先级与实施顺序

优先级 方案 改动范围 预期收益
P0 3.1 12 路循环对齐 service.py query 逻辑 pitch 问题基本解决
P1 3.2 DTW 精排 新增精排函数,不改数据库 tempo 问题显著改善
P2 3.3 调性估计升级 extractor.py 按需实施

P0 和 P1 不需要重新入库,改动最小,建议优先实施并重新跑评估基线后再决定是否做 P2。


5 V2 目标指标

变换类型 V1 V2 目标
lowpass 1.00 1.00
negative 1.00 1.00
tempo_fast 0.80 ≥ 0.95
pitch_down 0.50 ≥ 0.95
tempo_slow 0.45 ≥ 0.85
pitch_up 0.40 ≥ 0.95
整体 Recall 0.63 ≥ 0.92
整体 F1 0.773 ≥ 0.958

Precision 维持 1.0(不引入假阳性)。