本地 AI 语音转写长音频时,常会出现后半段反复重复、专有名词大面积错误或边界吞词等幻觉问题。单纯依赖模型参数难以根治,核心在于将长文件视为流程而非单一请求。通过将音频切分为 20 分钟小段并设置 10 秒重叠区,配合单声道 16kHz 预处理,可有效实现中断续跑并保障边界完整。在内存与精度之间如何取舍?面对不同硬件,如何通过短样本抽查快速判定转写方案的可行性?
— 此摘要由AI分析文章内容生成,仅供参考。
一段两小时的访谈、课程或会议,直接整段丢给本地语音识别,经常不是“慢慢出字”,而是后半段开始反复同一句话,专有名词整片错掉,或者正好在切段边界吞掉半句。与其把整文件重跑一遍赌运气,不如先切成可续跑的小段,转写后按重叠区合并,再用一份很短的抽查清单判断这台机器、这个模型值不值得接着跑完全程。

整文件直接转写,通常坏在哪
不少以 Whisper 为代表的语音识别模型,单次看得住的音频窗口大约只有 30 秒。长音频本来就得靠外层循环一段段送进去。封装如果只是“循环”,并不等于长音频策略已经做完:静音一长、后文一弱,模型可能开始重复同一句,而且会连着重复好几分钟。
mlx-whisper-long 针对的就是 Apple Silicon 上 mlx_whisper 的这类问题。项目说明里写得很明确:没有哪一个单独参数能彻底消掉这种幻觉,实际做法是切片、转写、再合并。它把文件切成 20 分钟一段,段与段重叠 10 秒,用来保住边界上的词,中间结果留在磁盘上,中断后可以续跑。
这套数字不是所有模型和所有语言的通用最优解。它只说明一件事:长音频处理要在模型外面再加一层你能复查的流程,而不是把两小时文件当成一个请求。
开工前先固定三件事
先听开头三分钟,记下说话人数、主要语言、噪音来源,以及必须写对的人名、课程名、产品名。这份词表后面比任何“再调一次参数”都有用。多说话人、又要时间戳和说话人标记时,普通转写往往只会给你一大段不分人的文字;MOSS-Transcribe-Diarize 这类模型把转写和说话人分离放在一次输出里,文本形如 [起始秒][S01]话语[结束秒]。它是否适合你的机器和语种,仍要以一小段试跑为准,不要按参数量或语言数量直接下结论。
音频先收成稳定的中间文件。多数本地引擎对单声道、16 kHz、16-bit PCM 最省事:
ffmpeg -i input.mp4 -ac 1 -ar 16000 -c:a pcm_s16le clean.wav
ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 clean.wav
-ac 1 合成单声道,-ar 16000 把采样率收到 16 kHz,pcm_s16le 避免再压一层有损编码。第二行只打印时长,后面的切片起点要用这个秒数,不要凭播放器上的大约值。
Apple Silicon(M1 及更新)上如果走上面那个长音频项目,依赖就是 ffmpeg 和 mlx-whisper。其他平台换成你已经能在短音频上跑通的引擎即可,本文不假设同一模型在所有设备上速度或错误率相同。
切分、转写、合并
下面用“20 分钟一段、重叠 10 秒”作为可复现的起点。先算出每一段的起点,再交给 ffmpeg。两小时就是 7200 秒,你可以换成 ffprobe 得到的真实时长。
duration = 7200
chunk = 20 * 60
overlap = 10
start = 0
index = 0
while start < duration:
length = min(chunk, duration - start)
print(f"{index:03d} {start:.0f} {length:.0f}")
if start + chunk >= duration:
break
start += chunk - overlap
index += 1
打印出来的三列是序号、起点秒、本段时长。对应切分命令是:
mkdir -p parts
ffmpeg -ss 0 -t 1200 -i clean.wav -c copy parts/part_000.wav
ffmpeg -ss 1190 -t 1200 -i clean.wav -c copy parts/part_001.wav
-ss 是起点,-t 是本段长度。第二段从 1190 秒开始,是因为上一段在 1200 秒结束,倒退 10 秒就是重叠。不要用无重叠的 segment 一刀切完就以为边界安全:词正好骑在切点上时,两段都可能丢掉它。
每一段单独转写,文件名保持序号,日志和文本都留在磁盘。某一段失败就只重跑那一段。合并时按起点排序,而不是按文件修改时间。重叠的那 10 秒里,删掉完全相同的重复句;如果两段文字不一样,留更靠近该段中部的那一版,边角上的半句优先丢掉。合并后的时间戳要能从接近 0 秒覆盖到整段时长,中间不能出现突然回退。
说话人标签如果来自带分离能力的模型,合并时不要把 [S01] 按文件重新编号,否则同一个人会在下一段变成另一个编号。这个编号是否稳定,以该模型自己的说明为准。
分段长度和硬件怎么取舍
分段是在边界工作量和单段稳定性之间做选择,不是越短越准。
| 取舍 | 切得更短 | 切得更长 |
|---|---|---|
| 幻觉和重复句 | 通常更容易停住 | 长静音后更容易空转 |
| 接缝 | 重叠区变多,合并更费事 | 接缝少,但一切错就丢更多上下文 |
| 内存与耗时 | 峰值更低,适合边跑边查 | 单段更吃内存,失败成本更高 |
| 适合的试法 | 先用 5 到 10 分钟看会不会漏词 | 短样本稳定后,再试 15 到 20 分钟 |
20 分钟加 10 秒重叠,只是一条已经有人用来避开长文件重复输出的基线。你的录音如果句间停顿很长,可以把切点挪到静音上,重叠仍然保留。课程里专名很密、语速很快时,先把段长减半,比一上来换更大的模型便宜。
硬件也按同样的办法看,不按型号口号看。只开 CPU 时,往往可以挂一夜跑完,但你要接受远慢于实时。有 GPU 或 Apple Silicon 统一内存时,速度通常更好,模型却受内存上限约束:短样本已经明显卡顿、风扇长转或进程被系统杀掉,就不要把两小时文件排队。先换更小的模型或更短的段。本地 AI 的收益是文件不出机器,不是每一档硬件都能换到同一种识别率。

