虽然标准的束搜索解码器通过保留多个候选转录结果改进了贪婪搜索,但其决策仅基于声学证据。为了生成符合语言学逻辑的输出,我们必须将语言模型的分数直接整合到束搜索过程中。这通过修改在每一步中用于对假设进行排序的评分函数来实现。解码器的目标从找到声学上最可能的路径转变为找到同时最好地满足声学模型和语言模型的路径。束中每个假设的分数使用前面介绍的组合公式进行更新:要生成语言连贯的输出,需要将语言模型的分数直接整合到束搜索过程中。这通过修改用于在每一步中评估假设的评分函数来实现。修改后的评分函数如下: $$ \text{分数}(W) = \text{声学分数} + \alpha \cdot \text{语言模型分数} + \beta \cdot \text{词数} $$让我们分解一下每个部分是如何纳入的:$\text{声学分数}$: 这是字符序列的运行对数概率,从CTC输出计算。这是标准束搜索解码器会使用的分数。$\text{语言模型分数}$: 这是由外部n-gram语言模型计算的完整词序列的对数概率。此分数仅在形成完整词时应用。$\alpha$ (阿尔法): 语言模型权重。这个超参数控制语言模型的影响。较高的α会优先考虑语法正确性,有时会牺牲声学准确性,而较低的α则使解码器更信任声学模型。$\beta$ (贝塔): 词插入奖励。这一项为假设中的每个词添加一个小的奖励。它抵消了概率模型偏爱较短序列的自然倾向(因为将更多小于1的概率相乘会导致更小的数值)。它有助于确保解码器不会不公平地惩罚较长、正确的句子。评分机制的实际运作语言模型的整合在解码过程中发生在特定时刻。束搜索算法按时间步进行,用新字符扩展每个假设。声学分数随着每个新字符的出现而更新。然而,语言模型分数只在识别到词边界时才计算并添加,这通常是在假设中附加空格字符时。考虑束中两个相互竞争的假设:“recognize”和“wreck a nice”。当音频的下一部分听起来像“speech”时,声学模型可能会为字符s-p-ee-ch生成高概率。声学更新: 解码器将“recognize”用一个空格扩展,然后是s、p等。声学分数在每次字符扩展时更新。语言模型查询: 一旦假设变为“recognize ”,解码器就会识别出一个完整的词。然后它查询语言模型,获取“speech”跟在“recognize”后面的概率。语言模型将为此序列返回一个相对较高的概率。分数组合: 加权的语言模型分数被添加到这个假设的总分中,使其获得显著提升。同时,“wreck a nice”假设被扩展为“wreck a nice beach”。当“wreck a nice ”确定后,将查询语言模型以获取“beach”跟在“wreck a nice”后面的概率。尽管这个短语在语音上是可信的,但它不太常见,因此语言模型会为其分配较低的分数。结果,“recognize speech”假设可能会获得更高的总分并保留在束中,而“wreck a nice beach”可能会被剪枝。digraph BeamSearchLM { rankdir=TB; graph [ fontname="Helvetica", size="12,8!", pad="1.0", splines=ortho, nodesep="1.5", ranksep="1.5" ]; node [ shape=record, style="rounded,filled", fontname="Helvetica", fillcolor="#e9ecef", fontsize=12 ]; edge [ fontname="Helvetica", fontsize=10 ]; caption [label="在词边界处,声学分数与加权语言模型分数结合。\n像“recognize speech”这样在语言上更可能的假设会获得显著的分数提升,\n很可能弥补略低的声学分数。", shape=plaintext, fontsize=11, fontcolor="#495057"]; // 定义不可见集群以控制水平流向和标签 subgraph cluster_t { label = "在“...recognize”和“...wreck a”之后的束"; style=invis; t0 [label="{'...recognize' | 分数: -4.2}"]; t1 [label="{'...wreck a' | 分数: -3.9}"]; } subgraph cluster_t_plus_1 { label = "下一个词后的候选"; style=invis; tp1 [label="{'...recognize speech' | 声学分数: -8.5}", fillcolor="#d0bfff"]; tp2 [label="{'...wreck a beach' | 声学分数: -8.1}", fillcolor="#d0bfff"]; } subgraph cluster_final { label="最终分数与语言模型更新"; style=invis; f1 [label="{'...recognize speech' | 最终分数: -8.5 + α*P('speech'|'recognize')}", fillcolor="#96f2d7", shape=oval]; f2 [label="{'...wreck a beach' | 最终分数: -8.1 + α*P('beach'|'a')}", fillcolor="#ffc9c9", shape=oval]; } t0 -> tp1 [label=" + ' speech'"]; t1 -> tp2 [label=" + ' beach'"]; tp1 -> f1 [label="查询语言模型", color="#1c7ed6", style=dashed]; tp2 -> f2 [label="查询语言模型", color="#f03e3e", style=dashed]; // 在同一层级对齐节点 {rank=same; t0; t1;} {rank=same; tp1; tp2;} {rank=same; f1; f2;} }上图显示了两个假设是如何评分的。即使“wreck a beach”的声学分数略高,语言模型为“recognize speech”分配的高概率也可以提高其最终分数,使其成为优选的转录结果。伪代码实现为了使此过程更具体,以下是一个包含n-gram语言模型的CTC束搜索解码器的高级算法。# 算法的简化表示 def ctc_beam_search_decoder(acoustic_probs, beam_width, lm, alpha, beta): # beam = [(前缀文本, 声学分数, 语言模型状态)] # lm_state 存储假设的n-gram历史 initial_lm_state = lm.initial_state() beam = [("", 0.0, initial_lm_state)] for timestep_probs in acoustic_probs: new_beam = [] for prefix, acoustic_score, lm_state in beam: for char, char_prob in timestep_probs.items(): # 处理空白符和重复字符的标准CTC逻辑 # (此部分为清晰起见已省略) new_prefix = prefix + char new_acoustic_score = acoustic_score + log(char_prob) # 检查是否刚完成一个词 if char == ' ': # 使用语言模型对完成的词进行评分 word = get_last_word(new_prefix) lm_score = lm.score(word, state=lm_state) # 获取下一个词的新的语言模型状态 new_lm_state = lm.update_state(word, lm_state) # 用语言模型分数和词奖励更新总分 total_score = new_acoustic_score + alpha * lm_score + beta new_beam.append((new_prefix, total_score, new_lm_state)) else: # 不是词边界,只需沿用语言模型状态 total_score = new_acoustic_score new_beam.append((new_prefix, total_score, lm_state)) # 剪枝束:按分数排序并保留前 `beam_width` 个假设 beam = sorted(new_beam, key=lambda x: x[1], reverse=True)[:beam_width] # 从最终束中最佳假设返回文本 sorted(beam, key=lambda x: x[1], reverse=True)[0] return best_hypothesis[0] 实际考量状态管理: 如伪代码所示,束中的每个假设都必须维护自己的语言模型状态。对于n-gram模型,此状态就是假设的最后n-1个词。这确保了下一个词的概率是基于其正确语境计算的。调整α和β: α和β的值并非固定不变。它们是重要的超参数,必须在验证集上进行调整,以找到最适合您的特定声学模型和语言模型的最佳平衡。这通常通过使用不同值运行解码并选择产生最低词错误率(WER)的组合来完成。性能: 为每个假设中的每个新词查询外部语言模型会增加计算开销。像KenLM这样高效的语言模型工具包旨在实现快速查询,使得即使对于大型束,此过程也是可行的。通过将语言模型整合到解码搜索中,您将ASR系统从一个简单的声学到音素转录器转变为一个更能理解和应用语言规则的智能系统,大幅提高了最终转录的质量和可读性。