ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

实时识别自定义词库:语音转文字工具的配置与调优指南

实时识别自定义词库:语音转文字工具的配置与调优指南

我做会议记录和视频字幕已经有快五年了,中间换过不少语音转文字工具。这里面最让人头疼的就是那些专业术语,无论什么工具,碰上一堆人名、产品代号、技术名词,识别结果基本就是灾难现场。所以当我看到“实时识别可自定义词库”这个标题的时候,第一反应是——终于有人把这个问题当回事了。这篇文章就把我折腾这类工具的经验整理出来,包括怎么选方案、词库到底怎么整才好用,以及那些文档里不会写的坑。

1. 为什么需要实时识别和自定义词库

1.1 实时识别的真实需求:不是“快”,是“在场”

很多人以为实时识别就是为了省时间,录完音等五分钟出结果能接受,为什么非要听写的同时就往外蹦字?我自己的判断是,实时识别解决的根本不是“快”,而是“在场”。

举个具体的场景。你在采访一位受访者,对方说到一个新名词,你光听音根本不知道是哪几个字。如果是录音后转写,你只能事后回听去猜,或者再联系对方确认。但你在电脑上开着实时转写,边聊边看字幕,当场就能发现对方说的词和屏幕上的字对不上,马上追问一句“是哪个x字?”,问题当场解决。这个价值是离线转写无论如何都给不了的。

会议场景更明显。开着远程会议的时候,实时字幕相当于给整个流程加了一道视觉辅助。作为记录员,你不需要全程绷着神经听写,眼角扫一下字幕就能跟上节奏,精力可以放在观察发言人的语气变化、讨论走向这些更需要判断力的地方。实时识别是给“人在现场”这件事用的。

1.2 自定义词库:解决“听得懂但写不对”的痛点

实时识别有了,但识别准不准才是决策者。通用模型对日常对话的覆盖已经不错了,但一旦进入某个垂直领域,立刻原形毕露。我统计过自己过去一段时间的中文会议录音,医疗、法律、软件技术这几个方向,通用模型的错别字率能到 10% 到 20%,主要就是喷在专有名词上。

举几个我真实遇到过的例子。“C++”被识别成“硒加加”;“分布式系统”写成“分不死系统”;“Vue”被写成“view”;人名几乎没有一次是写对的。这事的本质是,语音识别模型里的语言模型权重主要来自大众语料,专业词汇的出现频率低,即使声学模型收到的音频是正确的,语言模型也会把概率倾向到更常见的同音字组合上。

自定义词库就是在这一步介入的。往引擎里塞一份词表,告诉它“本场景下这些词的出现概率要调高,出现时要优先输出”,让语言模型的部分权重向你的业务场景倾斜。可以说,词库就是把通用模型改造成“行业模型”的杠杆,成本极低,但收益非常直接。

1.3 方案选型:本地引擎与在线API怎么权衡

围绕“电脑端实时识别”这个需求,现在市面上能走的路线大致分两类:本地识别引擎,和在线云识别接口。我两款都用过,说下实际体验上的差异。

本地方案是把你机器上的一块算力利用起来,在本地完成音频解码。最大的好处是彻底离线,录音内容不会离开你的设备。针对一些合规要求严格、不允许外部传输音频内容的场景,基本是唯一选择。缺点是识别精度确实还是比大厂的云服务差一些——毕竟本地模型参数规模摆在那里,另外它对 CPU 和内存的压力不小,用起来笔记本风扇嗷嗷转是常事。

在线云接口的识别效果通常更好,因为模型更大、训练数据更多,还经常有持续迭代。代价就是音频要传出去,隐私层面要想清楚。另外很多云接口虽然流量单价看着不贵,但持续使用之后账单会比想象中跑得快,适合在意精度、对数据外传不敏感的场景。

我的建议是,如果只是个人记记笔记,选本地方案,数据安全,成本可控;如果是公司项目或者涉及客户录音,建议直接把本地引擎的精度和隐私优势列进需求表里。下面讲的词库相关机制,两种方案虽然具体接口不一样,但底层逻辑是通用的。

2. 实时识别与自定义词库的关键机制

2.1 实时识别的技术链路:不是魔法,是流水线

你看屏幕上一个字一个字往外蹦,觉得挺神奇,但实际上实时识别就是一条固定的流水线,每一步都在抢时间。

第一步是音频采集,麦克风把模拟信号转成数字信号。这个环节采样率很关键,我用的主流引擎基本要求 16kHz 16bit 的单声道 PCM 格式,这基本是当前语音识别的默认规格。太低的采样率会丢失高频信息,影响辅音识别,太高的采样率又对传输和解码没有正向帮助,还浪费算力。

第二步是语音活动检测,也就是 VAD。这一步用来区分“有人在说话”和“环境噪声”,让引擎在不该计算的时候保持低功耗,同时避免把停顿当成静音给截断了。VAD 判断失误是实时识别丢字的头号原因,后面我会专门讲。

第三步是分帧加窗。音频被切成大概 20 到 50 毫秒一帧的小块,相邻帧之间加一个重叠窗口,确保信息不丢。然后每一帧会变成一组特征向量,也就是声音的数值化表示。

