语音识别准确率的计算: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))

你可能感兴趣的:(机器学习,语音识别,numpy,人工智能)