音频分类:从 MFCC 上的 k-NN 到 AST 与 BEATs 本节摘要:从「狗叫 vs 警笛」到「这是哪种语言」,全是音频分类(Audio Classification)。特征用梅尔,架构每十年换一代,评估指标始终是 AUC、F1 和每类召回率。2026 年的基线架构已经成熟:对数梅尔 → CNN 或 Transformer → softmax,真正的难点不在网络,而在数据——音频数据集类别极度失衡、域漂移严重(干净 vs 嘈杂)、标签噪声大(谁定义的「城市嘈杂」与「餐厅噪声」?)。
本节摘要:从「狗叫 vs 警笛」到「这是哪种语言」,全是音频分类(Audio Classification)。特征用梅尔,架构每十年换一代,评估指标始终是 AUC、F1 和每类召回率。2026 年的基线架构已经成熟:对数梅尔 → CNN 或 Transformer → softmax,真正的难点不在网络,而在数据——音频数据集类别极度失衡、域漂移严重(干净 vs 嘈杂)、标签噪声大(谁定义的「城市嘈杂」与「餐厅噪声」?)。本节将沿「MFCC 上的 k-NN → 对数梅尔上的 2D CNN → 音频频谱图 Transformer(AST)→ 自监督预训练的 BEATs」这条阶梯逐级搭建,讲透类别失衡的对策(均衡采样、Mixup、SpecAugment)与不同任务场景的评估指标选型。读完本节,你能为一个全新的音频分类任务正确选择架构、增强策略、类别均衡方案与评估指标。
阅读完本节,你应当能够:
拿到一段 10 秒音频,想知道「这是什么」。城市声音(警笛、电钻、狗叫)、语音指令(yes/no/stop)、语种识别(en/es/ar)、说话人情绪(愤怒/中性)、环境声音(室内/室外、人声嘈杂)——全是音频分类。2026 年基线架构成熟:对数梅尔 → CNN 或 Transformer → softmax。
核心难点不在网络,而在数据。音频数据集类别极度失衡、域漂移严重、标签噪声大。问题的 80% 是数据策展、数据增强与评估,而不是把 CNN 换成 Transformer。
(T, n_mels) 的对数梅尔当图像,套 ResNet-18 或 VGG,时间轴全局平均池化,softmax 分类。仍是 2026 年多数 Kaggle 比赛的基线。ESC-50:50 类各 40 段——均衡、简单。UrbanSound8K:10 类、10:1 失衡。AudioSet:632 类、长尾达 100 000:1。有效的对策:
💡 SpecAugment 的反直觉之处:它把频谱图的一大块直接抹零,看起来像在「破坏」信号,但正是这种破坏逼迫模型不能依赖任何单一频率或时段,从而学到更鲁棒的特征。它比几乎所有时域增强(加噪、变速)都更有效,且实现成本极低。
2026 年值得记住的数字:
| 基准 | 基线 | 2026 SOTA | 来源 |
|---|---|---|---|
| ESC-50 | 82%(AST) | 97.0%(BEATs-iter3) | BEATs 论文(2024) |
| AudioSet mAP | 0.485(AST) | 0.548(BEATs-iter3) | HEAR 排行榜 2026 |
| Speech Commands v2 | 98%(CNN) | 99.0%(Audio-MAE) | HEAR v2 结果 |
def featurize_mfcc(signal, sr, n_mfcc=13, n_mels=40, frame_len=400, hop=160): mag = stft_magnitude(signal, frame_len, hop) fb = mel_filterbank(n_mels, frame_len, sr) mels = apply_filterbank(mag, fb) log = log_transform(mels) return [dct_ii(frame, n_mfcc) for frame in log]
def summarize(mfcc_frames): n = len(mfcc_frames[0]) mean = [sum(f[i] for f in mfcc_frames) / len(mfcc_frames) for i in range(n)] var = [ sum((f[i] - mean[i]) ** 2 for f in mfcc_frames) / len(mfcc_frames) for i in range(n) ] return mean + var
简单但强:沿时间轴取均值 + 方差,给 13 维 MFCC 一个 26 维定长嵌入,瞬时跑完。直到 2017 年还能在 ESC-50 上打败 SOTA 神经网络基线。
def cosine(a, b): dot = sum(x * y for x, y in zip(a, b)) na = math.sqrt(sum(x * x for x in a)) or 1e-12 nb = math.sqrt(sum(x * x for x in b)) or 1e-12 return dot / (na * nb) def knn_classify(q, bank, labels, k=5): sims = sorted(range(len(bank)), key=lambda i: -cosine(q, bank[i]))[:k] votes = Counter(labels[i] for i in sims) return votes.most_common(1)[0][0]
import torch.nn as nn class AudioCNN(nn.Module): def __init__(self, n_mels=80, n_classes=50): super().__init__() self.body = nn.Sequential( nn.Conv2d(1, 32, 3, padding=1), nn.ReLU(), nn.MaxPool2d(2), nn.Conv2d(32, 64, 3, padding=1), nn.ReLU(), nn.MaxPool2d(2), nn.Conv2d(64, 128, 3, padding=1), nn.ReLU(), nn.AdaptiveAvgPool2d(1), ) self.head = nn.Linear(128, n_classes) def forward(self, x): # x: (B, 1, T, n_mels) return self.head(self.body(x).flatten(1))
300 万参数,单卡 RTX 4090 上 ESC-50 训练约 10 分钟,准确率 80% 以上。
设计要点:把对数梅尔当图像喂给 2D CNN 之所以有效,是因为语音的「共振峰」在频率轴上是局部连续的、随时间缓慢移动的——这与图像中边缘、纹理的局部结构高度同构,因此卷积核能直接套用。
AdaptiveAvgPool2d(1)把任意时长的频谱图压成定长向量,是该流水线支持变长输入的关键。
from transformers import ASTFeatureExtractor, ASTForAudioClassification ext = ASTFeatureExtractor.from_pretrained("MIT/ast-finetuned-audioset-10-10-0.4593") model = ASTForAudioClassification.from_pretrained( "MIT/ast-finetuned-audioset-10-10-0.4593", num_labels=50, ignore_mismatched_sizes=True, ) inputs = ext(audio, sampling_rate=16000, return_tensors="pt") logits = model(**inputs).logits
BEATs 用 microsoft/BEATs-base 经 beats 库加载,transformers 的 API 形状一致。
2026 年工具栈:
| 场景 | 起步选项 |
|---|---|
| 小数据集(<1000 段) | MFCC 均值上的 k-NN(你的基线)+ 音频增强 |
| 中等数据集(1K~100K) | BEATs 或 AST 微调 |
| 大数据集(>100K) | 从零训练,或微调 Whisper 编码器 |
| 实时、边缘设备 | 40 维 MFCC CNN,量化到 int8(关键词唤醒风格) |
| 多标签(AudioSet) | BEATs-iter3 + BCE 损失 + Mixup + SpecAugment |
| 语种识别 | MMS-LID、SpeechBrain VoxLingua107 基线 |
决策铁律:先冻结骨干,再考虑从零训练。微调 BEATs 的分类头,几小时拿到 95% 的 SOTA,而不是几周。
💡 Hugging Face 的
ASTForAudioClassification.from_pretrained(..., ignore_mismatched_sizes=True)会把预训练的 527 类 AudioSet 头随机重初始化成你的类别数——这正是「保留骨干知识、替换任务头」的标准微调姿势。ignore_mismatched_sizes是关键参数,不加会报形状不匹配错误。
本节产出技能文档(原课程 outputs/skill-classifier-designer.md),针对给定音频分类任务,自动选择架构、增强方案、类别均衡策略、评估指标。核心决策表:
基础:运行 code/main.py。它在 4 类合成数据(不同音高的纯正弦)上训练 k-NN MFCC 基线,报告混淆矩阵。
进阶:把 summarize 替换成 [均值、方差、偏度、峰度] 四阶矩池化。在同一合成数据集上,四阶矩是否优于均值+方差?
挑战:用 torchaudio 在 ESC-50 fold 1 上训练一个 2D CNN,报告 5 折交叉验证准确率。再加 SpecAugment(时间掩码 20、频率掩码 10),报告提升幅度。
下一节,我们转向语音的核心任务——语音识别(ASR),从 CTC、RNN-T 到注意力机制,理解让机器把声音转成文字的三大主流范式。