第四步是流式解码。这是实时识别和离线转写在技术上最本质的区别。离线识别可以等整段音频都到位之后,用双向模型看完整上下文再找最优结果;实时识别只能在这一帧一帧到达的同时,边解码边用“前缀束搜索”的算法,不断维护当前概率最高的若干候选路径。这有点像接力跑,每一棒都必须在行进中完成交接。

最后一步是结果后处理与渲染。引擎每识别出一段稳定的文字,就会把它输出到界面上,同时还在不断回看修正之前的候选结果。你会发现屏幕上偶尔会有字在跳变,就是这个原因——算法拿到了后续音频,觉得前面的判断可能错了,正在改。

2.2 自定义词库的实现方式:一份词表,两种机制

现在来说核心卖点,自定义词库。很多用户以为词库就是“把这些词塞进引擎的词典里,它就能认了”,这个理解对也不对。

词库本质上是通过两种机制影响识别结果的。第一种是前向干预。引擎在真正开始解码之前,会把词表里的词与对应的发音序列注册进去,确保这些词在词典和发音映射里一定是合法的路径,不会因为词表里没有而出不来。这一层解决的是“能不能识别出这个词的发音结构”的问题。

第二种是解码时的加权偏置。词表里的词在解码时会获得一个额外的得分加成,语言模型判断候选路径时,这些路径的权重被手工抬高,自然更容易被选为最终输出。这层解决的才是“在多个同音候选里优先选谁”的问题。

但这里有个容易误解的地方——词库不是万能的。如果某个词的发音和另一个常用词高度相似,而且它在上下文里完全不合理,引擎会在语言模型层面做整体判断,不一定会因为你给它加了分就不顾语法硬往上给你选。理解这一点很重要,它决定了你后面整理词库的方式。

2.3 词库不生效和“尽力而为”的真相

我在早期折腾词库的时候就踩过一个坑:往词库里加了好几百个词,重新运行,结果发现识别结果和没加之前一模一样。后来排查下来才搞清楚,词库的生效不是改一改就行的,有三个常见坑。

第一,很多引擎要求词库在识别引擎初始化之前就加载好,运行中途改了文件是无效的。必须重启一遍引擎,甚至是要确认进程真正被杀掉、重新启动,词库才会加载进去。这个问题在开发文档里写得往往不那么显眼,但实操中十有八九都会栽在这。

第二,一些词库格式支持带权重的条目。比如有的引擎支持在词条后面加一个数字,这个数字越大分词权重越高。但要注意,这个权重不是线性对应“准确率提升多少倍”的,实际效果是一个对数级别的加成分。换句话说,你把某个词的权重从 8 调到 9,感知上的区别可能并不明显,没必要一味追求权重拉满。

第三,词库本身只调节语言模型的候选排序。如果一个词实际是 5 个字的短语,你分配了一个 8 字的错误写法进去,它不会帮你变对。词库是“引导引擎往你希望的方向走”,不是“替你理解语义”。指望词库解决全部识别问题的人,用不了多久就会失望。

3. 从0到1搭建实操:配置、词库整理与调优

3.1 环境准备:麦克风、采样率与识别引擎选择

先别急着装软件,把环境弄对,后面省很多事。

麦克风这块,我强烈不建议用笔记本自带的麦克风直接做实时识别。绝大多数的笔记本麦克风都是为通话设计的,方向性差,环境音很容易混进来。我自己用的是那种夹在衣领上的全指向领夹麦,距离说话人嘴巴近,信噪比能高一大截。条件允许的话,再配一个 USB 声卡,能解决很多主板自带声卡的底噪问题。

确认麦克风没问题以后,在系统声音设置里把默认录音设备设成它,采样率选到 16 位、48000Hz 或者 44100Hz 都行,关键是要能正常采集。真正决定识别精度的采样率转换在识别引擎里完成,它会统一重采样到 16k。系统层面设置太高或太低影响不大,关键是设备本身质量。

识别引擎的选择,如果你是个人学习或者轻度使用,先从一个开源的本地引擎起步,很多支持自定义词库的实现都是参考用户词典的思路做的,改起来方便,也有现成的 Python 和 C++ 接口。如果你是要做生产级工具,再考虑接入商业云服务。我的建议是先从本地入手,把识别链路跑通了,再往上叠加需求。

3.2 词库整理三原则:格式、权重、分类

词库能不能起作用,一半看工具,一半看你整理词表的水平。我总结了三件事,照着做基本上不会有太大偏差。

第一件事是格式。先看引擎文档,确定它要的是什么格式。大部分引擎接受一个纯文本文件,一行一个词。但注意,中文词语如果没有空格分词,有的引擎会默认以整行作为一个词条,你需要保证一行只有一个词或一个短语。缩写、英文原文、中文翻译可以各占一行。

第二件事是权重。如果引擎支持逐词权重,比如每行末尾有一个数字表示权重,那我建议你优先给业务核心术语条目标一个中等偏高的权重,给常见口语词就老老实实放默认档。权重不是越高越好,我试过把所有词全部顶满,结果反而导致一些普通词被压制,识别率整体下降。正确的做法是分档位设计。

