acr-design.md 47.1 KB

Audio Content Recognition (ACR) System — 听歌识曲引擎设计文档

版本: v1.0 | 更新: 2026-06-02 | 状态: Draft


目录

  1. 概述与背景
  2. 解决的问题
  3. 技术原理
  4. 系统架构设计
  5. 数据准备与增强
  6. 模型设计
  7. 训练细节
  8. 推理与匹配策略
  9. 使用方法
  10. SOTA 调研与对比
  11. Roadmap
  12. Checklist
  13. Changelog
  14. Handoff 交付清单
  15. 参考与引用

1. 概述与背景

1.1 项目目标

构建一个音频内容识别(Audio Content Recognition, ACR)引擎,能够根据一段BGM(背景音乐)哼唱(Humming)录音片段等音频输入,在歌曲库中快速准确地识别出对应的歌曲。核心能力对标 Shazam、SoundHound、网易云音乐"听歌识曲"等工业级产品。

1.2 核心能力

能力 说明
BGM 识别 输入一段背景音乐,识别原曲
哼唱识别 (Query-by-Humming) 输入用户哼唱的旋律,识别匹配的歌曲
录音片段识别 输入现场录音(含环境噪声),匹配库中歌曲
抗噪鲁棒性 在嘈杂环境、低码率、压缩失真下保持准确率
快速检索 亿级曲库下毫秒级响应
增量扩展 歌曲库可动态增加,无需全量重训练

1.3 命名规范

术语 含义
Song / Track 库中原始歌曲
Reference 歌曲在库中的指纹/特征表示
Query 用户输入的待识别音频片段
Fingerprint 音频指纹(特征向量或哈希序列)
Landmark 频谱图中的峰值点,用于构建指纹
Candidate 匹配候选歌曲列表
Segment 一个Query对应的录音片段或BGM片段

2. 解决的问题

2.1 核心问题域

问题 描述 技术挑战
音频退化 Query 可能经过压缩(MP3/AAC)、降采样、远场录制 特征需对退化具有不变性
时间截断 Query 仅为歌曲的中间某一小段(3-15s) 指纹需支持局部匹配
哼唱偏差 用户哼唱的音高、节奏、音色与原曲不同 需旋律归一化与音高轮廓匹配
环境噪声 录音含背景人声、街道噪声、混响 特征提取需有一定抗噪性
速度变化 Query 播放速度可能快于或慢于原曲(±15%) 指纹对时间伸缩不敏感
键位偏移 Query 的调性可能不同于原曲(哼唱场景常见) 需相对旋律表示而非绝对音高
曲库规模 曲库可能达到百万至亿级 检索必须依赖哈希/近似最近邻索引

2.2 与现有方案对比

维度 传统指纹法 (Shazam-like) 深度学习 embedding 法 (本方案) 混合方案
哼唱识别 不支持 支持(训练时加入哼唱数据) 支持
抗噪性 中等 高(数据增强可大幅提升)
检索速度 极快(哈希表) 快(ANN 索引) 极快
曲库扩展 容易 容易(增量索引) 容易
硬件要求 中等(需 GPU 训练) 中等
调音适应性 好(对比学习可学到不变性)
时间碎片适应性 好(滑窗机制)

3. 技术原理

3.1 音频信号处理基础

3.1.1 短时傅里叶变换 (STFT)

音频信号经 STFT 转化为时频表示:

X(t, f) = Σₙ x[n]·w[n-t]·e^{-j2πfn/N}

其中 w[n] 为窗函数(Hamming/Hann),典型窗长 1024-4096 samples,步长 256-512 samples。

3.1.2 Mel 频谱

将 STFT 的线性频率通过 Mel 滤波器组映射到 Mel 刻度:

Mel(f) = 2595 · log₁₀(1 + f/700)

得到 Mel 频谱图作为模型的 2D 输入特征。Mel 频谱更符合人耳听觉感知,且对高频噪声有一定抑制作用。

3.1.3 色谱图 (Chroma Feature)

