歌曲作曲结构去重系统V1实施方案.md 7.42 KB

基于 Chromagram Sequence 的歌曲作曲结构去重系统 V1 实施方案

1 项目目标

1.1 项目背景

当前音乐去重体系划分为三个独立模块:

歌词去重

负责识别:

  • 歌词重复
  • 改编歌词
  • 部分重复歌词

当前已采用:

  • Jaccard Similarity
  • PostgreSQL pg_trgm
  • 规则引擎

实现文本层去重。


录音去重

负责识别:

  • 同一录音
  • 同源录音
  • 音频转载
  • 音频搬运

主要关注:

  • 音色
  • 演唱
  • 录音环境
  • 混音信息

该模块由独立团队负责。


曲去重(本项目)

本项目仅关注:

作曲结构(Composition)

包括:

  • 音级关系
  • 和声结构
  • 曲式演化
  • 音乐时间结构

不关注:

  • 歌手
  • 音色
  • 乐器品牌
  • 录音设备
  • 混音质量
  • 母带版本

1.2 项目目标

V1 适用范围

仅处理完整版 vs 完整版的对比。

识别:

晴天(原唱)
晴天(伴奏版)
晴天(钢琴版)
晴天(交响乐版)
晴天(翻唱版)

为同一作品。

区分:

晴天
七里香
稻香

等不同作品。

V1 不覆盖的场景

  • 全曲 vs 片段(属于 V2+ 规划)
  • 片段 vs 片段(属于 V2+ 规划)

2 总体技术路线

系统流程:

音频
 ↓
Chromagram提取
 ↓
时间归一化(12×512)
 ↓
Chromagram Sequence
 ↓
PostgreSQL + pgvector存储
 ↓
Cosine Similarity召回
 ↓
重复判定

3 技术选型依据

3.1 为什么不做人声分离

人声分离主要用于:

歌手分析
主唱分析
音色分析

而本项目关注:

作曲结构

Chromagram本身对乐器和人声具有一定鲁棒性。

因此V1阶段不引入额外模型。

降低系统复杂度。


3.2 为什么不做和弦识别

和弦识别属于:

音频
↓
和弦推理
↓
离散标签

过程。

每增加一次推理:

误差增加
信息损失增加

跨版本研究表明,同一首歌不同录音版本的和弦识别序列一致率仅约 64%, 不同版本(乐队翻唱、失真吉他等)会引入不一致的和弦检测错误, 导致文本相似度不稳定。

而曲去重更关注:

原始结构信息

因此直接使用Chromagram。


3.3 为什么选择Chromagram

Chromagram是音乐信息检索(MIR)领域最经典的作曲特征之一。

其核心思想:

将所有音高映射到:

C
C#
D
D#
E
F
F#
G
G#
A
A#
B

12个音级。

因此:

钢琴版
交响乐版
翻唱版
伴奏版

即使音色完全不同,

仍然会保留较高相似的色度结构。


4 特征提取

4.1 技术选型

Python

librosa

核心接口:

librosa.feature.chroma_cqt()

4.2 音频预处理

统一格式:

采样率:
22050Hz

声道:
Mono

格式:
WAV

转换工具:

ffmpeg


4.3 Chromagram生成

输入:

audio.wav

输出:

12 × T

矩阵。

示例:

C
C#
D
...
B

对应:

时间帧1
时间帧2
时间帧3
...
时间帧T

5 时间归一化

5.1 问题

不同歌曲长度不同:

3分钟歌曲
5分钟歌曲
8分钟歌曲

得到:

12×2000

12×3500

12×6000

无法直接比较。


5.2 解决方案

统一重采样:

12 × 512

实现:

from scipy.signal import resample

chroma_fixed = resample(
    chroma,
    512,
    axis=1
)

帧数选择依据:

  • 128 帧:每帧约 1.8 秒(4 分钟歌曲),时间分辨率过粗
  • 512 帧:每帧约 0.47 秒,结构细节保留充分
  • 512 帧展开后 6144 维,pgvector 性能可接受

5.3 设计思想

采用:

相对时间轴

而非:

绝对时间轴

即:

0%
10%
20%
...
100%

描述歌曲结构。

保证:

原版
钢琴版
翻唱版

长度不同仍可比较。

注:V1 仅处理完整版对比,Live 版等结构变体的鲁棒性在 V2 中通过 DTW 精排优化。


6 曲特征表示

最终统一表示为:

12 × 512

矩阵。

即:

6144维特征

展开后:

feature = chroma_fixed.flatten()

得到:

6144维向量

作为:

Composition Fingerprint

7 数据库存储设计

7.1 表结构

CREATE TABLE composition_feature
(
    id             BIGSERIAL PRIMARY KEY,
    song_id        BIGINT NOT NULL,
    feature_vector vector(6144),
    created_time   TIMESTAMP DEFAULT NOW()
);

7.2 字段说明

feature_vector

存储:

6144维Chromagram特征(pgvector vector类型)

使用 pgvector 的 vector 类型而非 FLOAT4[], 直接支持 Cosine 相似度索引和检索。


7.3 索引设计

使用 pgvector:

CREATE INDEX idx_composition_feature_vector
ON composition_feature
USING ivfflat (feature_vector vector_cosine_ops)
WITH (lists = 100);

支持:

Cosine Similarity

检索。


8 入库流程

Step1

上传音频


Step2

音频标准化

22050Hz
Mono

Step3

提取Chromagram

12 × T

Step4

重采样

12 × 512

Step5

展开

6144维

Step6

写入数据库


9 查询流程

Step1

新歌曲进入系统


Step2

重复执行:

音频
↓
Chromagram
↓
12×512
↓
6144维

Step3

Cosine Similarity检索

返回:

Top100

候选。


Step4

重复判定

根据阈值判断:

重复

疑似重复

非重复

10 相似度计算

采用:

Cosine Similarity

公式:

sim(A,B)
=
(A·B)
/
(|A||B|)

结果:

0~1

建议阈值(通过实验调整):

>0.95

高度重复。


0.85~0.95

疑似重复。


<0.85

非重复。

最终通过实验调整。


11 V1验证目标

验证以下问题:

问题1

同一首歌不同版本:

原唱
伴奏版
钢琴版
翻唱版

是否具有较高相似度。


问题2

不同歌曲之间:

晴天
七里香
稻香

是否能够有效区分。


问题3

Chromagram Sequence是否具备作曲结构表达能力。


问题4

转调翻唱对相似度的影响程度, 是否需要引入 Key 归一化。


12 V2升级路线

片段 vs 全曲 / 片段 vs 片段

引入:

帧级 CENS 特征 + FAISS 倒排索引

支持:

  • 全曲 vs 片段去重
  • 片段 vs 片段去重

DTW 精排

保持:

12 × 512

数据结构不变。

新增:

DTW

作为精排算法。

流程:

Cosine召回
↓
Top100
↓
DTW精排
↓
Top10

无需修改数据库。


13 V3升级路线

引入:

Faiss

或:

Milvus

实现百万级曲库检索。

同时保留:

DTW精排

机制。


14 最终方案总结

V1采用:

音频
→ Chromagram
→ 时间归一化(12×512)
→ 6144维作曲指纹
→ pgvector
→ Cosine Similarity
→ 重复判定

方案特点:

  • 仅处理完整版 vs 完整版
  • 不依赖声纹模型
  • 不依赖人声分离
  • 不依赖和弦识别
  • 保留完整时间结构
  • 与录音去重模块职责完全分离
  • 可直接升级至DTW方案
  • 避免后续数据结构重构
  • 工程实现复杂度低
  • 适合作为曲去重系统V1版本