Whisper:一个模型把多语言语音识别管线收进一张 token 序列
posts posts 2026-04-06T22:50:00+08:00实测约 10.9 万 Stars 的 OpenAI Whisper,讲清它如何用一个 seq2seq 模型同时做语音识别、语音翻译和语言识别,以及 6 档模型、faster-whisper 等落地选择。技术笔记Whisper, 语音识别, OpenAI, ASR, 多语言, Transformer, Python一句话判断
Whisper 真正改变的不是"把语音转成文字"这件事本身——语音识别模型一直存在。它把传统识别管线里分属不同环节的活——检测有没有人说话、识别是哪一种语言、把语音转成文字、再把外语翻成英语——全部收进同一个序列到序列(sequence-to-sequence)模型,用一组特殊 token 把它们当成同一类解码问题处理。一段音频进去,decoder 输出哪一类结果,取决于它先吐出的那一个任务 token。
项目坐标
数据来自 GitHub API(2026-09-13 验证):
| 指标 | 值 |
|---|---|
| GitHub Stars | 108,953(约 10.9 万) |
| GitHub Forks | 13,205 |
| 许可证 | MIT |
| 语言 | Python |
| 默认分支 | main |
| 创建时间 | 2022-09-16 |
| 最近推送 | 2026-08-31 |
官方仓库仍在维护(2026 年 8 月还有推送),但最后一个正式版本停在 v20250625,功能增量有限;生态上的活跃更多发生在第三方实现(faster-whisper、whisper.cpp 等)一侧。
系统总览
一段音频在 Whisper 里大致走这条链路:
核心在最后一步:decoder 不是一次性吐出文本,而是先输出 <|startoftranscript|>、<|zh|>、<|transcribe|> 这类特殊 token,用它们决定接下来按什么任务、什么语言、要不要时间戳来生成。
它把什么拆平了:传统管线和单模型的分界
传统语音识别是一条多阶段链路:先做语音活动检测(voice activity detection,VAD)判断哪里有人声,再靠音素识别、发音词典、语言模型把声学特征拼成词,最后用单独的翻译模型处理跨语言。每一段都要单独训练、单独调参,误差会沿着链路累积。
Whisper 把这套东西拆掉,换成两步:把音频切成 30 秒的窗口,转成 log-Mel 频谱喂进 Transformer encoder,再由 decoder 按任务 token 直接生成结果。识别、翻译、语言分类共享同一组参数,模型在 68 万小时弱监督音频上训练,用数据量抵消掉对显式词典和发音规则的依赖。代价是推理成本高——每 30 秒窗口都要完整跑一遍解码,而不是复用上一帧的中间结果。
核心机制
1. 多任务用一组特殊 token 表示
Whisper 不用不同的模型头去分任务,而是把任务本身编码进 token 序列。decoder 生成序列的开头固定是:
<|startoftranscript|> <|语言|> <|任务|> <|要不要时间戳|> 正文...<|语言|> 决定按哪种语言解码,<|任务|> 在 <|transcribe|>(转写)和 <|translate|>(翻成英语)之间选,时间戳 token 决定是否输出逐段起止时间。这套约定让"换任务"变成"换一个 token",模型结构因此可以保持单一。
2. 30 秒滑动窗口 + 自回归解码
transcribe() 内部把整段音频按 30 秒窗口滑动处理,每个窗口独立做一次自回归 seq2seq 解码。窗口之间靠 condition_on_previous_text 决定是否沿用前一个窗口的文本作为上下文,让长音频的转写更连贯;代价是:如果前文有一处错,可能顺着带偏后面,所以官方把它做成可开关的选项。
3. 六档模型
README 的模型表共 6 档,其中 4 档带 .en 英文专用版:
| 规模 | 参数量 | 英文专用版 | 多语言版 | 所需显存 | 相对速度 |
|---|---|---|---|---|---|
| tiny | 39 M | tiny.en | tiny | ~1 GB | ~10x |
| base | 74 M | base.en | base | ~1 GB | ~7x |
| small | 244 M | small.en | small | ~2 GB | ~4x |
| medium | 769 M | medium.en | medium | ~5 GB | ~2x |
| large | 1550 M | 无 | large | ~10 GB | 1x |
| turbo | 809 M | 无 | turbo | ~6 GB | ~8x |
相对速度以 large 为基准,是 README 在 A100 上转录英文语音的实测口径,实际受语言、语速和硬件影响很大。.en 系列只做英文,在 tiny.en、base.en 上比多语言版效果更好,到 small.en、medium.en 差距就明显缩小。
4. turbo:剪出来的第六档,也是 CLI 默认模型
2024 年 9 月发布的 large-v3-turbo(简称 turbo)不是重新训练的模型,而是把 large-v3 的解码器从 32 层剪到 4 层、编码器不动,再用同一批转录数据微调出来的版本,参数从 1550 M 降到约 809 M。配合 F.scaled_dot_product_attention,在 A100 上转录速度约为 large 的 8 倍,显存需求降到约 6 GB。代价写在明处:微调时排除了翻译数据,官方发布帖明确不期待它做好翻译——CLI 里即便指定 --task translate,它也倾向返回原语言,README 让翻译场景改用 medium 或 large;同一帖还承认它在泰语、粤语等少数语言上的错误率比 large 明显上升。
turbo 从 20240930 版本起进了 openai-whisper 的 load_model 支持列表,whisper.load_model("turbo") 可以直接加载,不必绕道 faster-whisper 或 transformers。CLI 的默认模型也从这一版开始从 small 换成 turbo——不带 --model 直接跑 whisper audio.wav,用的就是它。
一次转写流过系统
拿一段中文播客音频举例。whisper.load_model("medium") 后调用 model.transcribe("podcast.mp3", language="zh"):
load_audio用 ffmpeg 转成 16kHz 单声道 float32。- 音频按 30 秒窗口切分,每段补零对齐。
- 每段转成 80 个频带的 log-Mel 频谱,进 encoder。
- decoder 先输出
<|startoftranscript|> <|zh|> <|transcribe|>,再逐 token 生成中文文本。 - 结果按窗口合并,
result["text"]是全文,result["segments"]是带起止时间戳和置信度的分段。
如果要的是英文翻译,把任务 token 换成 <|translate|>(即 --task translate),decoder 输出就从中文文字变成英文译文。
这些准确率数字怎么读
Whisper 论文在 Common Voice、Fleurs、LibriSpeech 等基准上报告了 WER(词错误率)和 CER(字错误率)。怎么读这些数字:
- 测的是什么:在标准公开数据集上,把模型输出和人工转写逐词比对算出的错误比例。它衡量的是"这段音频转得准不准"。
- 数字反映系统的哪部分:主要反映 encoder 对声学特征的提取质量和 decoder 对语言规律的把握。语言之间的差异往往大于模型规模之间的差异——英文这类高资源语言错误率低很多,低资源语言会明显偏高。
- 不能推出什么:不能推出在具体生产音频上的表现——噪声、口音、专业术语、领域方言都会让 WER 上涨;也不能推出推理延迟或某块特定硬件上的速度,那些要看实现和硬件。
怎么用起来
安装依赖 ffmpeg,然后任选 pip 包或源码安装:
pip install -U openai-whisper # 或 pip install git+https://github.com/openai/whisper.git命令行最简用法(不带 --model 时默认 turbo,这是 20240930 版本起的默认值):
whisper audio.wav --model medium # 转写
whisper japanese.wav --language Japanese # 指定非英语语言
whisper japanese.wav --language Japanese --task translate # 翻成英语
whisper audio.wav --model medium --output_format srt # 出字幕Python 里先加载模型再转写:
import whisper
model = whisper.load_model("base")
result = model.transcribe("audio.mp3")
print(result["text"])只有 30 秒以内的音频,或想直接拿语言和文本,可以用底层的 decode:
import whisper
model = whisper.load_model("base")
audio = whisper.load_audio("audio.mp3")
audio = whisper.pad_or_trim(audio)
mel = whisper.log_mel_spectrogram(audio).to(model.device)
_, probs = model.detect_language(mel)
print(f"语言: {max(probs, key=probs.get)}")
options = whisper.DecodingOptions()
result = whisper.decode(model, mel, options)
print(result.text)decode 不做窗口滑动,只处理传入的 30 秒以内的音频,适合需要精细控制解码参数的场景。
生态与选型
Whisper 的模型权重被多个实现复用,选哪个取决于落地约束:
| 实现 | 定位 | 适合 |
|---|---|---|
| openai-whisper | 官方参考实现 | 基准测试、原型、依赖官方接口的场景 |
| faster-whisper | 用 CTranslate2 推理引擎重写,支持量化,速度和显存占用都占优 | 生产转写、GPU/多核 CPU 高吞吐 |
| whisper.cpp | C/C++,CPU 友好 | 离线、嵌入式、无 Python 环境 |
| transformers | Hugging Face 生态 | 需要微调,或要接入 Hugging Face 工具链 |
| WhisperX | 在 Whisper 输出上叠加 wav2vec2 强制对齐,把词钉到精确时间 | 需要词级精确时间戳 |
微调一般走 transformers:加载 openai/whisper-small,配一个标好语言和文本的音频数据集(重采样到 16kHz),用 --language zh --num_train_epochs 3 这类参数训练。数据量没有硬性门槛,但目标语言或领域的样本越多、越干净,效果越好。
什么时候值得用
- 先上:需要多语言识别或离线转写,先用默认的 turbo——速度约为 large 的 8 倍,精度只轻微下降,显存只要约 6 GB,多数场景的最省心起点。跨语言翻译要用 large-v3 或 medium;对单语言精度要求极致再上 large。
- 可以等:对词的精细时间戳强要求时,先评估 WhisperX;纯英文、CPU 受限、要极致吞吐时,直接看 faster-whisper 或 whisper.cpp,别从官方实现起步。
- 别指望:拿某个基准的 WER 直接当生产预期,也别忘了官方实现推理偏重,长音频和实时场景要单独做性能测试。
常见问题
whisper.load_model("turbo") 报 Model not found?
大概率是装的 openai-whisper 早于 20240930,那时 turbo 还没进支持列表。升级到最新版即可;whisper.available_models() 能列出当前包支持的全部模型名。
转写出现重复内容,或静音段也出了文字?
seq2seq 模型对低置信度片段容易复读或产生幻觉。官方对策是温度回退:首轮用温度 0 的贪心解码,失败后按 0.2、0.4……逐级升温重试,并用 no_speech_threshold 判定"这段没人说话"。hallucination_silence_threshold 可进一步滤掉静音段附近的幻觉输出。
长音频中途某段明显跑偏?
检查 condition_on_previous_text 是否开着。它沿用前一个窗口的文本作上下文,能提升连贯性,但一处错可能顺着带偏后面;CLI 用 --condition_on_previous_text False 可以关掉。
转写慢、显存紧?
纯英文场景优先选 tiny.en/base.en,同规格下英文错误率更低;还嫌慢,直接换 faster-whisper 或 whisper.cpp,别在官方实现上死磕参数。
结尾
Whisper 的开源价值,是证明了一条更省时的路径:模型不依赖显式的词典、发音规则和分阶段管线,靠足够大的弱监督数据,就把识别、翻译、语言分类并进同一个 seq2seq 模型。它今天的实用形态也不局限于这个仓库——权重散落在 faster-whisper、whisper.cpp、transformers 这些实现里,选型时先分清"模型的条目"和"跑模型的实现"是两回事。
官方资源
- GitHub:https://github.com/openai/whisper
- 论文:https://arxiv.org/abs/2212.04356
- Model Card:https://github.com/openai/whisper/blob/main/model-card.md
- turbo 发布讨论帖:https://github.com/openai/whisper/discussions/2363
- Colab 示例:https://colab.research.google.com/github/openai/whisper/blob/master/notebooks/LibriSpeech.ipynb
参与讨论
使用 GitHub 登录。欢迎补充事实、异议与实践。
讨论暂时无法加载。