色谱图将频谱能量投影到 12 个半音(C, C#, D, ..., B),对音色和音高变化具有不变性,特别适合哼唱识别。

Chroma(t, p) = Σ_{f ∈ pitches_in_class_p} |X(t, f)|²

3.1.4 谱峰提取 (Spectral Peaks)

在频谱图中提取能量峰值点(landmarks),每个 landmark 定义为 (t, f, energy)。Shazam 算法基于这些 landmark 构建哈希指纹。

3.1.5 哼唱旋律轮廓 (Melody Contour)

对于哼唱输入,使用基频(F0)估计提取旋律轮廓线。常用算法:

  • PYIN (Probabilistic YIN):基于 YIN 算法的概率改进版
  • CREPE:基于深度学习的基频估计
  • TorchCREPE:CREPE 的 PyTorch 实现

旋律轮廓经归一化后得到相对音高序列:ΔP(t) = P(t) - P(t-1)

3.2 音频指纹技术

3.2.1 传统指纹法 (Shazam Algorithm)

  1. 对音频做 STFT 得到频谱图
  2. 在时频平面提取能量峰值(landmarks)
  3. 对每对 landmark (f₁, t₁)(f₂, t₂) 构建哈希对: hash = (f₁, f₂, Δt) → (t₁, song_id)
  4. 查询时计算 Query 的 landmarks 和 hashes
  5. 在哈希表中找到匹配的歌曲候选
  6. 对候选做时间偏移直方图投票,选出最高票歌曲

优点:极快、曲库可极大、无需训练 缺点:对哼唱、速度变化、调性变化不适应

3.2.2 深度嵌入法 (Deep Embedding) —— 本方案核心

将音频片段映射到一个固定维度的嵌入向量(如 256 维),在嵌入空间中相似歌曲的 Query 和 Reference 距离接近。

对比学习目标 (Contrastive Learning)

Loss = -log( exp(sim(q, p)/τ) / Σ_{n=1}^{N} exp(sim(q, n)/τ) )

其中 sim(q, p) 是 Query 与正样本 Reference 的余弦相似度,τ 是温度系数。

核心优势

  • 通过对比学习,嵌入对音色、噪声、速度变化、调性变化具有不变性
  • 哼唱 Query 可与原曲 Reference 在嵌入空间中对齐
  • 支持增量曲库(新歌只需过一次模型生成嵌入)

3.3 检索策略

3.3.1 精确检索 (Brute Force)

当库规模 < 10K 时,直接计算 Query 嵌入与所有 Reference 嵌入的余弦相似度。

score_i = cosine(query_emb, ref_emb_i)
result = argmax(score_i)

3.3.2 近似最近邻检索 (ANN)

当库规模 > 10K 时,使用近似最近邻索引:

算法 特点 适用场景
IVF 倒排文件索引,训练聚类中心 百万级
IVF + PQ 乘积量化压缩向量 千万级
HNSW 分层导航小世界图 亿级,高精度
DiskANN 基于 SSD 的图索引 十亿级

推荐使用 Faiss 库实现 ANN 检索。

3.3.3 级联检索策略

Query → 粗筛 (ANN, top-K) → 精排 (余弦相似度) → 时间对齐验证 → Top-1
  • 粗筛:ANN 检索 Top-50/100 候选
  • 精排:计算精确余弦相似度,取 Top-10
  • 时间对齐验证:对 Top-10 候选做频谱图谱峰对齐验证,确认时序一致性

4. 系统架构设计

4.1 整体架构

┌─────────────────────────────────────────────────────────────┐
│                       API Gateway                           │
└─────────────────────┬───────────────────────────────────────┘
                      │
        ┌─────────────┼─────────────┐
        ▼             ▼             ▼
┌───────────────┐ ┌───────┐ ┌───────────────┐
│ Audio Ingest  │ │ Search│ │ Admin Service │
│ (Ingestion)   │ │ (QPS) │ │ (管理)        │
└───────┬───────┘ └───┬───┘ └───────┬───────┘
        │             │             │
        ▼             ▼             ▼
┌─────────────────────────────────────────────────────────────┐
│                   Core Engine Layer                         │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌───────────────┐  │
│ │ Pre-     │ │ Feature  │ │ Embedder│ │ Matcher       │  │
│ │ processor│ │ Extractor│ │ (Model) │ │ (Searcher)    │  │
│ └──────────┘ └──────────┘ └──────────┘ └───────────────┘  │
└─────────────────────────────────────────────────────────────┘
        │             │             │
        ▼             ▼             ▼
┌─────────────────────────────────────────────────────────────┐
│                    Storage Layer                            │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌───────────────┐  │
│ │ Raw Audio│ │ Finger-  │ │ Embedding│ │ Song Metadata │  │
│ │ (S3/OSS) │ │ print DB │ │ Index    │ │ (PostgreSQL)  │  │
│ └──────────┘ └──────────┘ └──────────┘ └───────────────┘  │
└─────────────────────────────────────────────────────────────┘

4.2 模块详细设计

4.2.1 Audio Preprocessor

输入: raw_audio_bytes / file_path / stream
功能:
  1. 格式解码 (MP3, WAV, FLAC, AAC, OGG, M4A)
  2. 重采样到统一采样率 (16kHz 或 22.05kHz)
  3. 通道合并 (多声道 → 单声道)
  4. 归一化 (RMS 归一化到目标响度)
  5. 分帧/滑窗 (非重叠或非重叠滑窗,每帧 3-15s)
输出: numpy.ndarray, shape=(samples,)

4.2.2 Feature Extractor

支持多种特征提取策略,可通过配置切换:

模式 A: Spectrogram + Log-Mel
  - STFT: window=2048, hop=512, window_fn=hann
  - Mel filters: 64/128 bins, fmin=0, fmax=8000
  - Log(spectrogram + 1e-6)

模式 B: Chroma CQT
  - Constant Q Transform, 12 bins/octave
  - 适用于哼唱场景

模式 C: Landmark + Hash (Shazam 兼容)
  - Peak extraction (2D local maxima)
  - Target zone pairing for hash construction

模式 D: Raw Waveform (可选)
  - 直接输入原始波形给 1D CNN

4.2.3 Embedder (深度模型)

参见第 6 节

4.2.4 Matcher / Searcher

输入: query_embedding (dim=256)
流程:
  1. ANN 检索: Faiss IVF+HNSW, top_k=100
  2. 精排: 计算精确余弦相似度, top_k=10
  3. 时间对齐验证 (可选):
     - 对 Top-10 候选提取谱峰
     - 计算 Query 与候选的时间偏移直方图
     - 确认存在一致性偏移峰值
  4. 置信度校准: 计算相似度分布 z-score
  5. 输出: sorted_results[ {song_id, score, match_type} ]

4.3 API 设计

// Recognize — 识别音频
service ACRService {
  // 输入音频返回 Top-N 匹配歌曲
  rpc Recognize(RecognizeRequest) returns (RecognizeResponse);

  // 批量入库
  rpc IngestSong(IngestSongRequest) returns (IngestSongResponse);

  // 删除歌曲
  rpc DeleteSong(DeleteSongRequest) returns (DeleteSongResponse);

  // 健康检查
  rpc HealthCheck(Empty) returns (HealthCheckResponse);
}

message RecognizeRequest {
  bytes audio_data = 1;        // 音频数据
  string audio_format = 2;     // wav, mp3, ogg
  float duration_sec = 3;      // 实际有效时长 (若未知留空)
  RecognizeMode mode = 4;      // AUTO, BGM, HUMMING, RECORDING
  int32 top_n = 5;             // 返回 Top-N (默认 5)
}

enum RecognizeMode {
  AUTO = 0;       // 自动检测模式
  BGM = 1;        // 纯 BGM 片段
  HUMMING = 2;    // 哼唱
  RECORDING = 3;  // 现场录音
}

message RecognizeResponse {
  repeated Candidate candidates = 1;
  float processing_time_ms = 2;
}

message Candidate {
  string song_id = 1;
  string title = 2;
  string artist = 3;
  float confidence = 4;
  float matched_begin_sec = 5;  // 匹配起始时间
  float matched_end_sec = 6;    // 匹配结束时间
  string match_type = 7;        // bgm / humming / recording
}

4.4 存储设计

数据 存储引擎 说明
原始音频 S3/MinIO/OSS 对象存储,按 song_id 组织
歌曲元数据 PostgreSQL 标题、歌手、专辑、时长、标签
嵌入向量 Faiss Index (IVF+HNSW) 256 维浮点向量
指纹哈希 Redis / LevelDB Shazam 兼容指纹键值对
频谱缓存 Redis / S3 预处理后的频谱图缓存
操作日志 ClickHouse / ELK 查询日志、性能监控

4.5 部署架构

                    ┌──────────┐
                    │  LB/Nginx│
                    └────┬─────┘
                         │
              ┌──────────┼──────────┐
              ▼          ▼          ▼
        ┌──────────┐ ┌──────────┐ ┌──────────┐
        │ API      │ │ API      │ │ API      │
        │ Server 1 │ │ Server 2 │ │ Server N │
        └────┬─────┘ └────┬─────┘ └────┬─────┘
             │            │            │
             ▼            ▼            ▼
        ┌─────────────────────────────────────┐
        │         Faiss Index (Sharded)       │
        │         GPU/CPU Hybrid              │
        ├─────────────────────────────────────┤
        │         PostgreSQL (RDS)             │
        ├─────────────────────────────────────┤
        │         S3-compatible Object Store   │
        └─────────────────────────────────────┘

5. 数据准备与增强

5.1 数据来源

5.1.1 歌曲原始数据

来源 类型 规模目标 许可注意
FMA (Free Music Archive) 开源音乐 100K+ 曲 CC 授权
MUSDB18 多轨分离数据集 150 曲 研究用途
GTZAN 流派分类 1000 曲 研究用途
自行爬取/合作 商业音乐 1M+ 曲 需版权授权
自建录制 哼唱/翻唱 10K+ 段 内部数据

5.1.2 训练数据构造

每个歌曲在库中作为 Reference,需为每个 Reference 构造多样化的 Query 用于训练。

基础构造逻辑

song.mp3 → 随机裁剪片段 (3-15s) → 数据增强 → Query
song.mp3 → 全曲 → Reference

5.1.3 哼唱数据

哼唱数据可通过以下方式获取:

  1. MIR-QBSH Corpus:专业哼唱数据集
  2. 自建哼唱数据集:组织用户录制哼唱旋律
  3. MIDI 转音频模拟:将 MIDI 文件通过合成器转为模拟哼唱
  4. M-Humming:自行标注的哼唱数据集

哼唱数据格式要求:

{
  "song_id": "song_001",
  "humming_id": "hum_001",
  "audio_path": "/data/humming/song_001_hum_001.wav",
  "original_song_path": "/data/songs/song_001.mp3",
  "humming_duration_sec": 8.5,
  "relative_pitch_shift": -2,  // 相对原曲的半音偏移
  "tempo_ratio": 1.1          // 相对原曲的速度倍率
}

5.2 数据增强策略

增强的目的是使模型学到对真实世界干扰的不变性

5.2.1 基础增强

增强操作 参数范围 目标
Additive White Gaussian Noise (AWGN) SNR: 5-30dB 环境噪声
Pink Noise / Brown Noise SNR: 10-25dB 自然噪声
Band-stop Filtering 随机 0.5-2kHz 陷波 频率缺失
Low-pass / High-pass 截止频率 1-8kHz 频带限制
Time Stretch 0.85-1.15x 速度变化
Pitch Shift -6 ~ +6 semitones 调性变化(哼唱)
Equalizer Randomization 随机增益 ±6dB 音色变化
Resampling 8-44.1kHz 采样率退化
MP3 Compression 32-128kbps 压缩失真
Reverb 房间混响模拟 远场录音
Volume Jitter -12 ~ 0 dB 响度变化
Time Masking (SpecAug) 遮罩 10-50 帧 局部缺失
Frequency Masking (SpecAug) 遮罩 8-16 bins 局部频率缺失

5.2.2 哼唱专用增强

增强操作 说明
F0 抖动 基频随机扰动 ±5%
节奏抖动 节拍随机扰动 ±10%
添加呼吸声 插入随机位置的呼吸音
音色变异 使用不同的合成器/人声
单音偏差 部分音符替换为邻音(模拟跑调)

5.2.3 数据增强管线

原始音频 (16kHz mono)
  │
  ├─→ [随机裁剪] 3-15s 随机片段
  ├─→ [重采样] 8kHz / 16kHz / 22.05kHz / 44.1kHz 随机选择
  ├─→ [响度归一化] RMS = target_loudness
  ├─→ [噪声叠加] AWGN / Pink / 背景音 按概率叠加
  ├─→ [滤波器] 低通/高通/带阻/均衡器 随机选择
  ├─→ [时域变化] Time Stretch ±15%
  ├─→ [频域变化] Pitch Shift ±6 semitones
  ├─→ [压缩模拟] MP3 编码再解码 (64-128kpbs)
  ├─→ [混响] 小型/中型/大型房间混响
  ├─→ [SpecAug] Time & Frequency Masking
  └─→ [特征提取] Mel Spectrogram / Chroma / Raw
       └─→ [输出] 增强后的特征张量

实现:torchaudio / audiomentations / librosa 组合管线。

5.3 数据格式与存储

训练数据格式

/data/
├── songs/                    # 原始歌曲
│   ├── song_001.mp3
│   └── ...
├── references/               # 参考指纹/嵌入
│   ├── ref_001.npy           # 歌曲全曲或多段嵌入
│   └── ...
├── queries/                  # 查询片段 (训练数据)
│   ├── train/
│   │   ├── song_001_seg_001.wav
│   │   └── ...
│   └── val/
│       └── ...
├── metadata.csv              # 歌曲元数据
└── train_pairs.csv           # (query_path, song_id, type)

metadata.csv 格式

song_id,title,artist,album,duration_sec,genre,language
song_001,Song Title,Artist Name,Album Name,240.5,Pop,en

train_pairs.csv 格式

query_path,song_id,query_type,augmentation_params
queries/train/song_001_seg_001.wav,song_001,bgm,"{snr:15, pitch_shift:0}"
queries/train/song_001_hum_001.wav,song_001,humming,"{pitch_shift:-2, tempo:1.1}"

5.4 数据流水线性能要求

指标 目标
增强吞吐 ≥ 200 样本/秒/GPU
预处理缓存 频谱图存入 LMDB/RecordIO
训练样本总量 ≥ 5M Query-Reference 对
参考曲库 ≥ 100K 歌曲(测试阶段)

6. 模型设计

6.1 模型架构选型

本方案采用 双塔结构 (Two-Tower / Siamese Network),两塔共享权重。

                  ┌─────────────────────────────────────┐
                  │         Similarity Score             │
                  │   cosine(q_emb, r_emb)              │
                  └──────────────────┬──────────────────┘
                                     │
                ┌────────────────────┴────────────────────┐
                ▼                                         ▼
        ┌───────────────┐                       ┌───────────────┐
        │   Query       │                       │   Reference   │
        │   Encoder     │                       │   Encoder     │
        │   (shared)    │                       │   (shared)    │
        └───────┬───────┘                       └───────┬───────┘
                │                                       │
        ┌───────┴───────┐                       ┌───────┴───────┐
        │  Input 1      │                       │  Input 2      │
        │  (Mel Spec)   │                       │  (Mel Spec)   │
        └───────────────┘                       └───────────────┘

6.2 候选骨干网络

方案 A: CNN-Transformer (推荐)

Input: Mel-Spectrogram (1, 128, T)  — 单通道, 128 Mel bins, 变长时间
  │
  ├─ Conv2D(1→32, 3×3, stride=1) + BN + ReLU
  ├─ Conv2D(32→64, 3×3, stride=2) + BN + ReLU
  ├─ Conv2D(64→128, 3×3, stride=2) + BN + ReLU
  ├─ Conv2D(128→256, 3×3, stride=2) + BN + ReLU
  │
  ├─ Reshape: (batch, T', 256)
  ├─ Transformer Encoder × 4 (d_model=256, nhead=8, dim_feedforward=1024)
  ├─ [CLS] Token Pooling / Global Average Pooling
  ├─ Projection: 256 → 256 (Linear + LayerNorm)
  └─ L2 Normalize → Embedding (256-dim)

总参数量: ~8-12M | MACs: ~2-5G per 5s audio

方案 B: EfficientNet-ish (轻量级)

Input: Mel-Spectrogram (3, 128, T) — 拼接近邻帧伪 RGB
  │
  ├─ MBConv blocks (EfficientNet-B0 like)
  │   - Stem: Conv 3×3, 32ch
  │   - Stage 1-7: MBConv with SE
  │   - Head: Conv 1×1, 1280ch
  ├─ Global Average Pooling
  ├─ Dropout 0.2
  ├─ Projection: 1280 → 256
  └─ L2 Normalize → Embedding (256-dim)

总参数量: ~5-8M | MACs: ~1-3G per 5s audio

方案 C: 纯 Attention (AST-like)

Input: Mel-Spectrogram (1, 128, T)
  │
  ├─ Patch Embedding (16×16 patches) + Position Embedding
  ├─ Transformer Encoder × 12 (d_model=768, nhead=12)
  ├─ [CLS] Token
  ├─ Projection: 768 → 256
  └─ L2 Normalize → Embedding (256-dim)

总参数量: ~80-90M | MACs: ~5-15G per 5s audio 优势: 准确率最高 | 劣势: 推理速度较慢

推荐: 方案 A (CNN-Transformer) 作为主选,方案 B 作为备选轻量级。

6.3 训练损失函数

6.3.1 主损失: SupConLoss (Supervised Contrastive Loss)

对于 batch 中每个 anchor a,
正样本集 P(a) = 所有与 a 同歌曲的样本
负样本集 N(a) = 与 a 不同歌曲的样本

L_supcon = Σ_a [ -1/|P(a)| · Σ_{p∈P(a)} log( exp(sim(z_a, z_p)/τ) / Σ_{n∈N(a)∪P(a)} exp(sim(z_a, z_n)/τ) ) ]

6.3.2 辅助损失: ArcFace / CosFace (可选)

当曲库有固定类别标签时,可附加分类损失:

L_arcface = -log( exp(s·cos(θ_y + m)) / (exp(s·cos(θ_y + m)) + Σ_j≠y exp(s·cos θ_j)) )

6.3.3 总损失

L_total = λ₁ · L_supcon + λ₂ · L_arcface + λ₃ · L_triplet

推荐 λ₁=1.0, λ₂=0.3, λ₃=0.1

6.4 哼唱识别专用模块

对于哼唱输入,在主干网络外增加一个旋律编码分支

哼唱音频
  │
  ├─ F0 估计 (CREPE / PYIN) → F0 轮廓 (hourglass-shaped)
  ├─ Chroma CQT → 12-bin 色谱图
  │
  ├─ 可选融合策略:
  │   A) 早融合 (Early Fusion): Mel + Chroma 通道拼接 → 同一网络
  │   B) 晚融合 (Late Fusion): Mel 分支 + Chroma 分支分别编码 → 拼接嵌入
  │   C) 分叉网络 (Forked): 共享底层特征层,高层分支出 Mel 和 Chroma 特征
  │
  └─ → 256-dim Embedding

