DeepFilterNet 3:端侧实时全带降噪的开源标杆

DeepFilterNet 是 FAU Erlangen-Nürnberg + WS Audiology 从 2021 年开始迭代的开源实时降噪模型 · 目标是在 CPU 上跑实时 · 处理 48 kHz 全带音频 · 不牺牲主观质量 。到 2023 年的 DeepFilterNet 3(下称 DFN3 )已经用 Rust 重写推理路径 · 单线程 CPU 上论文口径 RTF < 0.05 级别 · 是当前开源侧最强的实时 speech-enhancement baseline 之一。本文用 pip install deepfilternet 装完就跑的默认权重跑一遍同一套 benchmark。

一、DFN3 是什么

  • 代码仓库 & 权重 https://github.com/Rikorose/DeepFilterNet · Apache-2.0 · Rust + Python 双路径 · pip install deepfilternet 首次运行自动拉权重(约 2.3M 参数 · ~10 MB)
  • 采样率 48 kHz 全带(full-band)单声道 · CLI 自动 resample 输入到 48 kHz 处理并输出 48 kHz;Python APIenhance() 要求输入已经在 df_state.sr() = 48 kHz · resample 由 pipeline 显式做
  • 训练目标 speech enhancement · 从「speech + noise / reverb / clipping」还原纯净 speech · 训练集 DNS4 challenge dataset
  • 算法延迟 40 ms · 20 ms window + 50% overlap + 2 帧 look-ahead
  • benchmark(DFN2 论文口径 · DFN3 沿用同套 recipe 微调):DNS4 blind test set OVRL 3.31;单线程 Core-i5 6600U 笔记本 CPU 上 RTF 显著低于 1(论文汇报数值 <0.05 量级 · DFN3 Rust 版更快)

它是 speech-enhancement 模型 · 不是音源分离模型 :目标是「让一路人声更干净」· 训练目标里没有把干净 speech 之外的东西分离 出来的动机 · 而是把 noise / reverb / clipping 从 speech 里滤掉、只留一路输出。这个训练目标决定了它在 case05 餐厅 babble 这类「噪声本身也是人声」的场景下 · 是按能量选主 speaker · 而不是按说话人身份分离(详见 §三)。

