一次性能踩坑
前段时间在 AnythingLLM 里接 Whisper 做语音转文本,直接把一个 30 秒的音频扔进去,响应等了快两秒。并发一上来,服务就开始抖动,内存也蹭蹭涨。痛定思痛,我决定好好捋一下哪些地方可以优化。
其实问题很典型:模型加载慢、推理处理阻塞、长音频没法并行,再加上请求多了之后没有任何排队控制。下面整理了一套方案,实测效果还不错。
模型别反复加载
Whisper 支持 tiny 到 large 多种尺寸,通常用 base 就够日常转录。关键是要避免每次请求都 whisper.load_model(),那会反复读磁盘、占内存。我用一个单例把模型收起来:
import whisper
class WhisperService:
_instance = None
@classmethod
def get_instance(cls, model_size="base"):
if cls._instance is None:
cls._instance = whisper.load_model(model_size)
return cls._instance
这样一来,模型只加载一次,后续都复用同一个实例,响应延迟稳定不少。
音频预处理
不同来源的音频采样率、声道数可能乱七八糟,统一成 16kHz 单声道能让 Whisper 省去内部转换开销。用 pydub 处理一下:
from pydub import AudioSegment
import numpy as np
def preprocess_audio(audio_path):
audio = AudioSegment.from_file(audio_path)
audio = audio.set_frame_rate(16000).set_channels(1)
return np.array(audio.get_array_of_samples())
用多线程处理批量请求
Whisper 的推理主要是 CPU 密集型,但开启多进程会重复加载模型,内存占用飙升。在单个进程里用线程池反而更轻量,因为 Python 的 GIL 在这里不会成为瓶颈(底层计算释放 GIL 了)。我封装了一个简单的批量转录接口:
from concurrent.futures import ThreadPoolExecutor
class WhisperASR:
def __init__(self, model_size=, max_workers=):
.model = WhisperService.get_instance(model_size)
.pool = ThreadPoolExecutor(max_workers=max_workers)
():
futures = []
path audio_paths:
audio = preprocess_audio(path)
futures.append(.pool.submit(.model.transcribe, audio))
[f.result()[] f futures]