推荐使用 晚融合 方案,在训练时将 Mel 特征和 Chroma 特征分别经过共享底层后拼接,再投影到 256 维。

6.5 多尺度匹配策略

由于 Query 长度可变(3-15s),使用多尺度滑窗:

Reference (全曲 3min):
  [───── Window 1 (5s) ─────]
         [───── Window 2 (5s) ─────]
                [───── Window 3 (5s) ─────]
                       ... (stride = 2.5s)

每个窗口 → Reference Embedding Matrix: (num_windows, 256)

Query (5s) → Query Embedding: (1, 256)

匹配: max_sim = max(sim(query_emb, ref_window_emb_i) for i in windows)

7. 训练细节

7.1 实验环境

配置 规格
GPU NVIDIA A100 (80GB) × 4
CPU AMD EPYC 64C / Intel Xeon 48C
RAM 512 GB
存储 NVMe SSD 4TB
框架 PyTorch 2.x + Lightning / FSDP
加速 Flash Attention, torch.compile
监控 W&B / MLflow

7.2 超参数

参数 备注
Audio SR 16000 Hz 统一采样率
Frame Size 1024 (~64ms) STFT 窗长
Hop Size 512 (~32ms) STFT 步长
Mel Bins 128 梅尔滤波器数量
Max Duration 10s 训练时音频截断长度
Embedding Dim 256 嵌入向量维度
Batch Size 512-1024 分布式训练
Optimizer AdamW β=(0.9, 0.999)
Learning Rate 3e-4 Cosine Annealing
Weight Decay 0.01 L2 正则化
Warmup Steps 5000 Linear Warmup
Epochs 100-200 Early Stopping
Temperature τ 0.07 对比学习温度
Label Smoothing 0.1 防止过拟合
Gradient Clipping 1.0 Max norm
Mixed Precision bfloat16 加速训练
Scheduler Cosine Decay Warm restarts

