SpeechBrain 实战:基于 SepFormer 的 Microsoft DNS-4 语音增强(训练、评估与 DNSMOS 评测全流程)
【免费下载链接】speechbrainA PyTorch-based Speech Toolkit项目地址: https://gitcode.com/GitHub_Trending/sp/speechbrain
本文是 SpeechBrain 开源语音工具包(PyTorch-based Speech Toolkit)中recipes/DNS/enhancement配方的完整技术指南。该配方以 Microsoft Deep Noise Suppression(DNS)Challenge 4(ICASSP 2022)数据集为训练语料,使用 SepFormer 架构实现单通道语音增强。阅读本文后,你将掌握从 DNS-4 数据下载与 WebDataset 分片合成、到 SepFormer 增强模型训练、再到 DNSMOS 与 PESQ/Si-SNR 等主客观指标评估的完整闭环流程,并能基于 超参数配置 独立复现或调优该增强系统。
一、配方概述与适用场景
本配方位于 recipes/DNS/enhancement/,面向 DNS Challenge 4 的Real Time Non-Personalized DNS赛道(实时非个性化语音降噪)。其核心思路与主流语音增强范式一致:利用 SepFormer 的注意力建模能力,在时域上对带噪语音进行编码、掩码估计与解码重建,从而抑制噪声、保留语音。
从文件结构看,该配方由四部分构成:
- train.py:定义
Enhancement(sb.Brain)训练/评估主逻辑; - hparams/sepformer-dns-16k.yaml:全部超参数(模型结构、优化器、增强策略、数据路径等);
- dnsmos_local.py:本地 DNSMOS 评分脚本(语音质量 SIG、背景噪声质量 BAK、总体质量 OVRL);
- composite_eval.py:CSIG / CBAK / COVL 复合客观指标计算脚本。
数据下载与准备脚本则位于上一级 recipes/DNS/(dns_download.py、create_wds_shards.py、noisyspeech_synthesizer/等)。
二、环境准备与依赖安装
在开始之前,需要安装配方所需的额外依赖。recipes/DNS/enhancement/extra_requirements.txt声明的依赖包括:
librosa mir_eval onnxruntime pesq pyroomacoustics>=0.7.3 pystoi tensorboard webdataset安装命令:
pip install -r extra_requirements.txt各依赖在流程中的用途分别是:
- webdataset:读取 WebDataset 格式的分片(shard)数据,是 DNS-4 超大数据集高效 I/O 的关键;
- pesq / pystoi:在验证阶段计算 PESQ 与 STOI 等参考类指标(见 train.py);
- onnxruntime:运行 DNSMOS 的 ONNX 评分模型(见 dnsmos_local.py);
- mir_eval:计算 SDR / SDRi(见 train.py);
- librosa / pyroomacoustics:音频重采样与混响合成辅助;
- tensorboard:训练过程可视化日志。
三、DNS-4 数据集与数据准备三步曲
DNS-4 数据集的体量非常大:解压后datasets_fullband约 892 GB,其中clean_fullband827 GB(含 read/german/french/italian/spanish/russian 等语种子目录)、noise_fullband58 GB、dev_testset1.7 GB、impulse_responses5.9 GB。详细目录结构可查阅 recipes/DNS/README.md。
因此,数据准备分三步进行,且全部以WebDataset 分片(shard)的形式组织,以保证大规模训练时的高吞吐读取。
Step 1:下载数据集并创建 shard
python dns_download.py --compressed_path DNS-dataset --decompressed_path DNS-compressed如需并发下载(利用多线程并行拉取 126 个 split,适合大型集群):
python dns_download.py --compressed_path DNS-dataset --decompressed_path DNS-compressed --parallel_download下载解压后,把 clean 语音、噪声、以及 baseline 开发集分别打包成 shard:
# clean_fullband 分片(每次选择一个语种,如 read_speech / german_speech / french_speech ...) python create_wds_shards.py DNS-dataset/datasets_fullband/clean_fullband/<read_speech/german_speech/...>/ DNS-shards/clean_fullband/ # noise_fullband 分片 python create_wds_shards.py DNS-dataset/datasets_fullband/noise_fullband/ DNS-shards/noise_fullband # baseline dev-set 分片(noisy_testclips) python create_wds_shards.py DNS-dataset/datasets_fullband/dev_testset/noisy_testclips/ DNS-shards/devsets_fullbandStep 2:合成带噪语音并再次分片
训练增强模型需要"干净语音-噪声-带噪语音"三元组。noisyspeech_synthesizer通过向干净语音叠加噪声、卷积房间冲激响应(RIR)来合成训练对:
cd noisyspeech_synthesizer python noisyspeech_synthesizer_singleprocess.py noisyspeech_synthesizer.yaml \ --input_shards_dir ../DNS-shards \ --split_name read_speech \ --synthesized_data_dir synthesized_data_shards # 其余语种(german/italian/spanish/russian/french)同理依次执行Step 3:启动训练
训练入口命令(见 README.md 与 train.py):
cd enhancement python train.py hparams/sepformer-dns-16k.yaml \ --data_folder <path/to/synthesized_shards_data> \ --baseline_noisy_shards_folder <path/to/baseline_dev_shards_data>其中两个命令行参数分别对应 yaml 中的两个!PLACEHOLDER:
--data_folder:Step 2 生成的合成训练/验证分片目录(含train_shards/与valid_shards/);--baseline_noisy_shards_folder:Step 1 生成的 baseline 开发集噪声分片目录(用于训练结束后对官方 testclips 做增强并送 DNSMOS 评估)。
值得注意的是,训练数据分片内部还按语种分子目录,train.py 中的dataio_prep会依次扫描read_speech、german_speech、french_speech、italian_speech、spanish_speech、russian_speech六个目录下的shard-*.tar,再通过braceexpand展开分片通配符并合并为一个 WebDataset;meta_loader则遍历各子目录的meta.json累加样本数,用于计算looped_nominal_epoch(一个 nominal epoch 的迭代步数)。
四、超参数配置详解
sepformer-dns-16k.yaml 是配方的"灵魂",采用 SpeechBrain 的 HyperPyYAML 语法(!ref引用、!new实例化、!PLACEHOLDER占位符、!apply执行函数)。下面按类别逐一解读。
4.1 实验与数据基础参数
seed: 1234 __set_seed: !apply:speechbrain.utils.seed_everything [!ref <seed>] output_folder: !ref results/sepformer-enhancement-16k/<seed> save_folder: !ref <output_folder>/save train_log: !ref <output_folder>/train_log.txt data_folder: !PLACEHOLDER train_data: !ref <data_folder>/train_shards/ valid_data: !ref <data_folder>/valid_shards/ baseline_noisy_shards_folder: !PLACEHOLDER baseline_shards: !ref <baseline_noisy_shards_folder>/shard-{000000..999999}.tar shard_cache_dir:seed必须放在 yaml 顶部,因为后续所有对象的随机初始化都依赖它;- 输出默认写入
results/sepformer-enhancement-16k/1234/; shard_cache_dir留空表示本地读取;如果分片托管在网络上(WebDataset over HTTP),应指向大容量磁盘目录做缓存。
实验侧参数:
use_tensorboard: True tensorboard_logs: !ref <output_folder>/logs/ dereverberate: False precision: fp16 # bf16、fp16 或 fp32 test_only: False num_spks: 1 # 单说话人增强,输出一路估计信号 save_audio: True # 测试阶段把增强结果落盘 sample_rate: 16000 # 16 kHz audio_length: 4 # 每个样本 4 秒 n_audio_to_save: 204.2 训练策略参数
N_epochs: 100 batch_size: 4 batch_size_test: 1 lr: 0.00015 clip_grad_norm: 5 loss_upper_lim: 999999 limit_training_signal_len: False training_signal_len: 32000 ckpt_interval_minutes: 60lr = 1.5e-4,配合梯度裁剪clip_grad_norm = 5;limit_training_signal_len置 False 时训练序列不截断;若开启,cut_signals会随机选取training_signal_len(32000 采样点,即 2 秒 @16 kHz)的子段参与训练(train.py);- 每 60 分钟自动保存一次 checkpoint。
4.3 数据增强参数
use_wavedrop: False use_speedperturb: True use_rand_shift: False min_shift: -8000 max_shift: 8000 speed_changes: [95, 100, 105]启用速度扰动(SpeedPerturb,来自 speechbrain/augment/time_domain.py),以 95%/100%/105% 三档变速;DropFreq与DropChunk用于随机丢弃频带与时间片段,让模型不过度依赖特定频带或片段(use_wavedrop: False时默认不启用):
drop_freq_low: 0 drop_freq_high: 1 drop_freq_count_low: 1 drop_freq_count_high: 3 drop_freq_width: 0.05 drop_chunk_count_low: 1 drop_chunk_count_high: 5 drop_chunk_length_low: 1000 drop_chunk_length_high: 2000对应实现类分别为 DropFreq 与 DropChunk。
4.4 损失阈值化
threshold_byloss: True threshold: -30这是本配方一个值得注意的工程细节:训练时对 batch 内每条样本的 Si-SNR 损失做阈值过滤,只保留损失大于-30(即增强效果尚不理想、仍有学习空间)的样本参与平均反向传播,实现"hard threshold 掉太简单的数据项"。对应逻辑在 train.py:
if self.hparams.threshold_byloss: th = self.hparams.threshold loss_to_keep = loss[loss > th] if loss_to_keep.nelement() > 0: loss = loss_to_keep.mean() else: loss = loss.mean()此外fit_batch还包含非有限损失(NaN/inf)防护:当 loss 超过loss_upper_lim或为空时跳过该 batch 并计数(train.py)。
4.5 优化器与学习率调度
optimizer: !name:torch.optim.Adam lr: !ref <lr> weight_decay: 0 loss: !name:speechbrain.nnet.losses.get_si_snr_with_pitwrapper lr_scheduler: !new:speechbrain.nnet.schedulers.ReduceLROnPlateau factor: 0.5 patience: 2 dont_halve_until_epoch: 85- 损失函数为Si-SNR(尺度不变信噪比),封装在 get_si_snr_with_pitwrapper(PIT 包装器,便于扩展到多说话人场景;本配方
num_spks: 1); - 学习率采用 ReduceLROnPlateau 调度:验证损失停滞时以
factor=0.5减半,patience=2,且85 epoch 之前不降低学习率(dont_halve_until_epoch: 85)。在 train.py 的on_stage_end中,验证阶段会依据stage_loss驱动调度器并更新优化器学习率。
4.6 Checkpoint 与日志
save_all_checkpoints: False checkpointer: !new:speechbrain.utils.checkpoints.Checkpointer checkpoints_dir: !ref <save_folder> recoverables: encoder: !ref <Encoder> decoder: !ref <Decoder> masknet: !ref <MaskNet> counter: !ref <epoch_counter> lr_scheduler: !ref <lr_scheduler> train_logger: !new:speechbrain.utils.train_logger.FileTrainLogger save_file: !ref <train_log>save_all_checkpoints: False时,checkpointer 按验证 PESQ 保存/保留最优模型(save_and_keep_only(meta={"pesq": ...}, max_keys=["pesq"]),见 train.py)。yaml 末尾还提供了通过speechbrain.utils.parameter_transfer.Pretrainer微调预训练模型的模板(注释状态,取消注释并填入三个!PLACEHOLDER即可)。
五、SepFormer 网络结构(源码级解读)
本配方的掩码网络基于 SpeechBrain 的dual_path模块族(speechbrain/lobes/models/dual_path.py),整体为编码器-掩码网络-解码器三段式结构。
5.1 Encoder 与 Decoder
N_encoder_out: 256 out_channels: 256 kernel_size: 16 kernel_stride: 8 Encoder: !new:speechbrain.lobes.models.dual_path.Encoder kernel_size: !ref <kernel_size> out_channels: !ref <N_encoder_out> Decoder: !new:speechbrain.lobes.models.dual_path.Decoder in_channels: !ref <N_encoder_out> out_channels: 1 kernel_size: !ref <kernel_size> stride: !ref <kernel_stride> bias: FalseEncoder 本质是一个Conv1d(kernel_size=16, stride=8)+ ReLU:将 1 维时域波形编码为 256 维特征序列;Decoder 则是ConvTranspose1d,把掩码后的特征重建为单通道波形。
5.2 双路径 Transformer 掩码网络
SBtfintra: !new:speechbrain.lobes.models.dual_path.SBTransformerBlock num_layers: 8 d_model: !ref <out_channels> nhead: 8 d_ffn: 1024 dropout: 0 use_positional_encoding: True norm_before: True SBtfinter: !new:speechbrain.lobes.models.dual_path.SBTransformerBlock num_layers: 8 d_model: !ref <out_channels> nhead: 8 d_ffn: 1024 dropout: 0 use_positional_encoding: True norm_before: True MaskNet: !new:speechbrain.lobes.models.dual_path.Dual_Path_Model num_spks: !ref <num_spks> in_channels: !ref <N_encoder_out> out_channels: !ref <out_channels> num_layers: 2 K: 250 intra_model: !ref <SBtfintra> inter_model: !ref <SBtfinter> norm: ln linear_layer_after_inter_intra: False skip_around_intra: TrueDual_Path_Model 是 Dual-Path RNN / SepFormer / DPTNet 系列模型的公共底座。它以块长 K=250将编码特征切成块,随后由 2 个Dual_Computation_Block交替执行:
- intra 路径:8 层
SBTransformerBlock在块内(时间维度)建模局部依赖; - inter 路径:8 层
SBTransformerBlock跨块(块间维度)建模全局依赖;
配合norm: ln(LayerNorm)、skip_around_intra(intra 残差)、linear_layer_after_inter_intra: False,最终经 1×1 卷积与 gated 输出层(Tanh×Sigmoid)生成掩码,与编码特征逐元素相乘后送入 Decoder 重建波形。
5.3 前向与损失计算
compute_forward 展示了完整的推理链路:训练阶段先做速度扰动与噪声叠加,然后Encoder -> masknet -> Decoder,并对卷积带来的时序长度变化做 pad/截断对齐;compute_objectives 则将估计波形与干净波形送入 Si-SNR 损失。此外 train.py 保留了频域增强的代码路径(use_freq_domain),默认关闭时走时域路径。
六、评估体系:验证集指标与 DNSMOS
DNS Challenge 官方不提供开发测试集的干净参考音频,因此本配方采用"从训练集随机切出 5% 作为验证集"的策略,在验证集上计算 Si-SNR / PESQ / SDR / STOI / CSIG / CBAK / COVL 等参考类指标;而对 baseline 官方 testclips(只有带噪语音),则使用DNSMOS这一无参考指标做主观质量近似评估。
6.1 验证集客观指标
在 on_stage_end 中,验证阶段会汇总平均 Si-SNR 与平均 PESQ;save_results 则对验证集逐条计算 SDR、SDRi、Si-SNR、Si-SNRi、PESQ、STOI、CSIG、CBAK、COVL 并写入valid_results.csv(同时打印各指标均值)。其中复合指标由 composite_eval.py 基于 WSS、LLR、SNR、PESQ 的回归公式计算。
6.2 DNSMOS 无参考评估
DNSMOS 的本地实现位于 dnsmos_local.py,其工作原理是:将音频重采样到 16 kHz、按 9.01 秒窗口切分(不足则循环拼接),逐段送入 ONNX 模型(DNSMOS/sig_bak_ovr.onnx,非个性化模式)得到 SIG/BAK/OVRL 原始分数,再经多项式拟合得到最终 MOS 分数(dnsmos_local.py)。
前置条件:先从官方仓库下载评估模型,解压后放在DNSMOS目录下(sig_bak_ovr.onnx)。然后对增强结果与原始带噪语音分别评分:
# 对 SepFormer 增强后的 baseline testclips 评分 python dnsmos_local.py -t results/sepformer-enhancement-16k/1234/save/baseline_audio_results/enhanced_testclips/ -o dnsmos_enhance.csv # 对原始带噪 testclips 评分(基线参考) python dnsmos_local.py -t <path-to/datasets_fullband/dev_testset/noisy_testclips/> -o dnsmos_noisy.csv-t指定待评音频目录,-o指定结果 CSV 输出路径;最终在终端打印 SIG / BAK / OVRL 均值。
6.3 官方报告的参考结果
以下为本配方文档公开报告的复现结果(供横向参考,实际结果随数据与训练条件波动):
验证集指标(16 kHz):
| 采样率 | Valid Si-SNR | Valid PESQ |
|---|---|---|
| 16k | -10.6 | 2.06 |
预训练权重与完整模型可从 SpeechBrain 官方 HuggingFace 组织仓库(
speechbrain/sepformer-dns4-16k-enhancement)及官方备份链接获取。
DNS4 2022 baseline 开发集 DNSMOS:
| 模型 | SIG | BAK | OVRL |
|---|---|---|---|
| Noisy | 2.984 | 2.560 | 2.205 |
| Baseline: NSNet2 | 3.014 | 3.942 | 2.712 |
| SepFormer | 2.999 | 3.076 | 2.437 |
七、计算资源与训练成本(重要提示)
DNS-4 增强训练对算力的要求极高,文档明确给出了官方实验的资源清单:
- 训练数据规模约1300 小时的 clean-noisy 配对音频;
- 硬件配置:8 × NVIDIA RTX A6000 48GB,采用多 GPU 分布式数据并行(DDP)训练;
- 完成45 个 epoch耗时约17 天,平均每个 epoch 约9.25 小时;
- 官方建议:训练至少 90–100 个 epoch 可获得更优性能(yaml 中
N_epochs: 100即与此对应)。
因此,在启动训练前务必评估 GPU 资源与时间预算;也可以利用 yaml 中注释的pretrained_enhancement配置加载官方预训练模型进行微调,以大幅缩短训练周期。
八、注意事项与最佳实践小结
- 磁盘空间:下载压缩包约需 550 GB,解压后约 1 TB,加上合成 shard 还需额外空间;建议按 recipes/DNS/README.md 中的目录结构规划存储。
- 语种 shard 的组织:
dataio_prep会按语种子目录合并 shard,若某语种目录不存在会自动跳过,保证训练不因个别语种缺失而中断。 - 训练卡顿排查:
use_tensorboard: True时可通过 TensorBoard 观察训练/验证 Si-SNR 与 PESQ 曲线;学习率在 85 epoch 前不会下降,前期曲线"平坦"属预期行为。 - PESQ 模式选择:代码根据
sample_rate == 16000自动选择宽带(wb)或窄带(nb)PESQ 模式(train.py),16 kHz 下为 wb 模式。 - 增强音频落盘:训练结束后脚本会自动对 baseline 官方 testclips 执行增强,输出到
save_folder/baseline_audio_results/enhanced_testclips/,供 DNSMOS 与主观试听使用(train.py)。
九、相关引用
若在科研或商业项目中使用本配方,请按惯例引用 SpeechBrain、SepFormer 与 DNS-4 数据集(完整 BibTeX 见 README.md 与 recipes/DNS/README.md):
- SpeechBrain 1.0:
Ravanelli et al., "Open-Source Conversational AI with SpeechBrain 1.0", arXiv:2407.00463; - SepFormer:
Subakan et al., "Attention is All You Need in Speech Separation", ICASSP 2021; - DNS-4:
Dubey et al., "ICASSP 2022 Deep Noise Suppression Challenge", ICASSP 2022。
结语
通过本文,你已完整掌握 SpeechBrain 中 DNS-4 语音增强配方的全链路:从超大数据集的 shard 化组织、SepFormer 双路径 Transformer 的时域掩码增强原理、到损失阈值化与 ReduceLROnPlateau 等训练工程细节,再到 PESQ/Si-SNR 与 DNSMOS 双轨评估体系。下一步可以直接基于 sepformer-dns-16k.yaml 启动训练,或结合官方预训练模型进行微调,将这套增强系统快速落地到你的实际场景中。
【免费下载链接】speechbrainA PyTorch-based Speech Toolkit项目地址: https://gitcode.com/GitHub_Trending/sp/speechbrain
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考