判断语音识别结果好坏的指标——python实现:

  • WER字错率
  • SER句错率
  • 杰卡德系数
  • TF 相似度
  • TF-IDF 相似度
  • Word2Vec词向量比较相似性

素材的下载:

    下载地址:链接:https://pan.baidu.com/s/1cTjob0fic0wN16krePThxA

     提取码:269s

result.txt 是按照train.txt 中内容录得音频,经过语音识别的文字结果。

train.txt 为录音内容文本。

python 音频 相似度 音频对比相似度_python

WER字错率

    字错率是一种常用的且计算速度比较快的评价方法,根本原理在于统计原句中的文字,和识别录音之后的字的不同之处从而断定语音识别模型好坏。在一般性的识别率的计算上常常使用。“WER(词错误率,Word Error Rate)”。

 

python 音频 相似度 音频对比相似度_相似度_02

        Substitution——替换

        Deletion——删除

        Insertion——插入

        N——单词数目

        其中S+D+I的计算过程也叫:编辑距离计算

编辑距离计算:

        编辑距离,英文叫做 Edit Distance,又称 Levenshtein 距离,是指两个字串之间,由一个转成另一个所需的最少编辑操作次数,如果它们的距离越大,说明它们越是不同。许可的编辑操作包括将一个字符替换成另一个字符,插入一个字符,删除一个字符。

        例如我们有两个字符串:string 和 setting,如果我们想要把 string 转化为 setting,需要这么两步:

        第一步,在 s 和 t 之间加入字符 e。

        第二步,把 r 替换成 t。

        所以它们的编辑距离差就是 2,这就对应着二者要进行转化所要改变(添加、替换、删除)的最小步数。

因为有插入词,所以理论上WER有可能大于100%,但实际中、特别是大样本量的时候,是不可能的,否则就太差了,不可能被商用。(代码如下)

import distance
def edit_distance(s1, s2):
    return distance.levenshtein(s1, s2)

计算总WER():代码如下

# 计算总WER
def calculate_WER():
    text1_list = [i[11:].strip("\n") for i in read_result("result.txt")]
    text2_orgin_list = [i[11:].strip("\n") for i in read_result("train.txt")]
    # print(text2_orgin_list)
    total_distance = 0
    total_length = 0
    for i in range(len(text1_list)):
        text1 = text1_list[i]
        text2_orgin = text2_orgin_list[i]
        res, length = text_distance(text1, text2_orgin)
        # print(res, length)
        total_distance += res
        total_length += length
    print("总距离:", total_distance)
    print("总长度:", total_length)
    WER = total_distance / total_length
    print("总WER:", WER.__format__('0.2%'))

结果输出:

总距离: 538

总长度: 5213

总WER: 10.32%

SER句错率

        SER表述为句子中如果有一个词识别错误,那么这个句子被认为识别错误,句子识别错误的的个数,除以总的句子个数即为SER。

python 音频 相似度 音频对比相似度_人工智能_03

         站在纯产品体验角度,很多人会以为识别率应该等于“句子识别正确的个数/总的句子个数”,即“识别(正确)率等于96%”这种,实际工作中,这个应该指向“SER(句错误率,Sentence Error Rate)”,即“句子识别错误的个数/总的句子个数”。不过据说在实际工作中,句错率对结果太苛刻了,一般字错误率的2~3倍,所以可能就不太怎么看了。代码如下

# 计算SER句错率
def calculate_SER():
    text1_list = [i[11:].strip("\n") for i in read_result("result.txt")]
    text2_orgin_list = [i[11:].strip("\n") for i in read_result("train.txt")]
    total_distance = 0
    for i in range(len(text1_list)):
        text1 = text1_list[i]
        text2_orgin = text2_orgin_list[i]
        text2_orgin = remove_punctuation(text2_orgin)
        # 去除句子中的空格
        text1 = text1.replace(' ', '')
        # print(text1,"\n",text2_orgin)
        if text2_orgin != text1:
            total_distance += 1
    SER = total_distance / len(text1_list)
    print("总句子数量:", len(text1_list))
    print("总不相同句子数量:", total_distance)
    print("总SER:", SER.__format__('0.2%'))