7.3 训练流程

Step 1: 数据准备
  1. 收集原始歌曲 → 16kHz mono → 存储为 WAV
  2. 随机裁剪 + 数据增强 → 生成 Query/Reference 对
  3. 提取 Mel 频谱 → 存储为 .npy (可选在线提取)
  4. 分割 train/val/test (80/10/10)

Step 2: 预训练 (可选)
  1. 在大规模无标签数据上使用 SimCLR / BYOL 做自监督预训练
  2. 或使用公开预训练权重 (AudioMAE, CLAIR, CLAP)

Step 3: 有监督对比学习训练
  1. 加载预训练权重或从头初始化
  2. 每个 batch: 从 B 个歌曲各取 K 个片段 → B×K 样本
  3. 计算 SupConLoss + 辅助损失
  4. 每 N 步验证集评估 Recall@1, Recall@5
  5. 最佳模型保存 checkpoint

Step 4: 哼唱微调 (可选阶段)
  1. 使用哼唱数据 + 数据增强对模型做有监督微调
  2. 固定部分底层参数,微调顶层和高层 Transformer
  3. Learning rate: 1e-5 (较小)

Step 5: 索引构建
  1. 对所有歌曲提取 Reference Embeddings
  2. 使用 Faiss 构建 IVF+HNSW 索引
  3. 评估索引准确率与检索速度

