基于 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版本