输出结果: 

总句子数量: 100
总不相同句子数量: 59
总SER: 59.00%

杰卡德系数计算

        杰卡德系数,英文叫做 Jaccard index, 又称为 Jaccard 相似系数,用于比较有限样本集之间的相似性与差异性。Jaccard 系数值越大,样本相似度越高。 实际上它的计算方式非常简单,就是两个样本的交集除以并集得到的数值,当两个样本完全一致时,结果为 1,当两个样本完全不同时,结果为 0。 算法非常简单,就是交集除以并集。(代码如下)

# Jaccard 相似度
def jaccard_similarity(s1, s2):
    s1, s2 = set(s1), set(s2)
    return len(s1 & s2) / len(s1 | s2)

TF 相似度

        TF相似度计算就是,计算 TF(词频向量化) 矩阵中两个向量的相似度了,实际上就是求解两个向量夹角的余弦值,就是点乘积除以二者的模长,公式如下

        cosθ=a·b/|a|*|b|

代码如下:

import numpy as np
from sklearn.feature_extraction.text import CountVectorizer


# TF 相似度
def tf_similarity(s1, s2):
    def add_space(s):
        return ' '.join(list(s))
    # 将字中间加入空格
    s1, s2 = add_space(s1), add_space(s2)
    # 转化为TF矩阵
    cv = CountVectorizer(tokenizer=lambda s: s.split())
    corpus = [s1, s2]
    vectors = cv.fit_transform(corpus).toarray()
    print(vectors)
    return np.dot(vectors[0], vectors[1]) / (norm(vectors[0]) * norm(vectors[1]))

TF-IDF 相似度

        另外除了计算 TF 系数我们还可以计算 TFIDF 系数,TFIDF 实际上就是在词频 TF 的基础上再加入 IDF 的信息,IDF 称为逆文档频率。

TF-IDF与余弦相似性的应用(一):自动提取关键词 - 阮一峰的网络日志 (TFIDF讲解)        

代码如下:

from sklearn.feature_extraction.text import TfidfVectorizer


# TF-IDF 相似度
def tfidf_similarity(s1, s2):
    def add_space(s):
        return ' '.join(list(s))
    # 将字中间加入空格
    s1, s2 = add_space(s1), add_space(s2)
    # 转化为TF-IDF矩阵
    cv = TfidfVectorizer(tokenizer=lambda s: s.split())
    corpus = [s1, s2]
    vectors = cv.fit_transform(corpus).toarray()
    print(vectors)
    return np.dot(vectors[0], vectors[1]) / (norm(vectors[0]) * norm(vectors[1]))

Word2Vec词向量比较相似性

        将词映射成词向量在通过计算夹角比较相似性,可以通过训练好的Word2Vec 模型,加载模型,将词转化为向量。

使用新闻、百度百科、小说数据来训练的 64 维的 Word2Vec 模型,数据量很大,整体效果还不错,我们可以直接下载下来使用,这里我们使用的是 news_12g_baidubaike_20g_novel_90g_embedding_64.bin 数据,然后实现 Sentence2Vec。

        下载地址:链接:https://pan.baidu.com/s/1cTjob0fic0wN16krePThxA

        提取码:269s

代码如下:

model_file = 'news_12g_baidubaike_20g_novel_90g_embedding_64.bin'
model = gensim.models.KeyedVectors.load_word2vec_format(model_file, binary=True)

def vector_similarity(s1, s2):
    def sentence_vector(s):
        words = jieba.lcut(s)
        v = np.zeros(64)
        for word in words:
            v += model[word]
        v /= len(words)
        return v
    v1, v2 = sentence_vector(s1), sentence_vector(s2)
    return np.dot(v1, v2) / (norm(v1) * norm(v2))