7.4 评估指标

指标 说明 目标值
Recall@1 Top-1 准确率 ≥ 90% (BGM), ≥ 80% (哼唱)
Recall@5 Top-5 召回率 ≥ 95% (BGM), ≥ 90% (哼唱)
MRR Mean Reciprocal Rank ≥ 0.9
mAP Mean Average Precision ≥ 0.88
QPS Queries Per Second (单 GPU) ≥ 500
P50 Latency 中位数响应时间 ≤ 100ms
P99 Latency 99% 响应时间 ≤ 500ms
Index Build 10万曲库索引构建时间 ≤ 30min
Index Size 索引占用内存 ≤ 2GB (100K 曲)

7.5 消融实验设计

实验 变量 预期验证目标
特征对比 Mel vs Chroma vs CQT vs Raw 最优输入特征
骨干对比 CNN vs CNN-Tfm vs AST vs EffNet 最优架构
嵌入维度 64 vs 128 vs 256 vs 512 性能-容量平衡
对比损失 SupCon vs Triplet vs NT-Xent vs ArcFace 最优损失函数
温度系数 τ=0.05, 0.07, 0.1, 0.2 最优温度
数据增强 无增强 vs 基础 vs 全部 增强贡献度
哼唱策略 早融合 vs 晚融合 vs 分叉 最优融合方式
曲库抗噪 添加噪声曲库干扰 抗干扰能力

7.6 分布式训练策略

# 使用 PyTorch DDP / FSDP
torchrun --nproc_per_node=8 train.py \
  --batch_size 64 \
  --model cnn_transformer \
  --embed_dim 256 \
  --max_duration 10 \
  --lr 3e-4 \
  --epochs 200 \
  --warmup 5000 \
  --fp16 \
  --dataset_path /data/acr \
  --save_interval 10

8. 推理与匹配策略

8.1 推理流程

用户输入 Query (任意时长)
  │
  ├─ 1. 音频预处理 (重采样+通道合并+归一化)
  ├─ 2. 滑窗切片 (5s 窗口, 2.5s 步长)
  │     如果 Query < 3s: 补充静音到 3s → 拒绝/低置信度
  │     如果 3s ≤ Query ≤ 15s: 单窗口或最多 2 窗口
  │     如果 Query > 15s: 多窗口 5s 滑窗
  │
  ├─ 3. 特征提取 (Mel Spectrogram)
  │
  ├─ 4. 嵌入推理 (模型 forward) → query_embs: (num_windows, 256)
  │
  ├─ 5. 候选检索
  │     a) 对每个窗口嵌入做 ANN 检索 → Top-50 × num_windows
  │     b) 合并候选并去重 → Top-100
  │     c) 精排: 精确相似度计算 → Top-10
  │
  ├─ 6. (Optional) 时间对齐验证
  │     - 对 Top-10 候选提取频谱图峰值
  │     - 计算与 Query 的时间偏移直方图
  │     - 一致性验证 → 更新置信度
  │
  ├─ 7. 置信度校准
  │     - 计算 query_embs 与各候选嵌入的最大相似度
  │     - Z-score 标准化: score_z = (score - μ_candidates) / σ_candidates
  │     - 应用阈值 (score_z > 2.0 或直接阈值 > 0.7)
  │
  └─ 8. 输出结果

8.2 流式推理 (Streaming)

对于长音频流 (如直播、电台监听),支持流式识别:

音频流输入 (16kHz, 实时)
  │
  ├─ 环形缓冲区 (Ring Buffer, 15s 容量)
  ├─ 每积累 2.5s 新音频 → 触发一次识别
  ├─ 取: 缓冲区末尾 5s 作为当前 Query
  ├─ 嵌入 → ANN 检索 (使用缓存减少重复计算)
  ├─ 结果缓存与平滑: 连续 N 次命中同一歌曲 → 确认输出
  └─ 重复

8.3 拒绝策略 (Rejection)

当 Query 不在库中时,应可靠地拒绝(低误报率):

策略 实现
绝对阈值 max_score < 0.5 → 拒绝
相对阈值 max_score - second_score < 0.15 → 拒绝
分布阈值 max_score < μ_candidates + 2·σ_candidates → 拒绝
混合策略 三者加权组合
验证分支 增加"非歌分类"头,判断输入是否为有效音乐

8.4 缓存策略