用抽查决定能不能继续跑
不要先听完全文。按这个顺序看一份合并稿:
- 时间戳是否覆盖整段时长,有没有大段空白或时间回跳。
- 每个重叠区前后各听 15 秒,确认没有整句复制,也没有半句消失。
- 用词表搜索人名、课程名、数字和否定词,只回听对不上的位置。
- 抽开头、一次换话题处、结尾各一分钟,看是不是从某一段开始突然重复。
短样本就可以做门槛测试。拿和正片同样噪音、同样说话人的 10 分钟:如果已经大段重复、专名几乎全错,或者耗时长到你无法接受整文件的倍数,就停在这一步。换段长、换模型或改录音质量,都比把两小时跑完再返工便宜。通过了,再按同一参数处理全片,并保留每段原文,方便只替换出错的那一段。
出错时先对症状,再改参数
重复同一句,优先缩短段长,并避开长静音,而不是把温度或束搜索来回试一遍。项目记录里,长文件上的重复输出并不是靠某一个参数消掉的。
边界缺词,先把重叠从 10 秒加到能盖住一句完整的话,并把切点挪到停顿处。重叠太大则两边都会认出同一句,合并时要按“完全重复才删除”处理,避免把后一句真的复述也删掉。
专名错误通常不是切分问题。模型词表里没有的人名、药名、内部项目名,会稳定地听成近音词。有的引擎支持热词或自定义提示,用法以该项目文档为准;没有这项能力时,词表加查找替换是更可靠的人工校对。不要指望同一套替换规则对另一种口音或另一种语言仍然有效。
内存不足或中途被杀掉,先看是不是某一段特别长,或者模型大于机器能稳定放下的体积。只重跑失败段。时间戳错乱,多半是合并时用了错误顺序,或重叠去重删多了,把中间结果留着比对,比从原始长文件重转更快。
多说话人搅在一起时,不要靠换行和语感硬分。需要“谁在什么时候说了什么”,就换带说话人分离和时间戳的模型,并先用一段三人以上的重叠发言做试跑。普通音频转写做不到这一点,并不代表切分流程失败。
验证通过后再扩展
全片开始前,记下短样本的四项结果:音频时长、转写耗时、重复句有没有、词表里的专名对了多少。这四项比一个笼统的“准确率很高”更能说明本地方案能不能用。全片沿用同一段长、同一重叠和同一模型;只有短样本在接缝或重复句上失败时,才改一项再测,避免同时改段长和模型之后无法判断是哪一项起了作用。
录音本身过载、严重回声或大段重叠发言,本地转写的上限就在录音质量,不在切分脚本。这种材料先降噪或重新拾音,再谈模型和硬件。

评论列表 (1条):
加载更多评论 Loading...