You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

微软语音识别实验室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.")

关键修改说明

  1. 函数返回值调整:让string_edit_distance返回当前句子的总词数、删除数、插入数、替换数,这样每次循环调用都能拿到新句子的结果。
  2. 单词分割处理:在函数内部把输入的字符串按空格分割成单词列表,因为WER是基于单词的编辑距离,不是字符。
  3. 修复错误抛出:把RuntimeError("...")改成raise RuntimeError("..."),确保参数为空时能正确报错。
  4. 循环逻辑修正:在循环内每次调用函数时传入当前句子的ref_sent和hyp_sent,并接收返回值,避免复用旧值。
  5. 全局统计优化:新增全局累计变量,最后计算总WER,同时把全局统计的打印语句移到循环外面,避免重复输出。
  6. 除零保护:添加了tokens !=0的判断,避免空参考文本导致的除以零错误。

内容的提问来源于stack exchange,提问作者Innovative Aadi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 09:10:49