Query → 特征 Cache (LRU):
  - Key: audio_hash (MD5 of first 2s)
  - Value: (query_embedding, timestamp)
  - TTL: 30 分钟
  - Max size: 10K entries

热门歌曲 Cache:
  - 频繁命中的歌曲嵌入常驻内存
  - 使用 LFU eviction

9. 使用方法

9.1 安装

# 克隆仓库
git clone <repo-url> && cd acr-engine

# 创建环境
conda create -n acr python=3.11 && conda activate acr

# 安装依赖
pip install -r requirements.txt

# 可选: GPU 版 Faiss
pip install faiss-gpu

# 安装 torchaudio (含 CUDA)
pip install torch torchaudio --index-url https://download.pytorch.org/whl/cu121

9.2 数据导入

# 批量导入歌曲到曲库
python scripts/ingest.py \
  --input /data/music_library/ \
  --format mp3 \
  --recursive \
  --metadata metadata.csv

# 导入单曲
python scripts/ingest.py --input song.mp3 --song-id "song_001"

9.3 训练

# 完整训练流程
python train.py \
  --config configs/default.yaml \
  --data /data/acr/ \
  --output /models/acr/ \
  --epochs 200 \
  --gpus 4

# 继续训练 (从 checkpoint)
python train.py --resume /models/acr/checkpoint_epoch_100.ckpt

# 哼唱微调
python train.py \
  --config configs/humming_finetune.yaml \
  --resume /models/acr/pretrained.ckpt \
  --data /data/humming/

9.4 索引构建

# 构建 Faiss 索引
python scripts/build_index.py \
  --model /models/acr/best.ckpt \
  --songs /data/songs/ \
  --output /index/acr_index.faiss \
  --index-type "IVF4096,PQ16" \
  --gpu

9.5 API 服务启动

# 启动 REST API (HTTP)
python serve.py \
  --model /models/acr/best.ckpt \
  --index /index/acr_index.faiss \
  --port 8088 \
  --workers 4

# 启动 gRPC 服务 (推荐生产使用)
python serve.py --mode grpc --port 50051

# 使用 Docker Compose
docker-compose up -d

9.6 客户端调用

Python 客户端:

import requests

url = "http://localhost:8088/v1/recognize"
files = {"audio": open("query.wav", "rb")}
params = {"top_n": 5, "mode": "auto"}

resp = requests.post(url, files=files, params=params)
print(resp.json())
# {
#   "candidates": [
#     {"song_id": "...", "title": "...", "artist": "...",
#      "confidence": 0.92, "match_type": "bgm"}
#   ],
#   "processing_time_ms": 45.2
# }

命令行:

# 识别本地音频文件
python cli.py recognize --audio query.mp3 --top-n 5

# 录音识别 (麦克风)
python cli.py recognize --mic --duration 5

# 流式识别 (文件)
python cli.py stream --input live_audio.wav --interval 2.5

9.7 SDK 集成

Python: pip install acr-sdk
Go:     go get github.com/xxx/acr-go
Rust:   cargo add acr-rs
Java:   Maven: com.xxx:acr-client:1.0

Python SDK 使用示例:

from acr_sdk import ACRClient

client = ACRClient(endpoint="localhost:50051", mode="grpc")

# 识别
result = client.recognize("query.wav", mode="humming")
print(f"Song: {result.title}, Confidence: {result.confidence:.2f}")

# 批量入库
client.ingest("/data/new_songs/")

# 删除
client.delete_song("song_001")

10. SOTA 调研与对比

10.1 学术界 SOTA

方法 年份 核心思想 哼唱支持 Recall@1 (BGM) Recall@1 (Humming)
Shazam (Wang) 2003 谱峰哈希指纹 :x: ~85%* N/A
SoundHound 2006 旋律轮廓+指纹 :white_check_mark: ~88%* ~75%*
Dejavu 2015 Shazam 开源实现 :x: ~82% N/A
MatchNet 2018 Siamese CNN + Triplet :x: ~90% N/A
CLAP (LAION) 2023 对比语言-音频预训练 :x: ~87% N/A
AudioMAE 2023 掩码自编码器预训练 :x: ~85% N/A
Contrastive Audio (Oord) 2018 CPC + 对比学习 :x: ~86% N/A
HummingBird 2024 Chroma + 对比学习 :white_check_mark: ~91% ~82%
Singer (ByteDance) 2024 多任务对比学习 :white_check_mark: ~93% ~85%
Ours 2026 CNN-Tfm + SupCon + 哼唱融合 :white_check_mark: ≥92% ≥83%

* 为公开披露的估计值,非学术基准

10.2 工业界产品对比

产品 识别速度 BGM 准确率 哼唱准确率 曲库规模 延迟
Shazam (Apple) :star::star::star::star::star: :star::star::star::star::star: :x: 亿级 ~2s
SoundHound :star::star::star::star: :star::star::star::star: :star::star::star::star::star: 千万级 ~3s
网易云音乐 :star::star::star::star: :star::star::star::star: :star::star::star::star: 千万级 ~2s
QQ音乐 :star::star::star::star: :star::star::star::star: :star::star::star: 千万级 ~2s
Google Sound Search :star::star::star::star: :star::star::star::star: :star::star::star: 亿级 ~3s
Ours :star::star::star::star: :star::star::star::star: :star::star::star::star: 百万级(初期) ≤0.5s

10.3 本方案的边际优势 (vs 现有方案)

  1. 哼唱融合训练:通过专用的哼唱增强和对比学习策略,哼唱识别准确率显著优于纯指纹方案
  2. 混合架构:CNN-Transformer 比纯 CNN 有更好的序列建模能力,比纯 Transformer 更高效
  3. 级联检索:ANN 粗筛 + 精确重排 + 时间对齐验证,兼顾速度与精度
  4. 数据增强系统:全面的增强策略涵盖 BGM、哼唱、录音三大场景
  5. 可扩展性:增量索引支持动态歌库,无需重训练

11. Roadmap

11.1 阶段规划

Phase 0: 基础建设 (Week 1-2)
├── 环境搭建与依赖配置
├── 数据探索与预处理 pipeline
├── 基础特征提取模块 (Mel, Chroma, CQT)
├── 数据增强模块 (audiomentations pipeline)
└── 基线模型: Shazam 式指纹法 (Dejavu fork)

