微软语音识别实验室WER计算代码问题:循环仅累计首句结果
修复单句WER计算循环重复第一句结果的问题
嗨,我仔细看了你的代码,发现几个核心问题导致循环时一直复用第一句的计算结果,咱们一步步来解决:
问题根源
string_edit_distance函数没有返回计算出的tokens、deletions、insertions、substitutions这些关键值,你在循环里直接用这些变量时,其实是在引用之前残留的全局值(也就是第一句的结果)。- 你没有在每次循环中调用
string_edit_distance并传入当前句子的参考文本和假设文本,相当于根本没重新计算后续句子的WER。 - 函数内的
RuntimeError没有用raise抛出,参数为空时不会触发错误提示。 - 部分全局统计的打印语句(比如总句子数)放在了循环内部,导致每次循环都重复打印,逻辑混乱。
修复后的完整代码
第一步:修改string_edit_distance函数,让它返回计算结果
import numpy as np def string_edit_distance(ref=None, hyp=None): if ref is None or hyp is None: raise RuntimeError("ref and hyp are required, cannot be None") x = ref.split() # 按空格分割成单词列表(WER基于单词级编辑距离) y = hyp.split() tokens = len(x) if len(y) == 0: return (tokens, tokens, 0, 0) # 返回(总词数, 删除数, 插入数, 替换数) # 初始化距离矩阵和错误跟踪矩阵 p = np.PINF * np.ones((len(x) + 1, len(y) + 1)) e = np.zeros((len(x)+1, len(y) + 1, 3), dtype=np.int) # [删除, 插入, 替换] p[0] = 0 for ix in range(len(x) + 1): for iy in range(len(y) + 1): cst = np.PINF*np.ones([3]) s = 0 if ix > 0: cst[0] = p[ix - 1, iy] + 1 # 删除代价 if iy > 0: cst[1] = p[ix, iy - 1] + 1 # 插入代价 if ix > 0 and iy > 0: s = 1 if x[ix - 1] != y[iy -1] else 0 cst[2] = p[ix - 1, iy - 1] + s # 替换代价 if ix > 0 or iy > 0: idx = np.argmin(cst) p[ix, iy] = cst[idx] if idx == 0: # 删除 e[ix, iy, :] = e[ix - 1, iy, :] e[ix, iy, 0] += 1 elif idx == 1: # 插入 e[ix, iy, :] = e[ix, iy - 1, :] e[ix, iy, 1] += 1 elif idx == 2: # 替换 e[ix, iy, :] = e[ix - 1, iy - 1, :] e[ix, iy, 2] += s deletions, insertions, substitutions = e[-1, -1, :] return tokens, deletions, insertions, substitutions
第二步:修改主循环逻辑,正确调用函数并处理每一句
# 加载数据 with open("misc/hyp.trn") as f: hyp_data = f.readlines() with open("misc/ref.trn") as f: ref_data = f.readlines() # 预处理数据:去掉末尾20个字符并去除首尾空白 hypData = [line[:-20].strip() for line in hyp_data] refData = [line[:-20].strip() for line in ref_data] # 全局统计变量初始化 total_tokens = 0 total_deletions = 0 total_insertions = 0 total_substitutions = 0 # 先打印全局基础统计 print(f"Total number of reference sentences in the test set: {len(refData)}") print("----------------------------------------------------------------") # 循环处理每一句 for i in range(len(hypData)): ref_sent = refData[i] hyp_sent = hypData[i] print(f"Line Number: {i+1}") print(f"Reference: {ref_sent}") print(f"Hypothesis: {hyp_sent}") # 调用函数获取当前句子的计算结果 tokens, deletions, insertions, substitutions = string_edit_distance(ref_sent, hyp_sent) # 计算当前句子的WER(加除零保护) wer = (deletions + insertions + substitutions) / tokens if tokens != 0 else 0 # 打印当前句子的详细结果 print(f"Scores: N={tokens}, S={substitutions}, D={deletions}, I={insertions}") print(f"Sentence WER: {round(wer*100, 1)}%") print(f"Substitutions: {round((substitutions/tokens)*100, 1)}%" if tokens !=0 else "Substitutions: N/A") print(f"Insertions: {round((insertions/tokens)*100, 1)}%" if tokens !=0 else "Insertions: N/A") print(f"Deletions: {round((deletions/tokens)*100, 1)}%" if tokens !=0 else "Deletions: N/A") print("----------------------------------------------------------------") # 累计全局统计值 total_tokens += tokens total_deletions += deletions total_insertions += insertions total_substitutions += substitutions # 计算并打印总WER if total_tokens > 0: total_wer = (total_deletions + total_insertions + total_substitutions) / total_tokens print(f"Total WER: {round(total_wer*100, 1)}%") print(f"Total Scores: N={total_tokens}, S={total_substitutions}, D={total_deletions}, I={total_insertions}") else: print("No valid reference tokens to calculate total WER.")
关键修改说明
- 函数返回值调整:让
string_edit_distance返回当前句子的总词数、删除数、插入数、替换数,这样每次循环调用都能拿到新句子的结果。 - 单词分割处理:在函数内部把输入的字符串按空格分割成单词列表,因为WER是基于单词的编辑距离,不是字符。
- 修复错误抛出:把
RuntimeError("...")改成raise RuntimeError("..."),确保参数为空时能正确报错。 - 循环逻辑修正:在循环内每次调用函数时传入当前句子的
ref_sent和hyp_sent,并接收返回值,避免复用旧值。 - 全局统计优化:新增全局累计变量,最后计算总WER,同时把全局统计的打印语句移到循环外面,避免重复输出。
- 除零保护:添加了
tokens !=0的判断,避免空参考文本导致的除以零错误。
内容的提问来源于stack exchange,提问作者Innovative Aadi
相关产品推荐
相关产品推荐

