• 语音识别准确率的计算:CER


    1. WER 与 CER

    WER 表示词错率,CER 表示字错率。一般来说,在汉语语音识别中,字就是最小单位,所以通常用 CER,而英文或手写公式的识别中通常用 WER。

    虽然两者略有不同,但核心的计算方式是一样的。


    2. 计算方式

    CER 计算公式如下: C E R = S + D + I N CER=\frac{S+D+I}{N} CER=NS+D+I其中, N N N 是原字符串的长度, S S S 是替换掉的字符数量, D D D 是删除掉的字符数量, I I I 是额外插入的字符数量。

    因此,字错率的取值范围是 [ 0 , ∞ ) [0,\infin) [0,)

    字正确率
    此外,还有字正确率 C . A c c C.Acc C.Acc 这么个东西,它的公式就是 1 − C E R 1-CER 1CER 因此它可能是负数。


    3. 公式推导

    直接计算 S , D , I S,D,I S,D,I 很困难,但是有一个显而易见的方法就是动态规划,使用动态规划的方法可以不用直接求出三者的数量,而直接计算 S + D + I S+D+I S+D+I(取最小值),下面来看看推导过程:

    首先设 r r r 为原字符串, h h h 为识别字符串。 f [ i ] [ j ] f[i][j] f[i][j] 表示 r r r 到第 i i i 个字符, h h h 到第 j j j 个字符时的 S + D + I S+D+I S+D+I 是多少。

    然后进行状态转移,此时我们判断 r [ i + 1 ] r[i+1] r[i+1] h [ j + 1 ] h[j+1] h[j+1],如果它们两个相同,那它就不是 替换 / 删除 / 插入,状态转移方程可以直接写为: f [ i + 1 ] [ j + 1 ] = f [ i ] [ j ] f[i+1][j+1] = f[i][j] f[i+1][j+1]=f[i][j]
    而如果这两个字符不相同,那就有 替换 / 删除 / 插入 三种可能:

    1. 对于替换 S S S f [ i + 1 ] [ j + 1 ] f[i+1][j+1] f[i+1][j+1] 可以看作从 r [ i ] r[i] r[i] h [ j ] h[j] h[j] 分别同时增加一个不同的字符,且 S + = 1 S+=1 S+=1,所以此时的值为 S u b = f [ i ] [ j ] + 1 Sub=f[i][j]+1 Sub=f[i][j]+1
    2. 对于删除 D D D f [ i + 1 ] [ j + 1 ] f[i+1][j+1] f[i+1][j+1] 可以看作 h [ i ] h[i] h[i] 没变, r [ i ] r[i] r[i] 增加了一个字符,也就是 f [ i + 1 ] [ j + 1 ] f[i+1][j+1] f[i+1][j+1] 这个状态是由 f [ i ] [ j + 1 ] f[i][j+1] f[i][j+1] 转移过来,所以 D e l = f [ i ] [ j + 1 ] + 1 Del=f[i][j+1]+1 Del=f[i][j+1]+1
    3. 对于插入 I I I,和删除类似,只不过状态是由 f [ i + 1 ] [ j ] f[i+1][j] f[i+1][j] 转移而来,所以 I n s = f [ i + 1 ] [ j ] + 1 Ins=f[i+1][j]+1 Ins=f[i+1][j]+1

    考虑以上三种可能,总的状态转移方程就可以写成: f [ i + 1 ] [ j + 1 ] = min ⁡ ( S u b , D e l , I n s ) f[i+1][j+1]=\min(Sub,Del,Ins) f[i+1][j+1]=min(Sub,Del,Ins)因为我们想尽量找到更多相同的字符,也就是找最大匹配,所以取最小值,最后的 CER 就是: C E R = f [ l e n ( r ) ] [ l e n ( h ) ] / l e n ( r ) CER=f[len(r)][len(h)]/len(r) CER=f[len(r)][len(h)]/len(r)


    4. 代码实现

    import numpy
    
    def CER(r: list, h: list): -> float
        # initialisation
        f = numpy.zeros((len(r) + 1) * (len(h) + 1), dtype=numpy.uint16)
        f = f.reshape((len(r) + 1, len(h) + 1))
        for i in range(len(r) + 1):
            for j in range(len(h) + 1):
                if i == 0:
                    f[0][j] = j
                elif j == 0:
                    f[i][0] = i
        
        # computation
        for i in range(1, len(r) + 1):
            for j in range(1, len(h) + 1):
                if r[i - 1] == h[j - 1]:
                    f[i][j] = f[i - 1][j - 1]
                else:
                    Sub = f[i - 1][j - 1] + 1
                    Ins = f[i][j - 1] + 1
                    Del = f[i - 1][j] + 1
                    f[i][j] = min(Sub, Ins, Del)
        return f[len(r)][len(h)] / float(len(r))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
  • 相关阅读:
    2024年8月7日(mysql主从 )
    BellmanFord算法
    Vue2+Vue3基础入门到实战项目(七)——智慧商城项目
    5.Mybatis 缓存详解
    AcWing周赛76场 && LeetCode单周赛318场
    数组排序,实现中间数字最大,向两边越来越小的排序
    【全开源】餐饮点餐小程序源码(ThinkPHP+FastAdmin+Uniapp)
    高光时刻丨赛宁网安携前沿技术研究亮相Blackhat 2022
    LOAD_BALANCE=false 主在不会切换备
    docker命令
  • 原文地址:https://blog.csdn.net/SP_FA/article/details/128076457