Phase 1: V1 MVP (Week 3-6)
├── CNN-Transformer 模型实现
├── SupConLoss 训练管线
├── 基础数据收集 (FMA + MUSDB18 + GTZAN)
├── 训练 100K Query-Reference 对的模型
├── Faiss 索引构建 Pipeline
├── REST API + gRPC 服务
└── 本地 CLI 工具

Phase 2: 哼唱支持 (Week 7-10)
├── 哼唱数据收集 (内部录制 + MIR-QBSH)
├── 哼唱增强 Pipeline
├── Chroma 分支 + 旋律轮廓编码
├── 哼唱-原曲对比学习微调
├── 哼唱专用评估集构建
└── 哼唱模式 API 支持

Phase 3: 生产优化 (Week 11-14)
├── 模型量化 (INT8 / FP16)
├── ONNX Runtime / TensorRT 部署
├── 级联检索策略优化
├── 缓存系统实现 (LRU + LFU)
├── 流式识别支持
├── 负载测试与性能调优
├── Docker + K8s 部署配置
└── CI/CD Pipeline

Phase 4: 进阶能力 (Week 15-20)
├── 分布式曲库 (Index Sharding)
├── 多语言歌曲支持
├── 歌曲翻唱/Remix 识别
├── 歌曲定位 (识别到歌曲中具体位置)
├── 歌词时间轴对齐
├── Web dashboard (曲库管理 + 监控)
├── 增量学习 (在线模型更新)
└── 边缘端部署 (移动端/嵌入式)

Phase 5: 持续迭代 (Week 21+)
├── 用户反馈环路
├── A/B 测试框架
├── 模型持续训练 (CT)
├── 数据处理自动化
├── 新 SOTA 方法集成
├── 商业合作接入
└── 合规与版权管理

11.2 里程碑

里程碑 时间 交付物 验收标准
M0: 基础准备 Week 2 开发环境、数据管线 增强管线吞吐 ≥ 200/秒
M1: V1 MVP Week 6 可运行的识别引擎 Recall@1 ≥ 85% (BGM)
M2: 哼唱上线 Week 10 哼唱识别能力 Recall@1 ≥ 75% (Humming)
M3: 生产就绪 Week 14 高性能服务 P50 ≤ 100ms, QPS ≥ 500
M4: 进阶能力 Week 20 企业级平台 多场景覆盖, 曲库 100 万+

12. Checklist

12.1 数据准备

  • 确定数据来源并获取授权
  • 下载并组织原始歌曲库 (≥ 100K songs)
  • 统一转为 16kHz mono WAV 格式
  • 实现数据增强管线 (全部增强策略)
  • 生成训练 Query-Reference 对 (≥ 5M pairs)
  • 构建哼唱数据集 (≥ 10K 段)
  • 分割 train/val/test (80/10/10)
  • 验证数据分布多样性 (流派、语言、年代)
  • 实现数据加载器 (支持在线增强)
  • 数据版本控制 (DVC / HuggingFace Datasets)

12.2 模型开发

  • 实现基础 CNN-Transformer 骨干
  • 实现训练循环 (SupConLoss + 辅助损失)
  • 实现哼唱分支 (Chroma + F0 融合)
  • 实现多尺度滑窗匹配
  • 实现基准模型 (Shazam + Dejavu)
  • 实现对比实验框架
  • 超参数搜索 (学习率、温度、嵌入维度等)
  • 训练收敛验证

12.3 索引与检索

  • 实现 Faiss 索引构建管线
  • 实现 ANN + 精确重排的级联检索
  • 实现时间对齐验证
  • 实现置信度校准与拒绝策略
  • 索引增量更新 (增删歌曲)
  • 索引持久化与加载优化

12.4 服务部署

  • 实现 REST API (FastAPI / Flask)
  • 实现 gRPC API
  • 模型导出 (ONNX / TorchScript)
  • 模型量化 (INT8 / FP16)
  • 实现流式识别
  • 实现缓存系统
  • 负载测试 & 性能调优
  • Docker 镜像构建
  • Docker Compose / K8s 配置文件
  • 监控与告警 (Prometheus + Grafana)
  • 日志系统 (结构化日志)
  • CI/CD Pipeline

12.5 质量保障

  • 单元测试 (核心模块覆盖率 ≥ 80%)
  • 集成测试 (端到端识别流程)
  • 性能基准测试 (延迟、吞吐、内存)
  • 鲁棒性测试 (噪声、压缩、哼唱变化)
  • 回归测试 (每次模型更新)
  • 评估集标注与维护
  • 安全审计 (注入、权限、数据泄露)

12.6 文档与交付

  • 设计文档 (本文件)
  • API 文档 (Swagger / OpenAPI)
  • 部署文档 (Docker, K8s, 环境要求)
  • 用户手册 (SDK 使用指南)
  • 训练文档 (数据、超参数、实验记录)
  • 运维手册 (监控、日志、故障排查)
  • 演示 / demos

13. Changelog

[v1.0] — 2026-06-02

Added

  • 初始设计文档创建
  • 完整架构设计 (双塔对比学习 + Faiss 检索)
  • 数据增强策略 (12+ 种操作)
  • 哼唱识别模块设计
  • SOTA 调研对比表
  • Roadmap (Phase 0-5)
  • Checklist (6 大模块)

[Planned] — v1.1

Planned

  • 实验基准数据
  • 训练收敛曲线与指标
  • 模型参数量与推理延迟详细报告
  • 消融实验结果
  • 用户反馈收集结果

[Planned] — v2.0

Planned

  • 分布式曲库方案
  • 边缘端部署方案
  • 在线学习模块
  • 歌词时间轴识别

14. Handoff 交付清单

14.1 交付物概要

类别 交付物 责任人 验收人
设计 ACR 设计文档 (本文) 架构师 技术负责人
数据 训练数据集 & 评估集 数据工程师 算法工程师
代码 模型训练代码 算法工程师 架构师
代码 API 服务 & CLI 工具 后端工程师 架构师
部署 Docker / K8s 配置 DevOps 运维
文档 API 文档 & 用户手册 技术写作 产品经理
测试 测试报告 & 性能基准 QA 技术负责人

14.2 验收标准

