如何用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
相关产品推荐
相关产品推荐

