如何正确使用 librosa.resample 进行音频重采样(16kHz)

librosa 0.10+ 版本中 `librosa.resample` 已改为仅支持关键字参数(keyword-only),必须显式传入 `orig_sr` 和 `target_sr`,否则会报错“takes 1 positional argument but 3 were given”。本文详解正确调用方式、多通道处理技巧及实用注意事项。

在使用 wav2vec2 等预训练模型进行语音微调时,确保所有音频统一为 16 kHz 采样率 是关键前提。而从 torchaudio.load() 加载的音频往往原始采样率各异(如 44.1 kHz、48 kHz 或 8 kHz),需通过重采样对齐。许多用户在迁移到较新版本的 librosa(≥0.10.0)后,因沿用旧版位置参数写法(如 librosa.resample(y, sr, 16000))触发如下错误:

TypeError: resample() takes 1 positional argument but 3 were given

这是因为新版 librosa.resample 显式要求所有参数(除音频数组 y 外)必须以命名参数形式传入,其函数签名如下:

def resample(
    y: np.ndarray,
    *,
    orig_sr: float,
    target_sr: float,
    res_type: str = "soxr_hq",
    fix: bool = True,
    scale: bool = False,
    axis: int = -1,
    **kwargs
) -> np.ndarray:

其中 * 表示其后所有参数均为 keyword-only —— 这是导致错误的根本原因。

✅ 正确用法(适配 mono 与 stereo):

import librosa
import numpy as np

# 假设 database['audio'] 是 list of 1D/2D numpy arrays,database['psr'] 是对应原始采样率列表
new_audios = []
new_sr = []

for i, (audio_signal, original_sr) in enumerate(zip(database['audio'], database['psr'])):
    audio_signal = np.asarray(audio_signal)

    # 处理单通道(mono)
    if audio_signal.ndim == 1:
        resampled = librosa.resample(
            y=audio_signal,
            orig_sr=original_sr,
            target_sr=16000
        )

    # 处理多通道(stereo 或更多),逐通道重采样并保持形状
    elif audio_signal.ndim == 2:
        resampled_channels = []
        for ch in audio_signal:
            ch_resampled = librosa.resample(
                y=ch,
                orig_sr=original_sr,
                target_sr=16000
            )
            resampled_channels.append(ch_resampled)
        resampled = np.stack(resampled_channels, axis=0)

    else:
        raise ValueError(f"Unsupported audio dimensionality: {audio_signal.ndim} at index {i}")

    new_audios.append(resampled)
    new_sr.append(16000)

# 更新数据字典
database['audio'] = new_audios
database['newsr'] = new_sr

⚠️ 注意事项与最佳实践:

  • 不要混用 torchaudio 与 librosa 的重采样逻辑:torchaudio.transforms.Resample 更高效且原生支持 Tensor,若全程使用 PyTorch 生态,推荐优先采用:

    from torchaudio.transforms import Resample
    resampler = Resample(orig_freq=original_sr, new_freq=16000)
    resampled_tensor = resampler(speech_array)  # speech_array: torch.Tensor, shape [C, T]
  • 避免 librosa.resample 对长音频的内存峰值:该函数内部会将信号上采样至 LCM 频率,对超长语音(>30s)可能引发 OOM。此时建议分段处理或改用 scipy.signal.resample_poly(需手动设计抗混叠滤波器)。

  • res_type="soxr_hq" 是默认高质量选项,但依赖 soxr 库(需 pip install pysoundfile 或 conda install -c conda-forge soxr)。若环境受限,可降级为 "kaiser_best" 或 "polyphase",精度略低但无额外依赖。

  • 始终验证重采样结果:检查输出长度是否合理(近似按 len_in * 16000 / orig_sr 缩放),并用 librosa.get_duration(y=resampled, sr=16000) 校验时长一致性。

总结:librosa.resample 的关键字参数强制策略提升了 API 可读性与健壮性。只需将 librosa.resample(y, sr, 16000) 统一替换为 librosa.resample(y, orig_sr=sr, target_sr=16000),即可彻底解决报错,并为 wav2vec2 微调构建稳定、合规的 16 kHz 音频流水线。