[ ] 端到端识别流程通过: 输入音频 → 输出正确歌曲
[ ] Recall@1 ≥ 90% (BGM 场景, 干净音频)
[ ] Recall@1 ≥ 80% (哼唱场景)
[ ] P50 延迟 ≤ 100ms (单机器, 百万曲库)
[ ] P99 延迟 ≤ 500ms
[ ] 并发 QPS ≥ 100 (单机器, 4 CPU cores)
[ ] 曲库增量更新 ≤ 1s/曲
[ ] 所有单元测试通过 (覆盖率 ≥ 80%)
[ ] 安全审计无高危漏洞
[ ] 文档完整性审查通过

14.3 风险与缓解

风险 概率 影响 缓解措施
版权音乐数据获取困难 优先使用开源数据集; 探索合成数据
哼唱数据不足 合成哼唱 + Mid-to-Audio 生成
噪声下准确率不达标 更激进的数据增强; 模型集成
大曲库检索延迟 多级索引; GPU 加速检索
模型过拟合 强正则化; 大规模数据; Dropout
哼唱与 BGM 模式冲突 双模式 / 级联识别

14.4 移交步骤

  1. 代码移交:所有代码推送到主仓库,PR 审核通过,CI 绿色
  2. 模型移交:最佳模型 checkpoint + 导出 ONNX/TorchScript
  3. 数据移交:训练数据、评估数据、数据管线代码
  4. 索引移交:Faiss 索引文件 + 元数据
  5. 部署移交:Docker 镜像推送到 Registry,K8s 配置文件就绪
  6. 文档移交:所有文档整理到 /docs/ 目录
  7. 演示移交:运行 demo 脚本,展示端到端识别流程
  8. 培训移交:对运维/开发人员进行 2 小时技术培训

15. 参考与引用

15.1 学术论文

主题 论文 年份
音频指纹 (Shazam) Wang, A. "An Industrial-Strength Audio Search Algorithm" 2003
对比学习 (SimCLR) Chen et al. "A Simple Framework for Contrastive Learning" 2020
监督对比学习 Khosla et al. "Supervised Contrastive Learning" 2020
频谱图增强 (SpecAug) Park et al. "SpecAugment: A Simple Augmentation Method" 2019
语音谱图 Transformer Gong et al. "AST: Audio Spectrogram Transformer" 2021
CLAP Wu et al. "Large-scale Contrastive Language-Audio Pretraining" 2023
AudioMAE Huang et al. "Masked Autoencoders that Listen" 2023
CPC for Audio Oord et al. "Representation Learning with Contrastive Predictive Coding" 2018
哼唱识别综述 Sharma et al. "Query-by-Humming: A Survey" 2023
CREPE Kim et al. "CREPE: A Convolutional Representation for Pitch Estimation" 2018

15.2 开源项目

项目 说明 链接
Dejavu Shazam 指纹法 Python 实现 https://github.com/worldveil/dejavu
Faiss 向量相似度搜索库 (Meta) https://github.com/facebookresearch/faiss
CLAP 对比语言-音频预训练 (LAION) https://github.com/LAION-AI/CLAP
torchaudio PyTorch 音频工具包 https://github.com/pytorch/audio
audiomentations 音频数据增强库 https://github.com/iver56/audiomentations
librosa 音频分析库 https://github.com/librosa/librosa
marsyas 音频处理框架 https://github.com/marsyas/marsyas
Essentia 音频分析库 (UPF) https://github.com/MTG/essentia

15.3 数据集

数据集 规模 用途 许可
FMA (Free Music Archive) 106,574 曲 基础歌曲库 CC
MUSDB18 150 曲 (多轨) 音源分离 研究
GTZAN 1,000 曲 流派分类 (基线) 研究
MIR-QBSH ~4,800 哼唱 哼唱识别 研究
Medley-solos-DB 21,574 片段 音色分析 CC
AudioSet (Google) 2M+ 片段 预训练/多任务 YouTube

附录 A: 快速开始 Demo

#!/usr/bin/env python
"""ACR Engine Quick Demo"""

from acr_engine import ACRPipeline

# 初始化
pipeline = ACRPipeline(
    model_path="models/acr/best.ckpt",
    index_path="index/acr_index.faiss",
    mode="auto"
)

# 批量导入
pipeline.ingest_directory("data/samples/")

# 识别
for query_path in ["query_bgm.wav", "query_hum.wav", "query_noisy.wav"]:
    result = pipeline.recognize(query_path)
    print(f"{query_path}: {result.title} ({result.confidence:.2%})")

附录 B: 配置模板 (configs/default.yaml)

model:
  name: cnn_transformer
  embed_dim: 256
  backbone:
    cnn_channels: [32, 64, 128, 256]
    transformer_layers: 4
    nhead: 8
    dim_feedforward: 1024
  humming_branch:
    enabled: true
    fusion: late
    chroma_bins: 12
    f0_embed_dim: 64

data:
  sample_rate: 16000
  n_mels: 128
  n_fft: 1024
  hop_length: 512
  max_duration: 10.0
  min_duration: 3.0
  window_size: 5.0
  window_stride: 2.5

augmentation:
  noise:
    enable: true
    snr_range: [5, 30]
  pitch_shift:
    enable: true
    semitones_range: [-6, 6]
  time_stretch:
    enable: true
    rate_range: [0.85, 1.15]
  mp3_compression:
    enable: true
    bitrate_range: [32, 128]
  spec_augment:
    enable: true
    time_mask_max: 50
    freq_mask_max: 16

training:
  batch_size: 512
  epochs: 200
  lr: 0.0003
  weight_decay: 0.01
  warmup_steps: 5000
  temperature: 0.07
  loss:
    supcon_weight: 1.0
    arcface_weight: 0.3
    triplet_weight: 0.1
  optimizer: adamw
  scheduler: cosine
  mixed_precision: bf16
  gradient_clip: 1.0

index:
  type: "IVF4096,PQ16"
  metric: cosine
  train_on_gpu: true
  nprobe: 64

serving:
  host: "0.0.0.0"
  port: 8088
  workers: 4
  max_query_duration: 30.0
  cache_size: 10000
  reject_threshold: 0.5
  top_n: 5

logging:
  level: INFO
  format: json
  output: stdout