频率并非重要性:一个未能通过检验的排序维度
我们按语料库频率对领域词汇进行排名,结果排名前 20 的词却都是通用词。一个预先计划的数据门控是如何阻止一个糟糕的坐标轴发布的。
我们需要对一个领域词汇进行排序,以便将最重要的术语放入预算紧张的提示中。最显而易见的信号是频率:计算每个术语在可信语料库中出现的次数,按计数排序,然后就完成了。我们构建并进行了测量,结果排名前 20 的术语是“咨询”、“治疗”、“面部”、“预约”,以及另外十六个通用模型早已熟知的词语。没有一个品牌名称进入该列表。我们为推广特色词汇而建立的这个机制,恰恰推广了那些最不需要推广的词汇。
这篇文章是关于为什么频率作为重要性信号会失败,在那次失败之前我们避开的两个陷阱(基于使用情况派生的频率和原始计数),以及真正拯救我们的部分:设计发布流程,使得该机制可以低成本地失败,并在代码和行为变更之间设置了一个分布检查。
背景设定:30 个槽位,数千个候选词
这个排序的使用方是用于语音识别的关键词偏置提示。该提示有严格的 token 预算,实践中大约能容纳 30 个术语。词汇数据库包含数千个已确认的术语。无论我们选择哪种排序函数,它都决定了词汇表中哪 1% 的词可以影响转录;其他所有词就跟不存在一样。
我们现有的排序使用了来源信任层级(手动输入的术语优先于网站挖掘的术语,网站挖掘的术语又优先于机器生成的术语),并以 token 成本作为决胜标准。问题出在分布的中间部分:数千个术语共享同一层级,而在同一层级内,决胜标准偏爱短字符串。在人类词汇中,短字符串往往偏向于通用词。两个字的日常用词浮到了提示的顶部,而整个系统本应转录的品牌名称却排在了截断线以下。
频率看起来是解决方案。重要的术语应该在领域文本中经常出现;而晦涩的噪声则不应该。这种直觉没有错,但它在关键之处有所欠缺。
陷阱一:使用频率会放大你自己的错误
第一个候选语料库是我们自己的使用日志:即用户实际所说话语的转录文本。这是最诱人的语料库,因为它反映了真实的需求。当生成它的流水线正是你要修复的流水线时,它也以一种微妙的方式被污染了。
我们的转录引擎曾将某个品牌名称错误地识别为一个发音相似的竞品术语。在使用语料库中,错误术语每出现十二次,正确术语才出现一次,因为语料库记录的是引擎写下的内容,而不是说话者所说的内容。如果按该语料库进行排名,错误识别就会被提升到偏向性提示中,这使得引擎对错误的术语更加确信,从而进一步抬高其频率。错误助长了自身的增长。
我们从中得出的规则是:绝不要从排名本应纠正的系统的输出中派生排名信号。这种形式的反馈循环不会自我宣告;它们只会悄悄地收敛到故障模式。
陷阱二:原始计数奖励重复,而非共识
第二个候选方案是来自可信领域网站的抓取频率,这绕开了反馈循环,因为文本从未经过识别引擎。但原始出现次数有其自身的偏见:一个在每个页面(导航栏、页脚、推广横幅)上都重复某个术语的网站,其票数会超过十个各自只提及一次不同且真正重要的术语的网站。
我们将统计数据从原始计数切换为源级别的文档频率:即这个术语究竟在多少个不同的网站中出现?一个在七个独立诊所中都出现的术语是整个领域的共识;而一个在某个诊所网站上出现 400 次的术语则是该诊所的营销内容。我们还将坐标轴的上限设为一个较小的值,以便它能在不同信任层级之间打破平局,而又不会压倒它们。
这是对错误想法的正确改进。它修复了操纵和偏差问题,但仍然无法解决核心问题。
衡量指标:通用词汇终究胜出
在构建并测试了计数、去重和来源归属功能后,我们在 28 个网站上运行了计数器,并在将该维度接入实时排名之前查看了分布的顶端部分。按文档频率排名的前 20 位是:
咨询、疗程、面部、轮廓、治疗、预约、疼痛、炎症、额头、组织、体形、胸部、弹性、脂肪、提拉、填充物,以及一些类似性质的词语。其中每一个词都是任何语音模型开箱即用就能正确转写的词。没有任何品牌名称。
事后看来,这个结果是显而易见的。文档频率衡量的是跨来源的一致性,而独立来源之间最一致的内容是普通语言。每家诊所都会写“咨询”和“预约”;只有部分诊所会提供特定的设备或产品。在专业语料库中,出现范围的广度与分布顶端的通用性相关。我们想要的特色词汇位于中间地带:出现在多个来源中,但又不存在于两个极端。
频率,无论以何种形式,回答的都是“这个词有多常见?”而重要性,对我们的目的而言,回答的是“模型在多大程度上需要这个词的帮助?”这两个问题近乎相反。模型需要帮助的词,恰恰是在通用文本中代表性不足的那些词。
行之有效的部分:代码与行为之间的一道关卡
这就是避免其成为一个代价高昂的错误的原因。在规划评审期间,一位评审员指出了这个确切的风险:抓取频率可能与通用性相关,从而助长垃圾内容而不是抑制它。我们无法通过争论解决这个问题,因此我们围绕一项度量重新设计了发布方案:
- 该轴的实现带有一个不变量,并通过单元测试进行了验证:如果每个词项的频率都为零,则排名与旧排名逐字节完全相同。空数据意味着该轴不存在。
- 频率表由一个单独的批处理步骤填充,该步骤被刻意地未在预定流水线中启用。
- 在填充和采用之间设立了一道书面关卡:检查分布的前 20 位。如果主要由独特的领域词项主导,则采用该轴。如果主要由通用词主导,则截断该表并跳过采用。
这道关卡失败了,而失败的代价很低。我们截断了表,让轴代码在其零数据不变量的保护下处于休眠状态,并发布了我们预先指定的后备方案:将度量发现的通用词添加到停用词列表中,从而将这些词项完全从提示中排除。这项度量没有白费;它产出了我们所能期望的最好的停用词候选,这些候选有数据支持,而非凭直觉。
通用模式是:当一个排名信号看似合理但未经证实之时,分别交付其机制和数据,在它们之间设置一个分布检查,并预先确定“失败”是什么样子以及后备方案是什么。另一种方案,即直接将该轴接入生产环境,并通过观察质量指标的漂移来评估它,会耗费数周时间并侵蚀对整个系统的信任。
我们可以用什么来代替词频
这次门禁事件给我们留下了一个更尖锐的问题:如果不是词频,那什么能预测“模型需要在这个术语上得到帮助”?在事后讨论中,有三个信号留存了下来:
- 分词器碎片化。模型的 tokenizer 会粉碎成许多片段的术语,是模型很少见过的术语。这仅凭词汇表就可以离线计算,完全不需要语料库,并且在我们早期的测量中,它能清晰地将品牌名称与日常词汇区分开来。
- 观察到的混淆。一个从生产事故中收集的实际错误识别词典,指出了需要增强的确切术语。它虽然很小,但每个条目都是事实真相。
- 中频段文档频率。如果非要使用频率,那么有用的频段是中间部分:即出现在少数几个独立来源中但并非所有来源都出现的术语。频率分布的顶端是通用词汇;底端是噪音。
这些方法没有一个像计数那样简单。而这恰恰是重点所在。
发布语料库衍生排序信号的核对清单
- 切勿根据你试图纠正的系统所产生的语料库进行排序;闭环会放大自身的错误。
- 跨独立来源的文档频率优于原始计数,并为该轴设置上限,以免其压倒更强的信号。
- 在采用前,请查看分布的实际顶部,而不是指标的描述。在查看之前决定通过标准。
- 实现该轴时使用零数据不变量,以便“无数据”可证明地等同于“旧行为”,并将数据填充和采用作为独立的开关。
- 预先确定一个后备方案。我们的方案是数据驱动的停用词扩展,它将一个失败的轴变成了一个有用的产物。
- 记住频率衡量的是什么。普遍性和重要性指向不同的方向,而这正是在你的词汇变得专业化的时候,也是你唯一需要排序的时候。
该轴仍在代码库中,处于休眠状态。如果我们能找到一个通过该关卡的信号,那么只需一个批处理作业即可采用。在此之前,这个关卡完成了它的工作:它让一个看似合理的想法在电子表格中失败,而不是在生产环境中。