演进 · 三代DeepFilterNet (2021 · https://arxiv.org/abs/2110.05588) 首次把「深度滤波(Deep Filtering)」用于全带 SE · 用 ERB 特征减少频域计算 · 提出在 noisy STFT 上按相邻若干帧做复数 FIR 加权求和 估计 clean speech 复数谱 · 而不是传统单帧复数掩码 CRM。DeepFilterNet 2 (2022 · ICASSP · https://arxiv.org/abs/2205.05474) 把架构精简到能在 Raspberry Pi 4 实时跑:encoder / decoder 用 grouped linear + pathway conv 大幅减 FLOPs · GRU hidden 降到 256 · 换成 1D-over-frequency 卷积节省 temporal buffer · 加 batch-size scheduling 稳定训练。DeepFilterNet 3 (2023 · https://arxiv.org/abs/2305.08227) 是工程侧升级 · Python 推理路径全部搬到 Rust · 单条 15 s 音频推理时间进一步下降;本文只关心 pip 默认权重的工程使用 · DFN3 相比 DFN2 的主要可感知变化是推理路径和速度 · 架构理解按 DFN2 的两阶段框架看即可。

ERB 补一句 :ERB (Equivalent Rectangular Bandwidth) 是心理声学上的听觉滤波器带宽尺度 · 类似 Bark scale 但不是 Bark · DFN 系列这里用 ERB 把线性 STFT 频点聚合成 32 个感知匹配带 · 减少后续频域计算量。

DFN2/3 的整体流程(两阶段 speech enhancement):

DFN2/3 的详细网络结构(encoder / ERB decoder / DF decoder 三大块):

核心机制

  • 两阶段建模 · 一粗一细 · Stage 1 先在 32 个 ERB 感知带上给每个 band 预测一个实数增益 G · 直接乘到频谱上------相当于「先把频谱大致形状修对 · 稳态噪声这一步基本能压掉」。Stage 2 只在语音基频和主要共振峰所在的低频 STFT bins 上继续处理(具体上限由模型配置的 DF bin 数决定 · 常见默认覆盖到约 5 kHz)· 用 Deep Filtering 补人声细节。为什么分两步:稳态噪声粗调就够 · 人声细节值得单独用大参数抠 · 分开做总 FLOPs 反而更省
  • Deep Filtering vs 传统复数掩码 · 传统做法(CRM)是「当前帧乘一个复数 mask」------Y[t,f] = M[t,f] · X[t,f] · 只看单帧。DF 是「当前帧 = 前后 N 帧的加权和」------Ŝ[t,f] = Σ_{τ=-K_p}^{K_a} C[τ,t,f] · X[t+τ,f] · 复数 FIR 系数 C 由网络输出 · K_p 表示回看过去帧数 · K_a 表示 look-ahead(DFN3 默认 2 帧)。直观理解:单帧 mask 是「静态修图」· 多帧 FIR 是「用时间上下文合成一个更干净的帧」· 高噪声段前者相位重建不出来 · 后者能------论文口径下高 SNR 场景 SI-SDR +1.5 dB 主要来自这一步

二、CLI 与 Python API 两种用法

安装(命令示意):

复制代码
pip install deepfilternet

方式 1 · CLI(最短闭环 · 一行处理一批文件):

复制代码
# 单文件降噪 · 输出到 output/ · 文件名保留原名
deepFilter audio.wav -o output/

输出 output/audio_DeepFilterNet3.wav · 44.1 kHz 或 48 kHz 都自动 resample。

方式 2 · Python API(想在 pipeline 里直接调 · 本文实测走这条):

复制代码
import torchaudio
from df.enhance import enhance, init_df

model, df_state, _ = init_df()             # 首次自动拉权重
target_sr = df_state.sr()                  # 48000

audio, sr = torchaudio.load("audio.wav")   # (C, T)
if audio.shape[0] > 1:
    audio = audio.mean(dim=0, keepdim=True)   # 混单声道
if sr != target_sr:
    audio = torchaudio.functional.resample(audio, sr, target_sr)
denoised = enhance(model, df_state, audio) # (1, T) · 48 kHz mono 输出
torchaudio.save("out.wav", denoised, target_sr)

几点工程侧要点

  • 单路输出 · 只有 denoised.wav · noise 直接被丢掉 · 拿不到分离出的 noise stem
  • 原生 48 kHz full-band · Python API 需手动 resample · CLI 会自动处理输入采样率并保持 48 kHz 输出;Python API 要求输入已经在 48 kHz · 16 kHz 场景在下游 downsample 回去
  • 实时结构 · 天然流式 · 20 ms 帧 + 50% overlap + 2 帧 look-ahead · 算法延迟 40 ms · chunk-by-chunk 处理没有全局依赖
  • 模型体积轻 · DFN3 权重约 2.3M 参数 / ~10 MB checkpoint · 适合端侧部署
  • 不做多说话人分离 · SE 目标里没有「区分说话人个体」的信号 · case05 类型下要么 babble 全被压 · 要么留下声音最响的那个 · 详见 §三

三、5 条 case · 降噪前后

5 条 case 覆盖音乐 BGM / 白噪 / 键盘打字 / 会议室环境 / 餐厅 babble 5 类噪声场景(benchmark/*.wav)· 用 DNSMOS 打分(微软 DNS-Challenge P.835 primary + P.808 model_v8 · 16 kHz mono · 9.01 s / 9.0 s 分块)· 只比较同一条样本的降噪前后。

注意 :DFN3 输出是 48 kHz · 但 DNSMOS 模型按其要求把输入重采样到 16 kHz 后打分 · 所以表中 MOS 不评价 16 kHz 以上的高频质量 · 只作同一样本前后比较的参考。

DFN3 是单路输出 SE 模型------只出一路 denoised speech · 没有分离出的 noise / no_speech stem。所以下面每条 case 只放「降噪前 / 降噪后」两路对比 · 频谱图也是两栏。

# case(场景) DNSMOS OVRL 前 → 后 BAK 前 → 后 判决
01 加州旅馆(音乐 BGM) 1.12 → 2.05 (+0.93) 1.14 → 3.07 (+1.93) ✅ 有提升 · 副歌段有明显 artifact
02 白噪(稳态宽带) 2.10 → 3.41 (+1.31) 2.01 → 4.18 (+2.17) ✅ 大幅提升 · 稳态噪声主场
03 键盘打字(瞬态噪声) 2.17 → 3.29 (+1.12) 1.90 → 4.15 (+2.25) ✅ 大幅提升 · 瞬态压得很干净
04 会议室(室内环境混合) 2.12 → 3.21 (+1.09) 2.14 → 4.07 (+1.93) ✅ 大幅提升
05 餐厅 babble(多说话人混叠) 2.17 → 3.02 (+0.85) 2.19 → 4.06 (+1.87) ✅ 只保留主说话人 · 但目标是否为主说话人由能量决定

一句话结论 :5 条 case 里 5 条 OVRL 都有约 +0.85 到 +1.31 分的提升 · BAK 提升更明显(+1.87 到 +2.27)· 除 case01 外 · OVRL 后值都在 3.0+ · BAK 后值在 3.07-4.18。case01 属于 speech enhancement 的域外压力测试 (音乐 + vocals · DFN3 训练目标里没有音乐类别)· DNSMOS 只作同样本前后参考 · 音乐质量本身要看听感和频谱 artifact。case05 餐厅 babble 场景要留个心眼 :DNSMOS 从 2.17 涨到 3.02 看起来很漂亮 · 但这不是「DFN3 会做说话人分离」· 只是 SE 模型倾向于保留能量占优的语音成分、把其它 babble 一起压掉。如果目标说话人正好不是最响的那一路 · 你会得到「一个被压下去的目标 + 一个被保留的路人甲」。

3.1 case01 · 加州旅馆 · BGM + vocals 混合

降噪前

降噪后

听感 :BGM 大幅衰减 · 但 vocals 也被削出可闻的剪切痕迹------副歌段元音尾巴收得偏硬 · 呈现门限式压制 · 频谱图上能看到高频段能量断续。可能原因:音乐伴奏跟 speech 的频谱 / 谐波结构高度重叠 · SE 目标下 DFN3 会把 BGM 当 noise 压掉 · 但 vocals 里跟 BGM 频谱重叠的成分也被误伤 · 且默认 recipe 不把 vocals stem 单独保护。

3.2 case02 · 白噪 · 稳态宽带噪声

降噪前

降噪后

看点:宽带底噪整体下移 · speech 谐波结构完整保留 · 稳态噪声是 SE 最舒适的场景。

3.3 case03 · 键盘打字 · 瞬态噪声

降噪前

降噪后

看点:键盘敲击的宽带瞬态竖线被明显削弱 · speech formant 保留 · DF 的多帧时域上下文对亚帧级瞬态处理比单帧 mask 有优势。

3.4 case04 · 会议室 · 室内环境混合

降噪前

降噪后

看点:低频环境噪底 + 空调 hum 被抑制 · speech 保留清晰 · 混响未额外增强也未变差(DFN3 训练里含 reverb 但不专门做 dereverberation)。

3.5 case05 · 餐厅 babble · 多说话人混叠

降噪前

降噪后

看点:主导说话人被保留 · 背景 babble 明显压低但仍有残留(babble 频谱结构跟 speech 相似 · SE 无法完全区分)· 目标说话人不占优时会翻车。

四、四模型对比 · DFN3 适合什么场景

下面是全系列 4 篇公用的一张 DNSMOS 对比图 · 5 case × 4 模型(htdemucs / DFN3 / RNNoise / FRCRN)· 每篇都放这张 · 别的模型的具体行为详见对应篇。

DFN3 在这套 benchmark 上的落点

  • case02 白噪 · OVRL 3.41 · case03 键盘 · 3.29 · case04 会议室 · 3.21 ------ 3 条 case 都拿到 3.0+ OVRL · 稳态 / 瞬态 / 环境混合三类都稳
  • case05 餐厅 babble · OVRL 3.02 ------ 明显压下 babble · BAK 4.06 · 但按能量选主 · 不区分说话人
  • case01 音乐 BGM · OVRL 2.05 ------ 4 个模型里最低的 case01 · 副歌段有可听 artifact · 音乐不是 SE 训练目标

DFN3 适合

  • 端侧实时视频会议 / 直播 / RTC ------ 见 §一 三项工程指标(40 ms 延迟 · ~10 MB 权重 · 论文口径 CPU RTF <0.05 量级)· 三个数字放一起在开源侧几乎无对手
  • 单说话人 + 稳态 / 瞬态 / 环境混合噪声 ------ 白噪 / 键盘 / 会议室这类 · DFN3 都能压到 3.2+ OVRL 且听感自然
  • 全带 48 kHz 输出 ------ 高频细节保留 · 下游是 24 / 48 kHz 的语音播客 / 直播 / 会议录音也能用;含音乐制作 / 伴奏分离的场景不要按音乐增强模型用(case01 已经说明)

DFN3 不适合

  • 多说话人 babble 要指定目标 ------ case05 场景 DFN3 按能量选主 · 想按说话人身份分离得走 TSE 类
  • 音乐场景剥人声 ------ case01 分数明显低于 htdemucs · 副歌段 artifact 可听
  • 嵌入式几十 KB / 超低延迟 <20 ms ------ DFN3 已经很小但还不够小 · 40 ms 延迟已经很低但还不够低

五、写在最后

DFN3 是端侧实时全带降噪 的当前开源标杆------按 §一 三项工程指标(低延迟 / 轻体积 / CPU 实时)· 已经能覆盖视频会议 / 直播 / RTC 类的绝大多数落地需求。case02 白噪 / case03 键盘 / case04 会议室场景听感自然 · 没有明显的门限式 artifact;case05 餐厅 babble 场景 DNSMOS 也不错 · 但含义是「保留了能量占优的那一路语音」而不是「保留了目标说话人」------目标说话人正好是最响那一路时刚好合适 · 否则要上 TSE 类。

工程侧几个提醒:DFN3 输出是单路 48 kHz mono · 拿不到分离出的 noise stem;16 kHz 场景用完要 downsample 回去;音乐类音频里副歌段有可听 artifact · 别把它当音乐分离模型用。观察都基于 5 条样本 · 落地前用自己业务的一批 case 验证

相关推荐
第一程序员1 小时前
AI 辅助编程的 7 个误区:把模型当高级搜索引擎是对它的最大浪费
python·rust·github
Groundwork Explorer2 小时前
W5500 网卡编程初始化与使用指南
python·单片机
逸Y 仙X3 小时前
MCP(模型控制协议)完全指南:从核心概念到实战开发
python·大模型·llm·ai编程·mcp
WILLF4 小时前
前端视角:Python requests vs JS axios
前端·python
哒哒哒5285204 小时前
69. Python: 核心语法-面向对象基础-案例(教务系统)
python
何以解忧,唯有..4 小时前
Python 中获取目录操作完全指南
windows·python·microsoft
南京云森杉木桩4 小时前
常见打桩木品牌推荐,选对材质让工程更稳固
人工智能·python·材质
总有刁民想爱朕ha4 小时前
Python PyQt5图片批量转MP4视频工具:本地离线免费无水印,完整代码
开发语言·python·qt
zyj8890914 小时前
濮阳工厂目视化设计安全警示牌材质怎么选耐用
python·安全·材质