第三件事是分类。把词库按主题拆文件,比如“技术术语.txt”“人名地名.txt”“测试环境特有用语.txt”,加载的时候按需选用。别把所有词堆在一个文件里,不然回头想调某个词的权重,要翻几百行,很痛苦。

我现在的词库长这样:

# 技术术语 分布式系统 8 消息队列 7 容灾备份 6 服务网格 7 Kubernetes 8 # 客户特定缩写 某项目代号 9 某系统名 9 # 人名 张某某 8 李某某 8

这只是个示例,具体格式要按你用的引擎来调,但这个分文件、分权重的思路是通用的。

3.3 实测调优:参数调整与效果验证

装好、词库配好以后,真正的活才开始。我一般按下面这套流程跑测试。

先录一段大约 5 分钟的自己说话音频,内容要覆盖日常口语、专业术语和人名。然后分别用“无词库”和“有词库”两个配置跑一遍,把两次的识别结果保存下来,对照原文人工标注一下错字位置。这里有个容易被忽略的细节——评估识别率必须用同一段音频,否则没法定量对比。

第一次跑完,找出所有被识别错的词。如果这个词在词库里已经存在,那大概率是权重不够或发音标注有误;如果这个词根本还没加进词库,那就加进去再跑一轮。如此重复交替,直到达到你满意的准确率为止。

再提一句标点符号。你打开实时识别的时候,会发现连续说话结果里经常没有标点,或者只在段落结束时有句号。这是因为很多实时识别模型默认只输出文字的候选结果,标点是在后处理阶段用模型单独加上的,所以有延迟。如果你的需求是要带标点的完整文稿,建议在识别结果稳定之后再跑一遍标点恢复,而不是盯着屏幕等它实时吐标点。

提示:很多引擎支持在识别结果里带时间戳,实测里非常好用。输出一段带词级时间戳的 JSON,你可以用它来做音视频字幕对齐,省掉反复手动校对时间的功夫。

4. 高频问题与排查技巧

4.1 实时识别一直卡顿或丢字

先排除最简单的可能性:机器负载太高。打开任务管理器看一眼,如果识别引擎进程占用已经接近满负荷,那就说明你的机器跑不动当前的模型配置。本地引擎一般有不同尺寸的模型,换一个小一点的模型能立竿见影。丢字还有一个隐藏原因就是 VAD 把说话开头的气音给截掉了,特别是以“诶”“呃”“那”开头的语句,经常从第一个字开始就被吞。解决办法是调整灵敏度,把它调低一点,让引擎更“宽容”地判定语音开始。

4.2 词库加载了但识别就是不变

这个问题我也反复遇到过。先确认词库文件的编码格式,很多引擎只认 UTF-8,你用系统记事本另存成了带 BOM 的 UTF-8,或者存成了 GBK,加载时会直接失败,而且通常不会有明显的报错信息。接着确认引擎进程是否完全重启过,不是简单刷新界面,而是要杀掉所有相关进程再重新启动。

如果还不行,就检查词条本身。词库里存了一个错字版本,比如“Arthas”写成“阿斯”,那你再怎么努力也得不到对的输出。词库不是替你写对,它只是让你的“错版本”变成候选路径之一,按权重去抢输出。

4.3 同音词和多音字处理

这是中文识别里最折腾的事情。比如“账户”和“账号”在很多地区发音几乎一致,但语义在不同语境完全不同。词库能做的只是让某个写法在候选排序中优先级更高,但它不知道你此刻到底想要哪个。这种情况下,靠上下文人工判断还是最靠谱的。常用做法是给这类词加上权重,然后在重要识别结果上人工过一遍。

多音字的问题属于声学模型层面,词库几乎无能为力。“还”在“还钱”和“还有”里声调不同,靠词表解决不了,只能让引擎根据上下文语言模型来猜。

4.4 识别正确但格式一塌糊涂

实时识别输出的文字格式经常很乱,Common 英文术语的大小写乱七八糟,中文数字混着阿拉伯数字,标点完全没有。这些都是后处理层的事,不用在引擎层面死磕。我的做法是识别完成后走一遍统一的后处理脚本,把特定术语固定为标准写法,把数字格式统一,把标点用模型加一遍。这一步做完,稿子基本就能直接用。

5. 一些后期可以继续扩展的方向

如果你用的引擎有接口,还可以做很多周边功能。比如把实时识别的文本接到你的笔记软件里,开会的时候自动生成结构化摘要;或者把带时间戳的输出切成字幕文件,省去手动打轴的时间。另一个方向是训练一个自己的热词模型,在词库基础上做针对性增强,这比每次手动调权重要稳定得多。选型的时候,多留意一下引擎的接口开放程度,这决定了后面你还能走多远。

根据我自己的经验,词库不是一次性搞定的。每次开完会、录完音,把里面识别错误的词补进词库里,大概积攒一个月,你会明显感觉到识别准确率在往上走。这个积累的过程,才是自定义词库真正的价值所在。工具都摆在那,区别就是你愿不愿意花时间把自己的词库慢慢“养”起来。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进