You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用librosa或torchaudio实现与ffmpeg一致的8K转16K音频重采样?

实现与Whisper的ffmpeg重采样完全一致的方法

要直接将8kHz音频数组重采样为16kHz并和whisper.load_audio的结果完全对齐,核心是复刻Whisper依赖的ffmpeg处理流程——它本质是将音频转成**单声道16位有符号整数(s16le)**格式后重采样,再转换为[-1,1]范围的float32数组。以下是两种可靠方案:

方案一:用ffmpeg直接处理内存音频数据(完全对齐)

这是最准确的方式,完全复刻Whisper的ffmpeg调用逻辑,仅将输入从文件改为内存中的音频字节:

import subprocess
import numpy as np
import torchaudio

# 假设已通过torchaudio获取8kHz单声道音频数组
waveform, sr = torchaudio.load("test.wav")
assert sr == 8000
audio_8k = waveform.squeeze().numpy()  # 转为单声道numpy数组

# 1. 将float32数组转为s16le格式字节(Whisper的ffmpeg输入格式)
audio_8k_s16 = (audio_8k * 32767).astype(np.int16).tobytes()

# 2. 通过管道调用ffmpeg完成重采样
cmd = [
    "ffmpeg",
    "-f", "s16le",    # 输入格式为s16le
    "-ar", "8000",    # 输入采样率
    "-ac", "1",       # 单声道
    "-i", "-",        # 从标准输入读取
    "-f", "s16le",    # 输出格式
    "-ar", "16000",   # 目标采样率
    "-ac", "1",       # 保持单声道
    "-"               # 输出到标准输出
]
process = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
audio_16k_s16, _ = process.communicate(input=audio_8k_s16)

# 3. 将s16le字节转回float32数组(和Whisper输出格式一致)
audio_16k = np.frombuffer(audio_16k_s16, dtype=np.int16).astype(np.float32) / 32768.0

如果习惯用ffmpeg-python库,代码会更简洁:

import ffmpeg
import numpy as np
import torchaudio

waveform, sr = torchaudio.load("test.wav")
assert sr == 8000
audio_8k = waveform.squeeze().numpy()

audio_8k_s16 = (audio_8k * 32767).astype(np.int16).tobytes()
out, _ = (
    ffmpeg.input("pipe:", format="s16le", ac=1, ar=8000)
    .output("pipe:", format="s16le", ac=1, ar=16000)
    .run(input=audio_8k_s16, capture_stdout=True)
)

audio_16k = np.frombuffer(out, np.int16).astype(np.float32) / 32768.0

方案二:用torchaudio模拟ffmpeg的重采样参数

若不想依赖ffmpeg进程,可通过torchaudio配置匹配ffmpeg默认的swresample滤波器参数。ffmpeg默认使用线性插值重采样(8kHz→16kHz属于整数倍上采样,线性插值是默认选择),用torchaudio实现如下:

import torch
import torchaudio

waveform, sr = torchaudio.load("test.wav")
assert sr == 8000

# 使用线性插值重采样,匹配ffmpeg默认逻辑
audio_16k = torchaudio.functional.resample(
    waveform,
    orig_freq=8000,
    new_freq=16000,
    resampling_method=torchaudio.transforms.ResamplingMethod.LINEAR
).squeeze().numpy()

# 注意:torchaudio的线性重采样输出是float32,范围已在[-1,1],无需额外缩放

为什么之前的librosa/torchaudio结果不一致?

Librosa的kaiser_best使用Kaiser窗FIR滤波器,torchaudio默认的重采样方法(如kaiser_window)也和ffmpeg的默认swresample参数不同,导致输出数值差异。而上述两种方案完全对齐Whisper的训练时重采样逻辑,不会影响识别效果。

内容的提问来源于stack exchange,提问作者user3668129

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 03:11:25