[Audio] ASR에서 CER, WER 구현 및 측정해보기

2024. 2. 9. 12:47Developers 공간 [Shorts]/Vision & Audio

728x90
반응형
<분류>
A. 수단
- OS/Platform/Tool : Linux, Kubernetes(k8s), Docker, AWS
- Package Manager : node.js, yarn, brew, 
- Compiler/Transpillar : React, Nvcc, gcc/g++, Babel, Flutter

- Module Bundler  : React, Webpack, Parcel

B. 언어
- C/C++, python, Javacsript, Typescript, Go-Lang, CUDA, Dart, HTML/CSS

C. 라이브러리 및 프레임워크 및 SDK
- OpenCV, OpenCL, FastAPI, PyTorch, Tensorflow, Nsight

 


1. What? (현상)

이번 글에서는 음성인식에서 사용되는 Metric인 CER과 WER에 대해 살펴보고자 합니다.

먼저 가장 많이 사용되는 CER,WER,TER과 추가적인 개념을 정리하고, CER과 WER을 어떻게 구현한지 살펴보겠습니다.

 

설명하기에 앞서 CSID의 개념에대해 살펴보겠습니다.

  • Correct(C) : 정답인 해당 단위(단어, 음절 등)의 개수
  • Substitution(S) : 음성 인식된 text 중 잘못 "대체"된 해당 단위(단어, 음절 등)의 개수 
  • Insertion(I) :  음성 인식된 text 중 잘못 "추가"된 해당 단위(단어, 음절 등)의 개수
  • Deletion(D) : 음성 인식된 text 중 잘못 "삭제"된 해당 단위(단어, 음절 등)의 개수
  • total # of reference(N) = C+S+D
  • total # of hypothesis = C+S+I

위의 예를 보면 아래와 같습니다.

$$\begin{matrix}
Reference & | & How & are & you &  & today & Patrick \\
 & | & S & D &  & I & & S \\
Hypothesis & | & Were &  & you & here & today & playing \\
\end{matrix}$$

 

기준을 통해, Trascription Hypothesis 문장과 Reference 문장 간의 차이를 측정하는 알고리즘을 Levenshtein distance(Edit Distance) 알고리즘이라고 하며, 이를 기반으로 측정한 Error Rate는 아래와 같습니다.
** transcription : 구술된 내용을 글로 옮겨 기록하는 것(전사)

$$Error Rate = \frac{(S+D+I)}{N}$$

 

  • WER (Word-Error Rate) : 단위가 "단어"일 때의 Error Rate 입니다. 
    • WERR(Word Error Rate Reduction) : BASELINE의 WER보다 얼마나 좋아졌는지를 측정하는 것입니다.
    • Oracle WER : 단순히 최대 후보(hypothesis)를 선택하는 것이 아니라 beam search와 같은 방법을 활용할 때, lattice나 N-best 후보내에서 Reference(정답)와 비교했을 때 가장 WER이 작은(가장 정답과 비슷한) 후보를 선택해 비교하는 것입니다. WER의 Lower Bound라고 할 수 있습니다.
    • Word Accuracy (WAcc)
  • CER (Character-Error Rate) : 단위가 "음절"일 때의 Error Rate 입니다. 
  • TER (Token Error Rate) : 단위가 "토큰 혹은 sub-word"일 때의 Error Rate 입니다. 

 

이외에도 아래와같이 다양한 Metric이 존재합니다.

  • POSER (Part-of-speech Error Rate) : 단위가 "POS"일 때의 Error Rate 입니다. 문법적으로 Reference에 가장 가까운 값을 고르는 방법입니다. 
    ** POS(Part of Speech) : 품사
  • LER (Lemma Error Rate) : 단위가 "lemma"일 때의 Error Rate 입니다.
    ** lemma : 표제어 또는 기본 사전형 단어. 예를 들어 am, are is 는서로 다르지만 뿌리 단어는 be이고 이를 표제어라 합니다.

  • EmbER (Embeddings Error Rate) : 단위가 "lexical word embeddings"일 때의 Error Rate 입니다. 기존에 의미론적인 부분이 반영되지 않아 word의 차이를 binary(0또는 1)로 측정하는 것이 아닌 Cosine Similarity를 통해  weight를 주는 방법입니다.
    ** lexical  : 어휘란 뜻으로, 특정 분야 혹은 도메인에서 사용되는 단어와 구

  • BERTScore : 단위가 "semantic proximity"일 때의 Error Rate입니다. Text Generation을 위해 만들어졌으며, BERT를 활용해 tokenize한 후, Contextual Embedding을 만들어 둘 사이의 Cosine Similarity를 통해 구하는 방법입니다.
    ** 참조 : BERTScore: EvalutatingText Generation With BERT(ICLR'20) https://arxiv.org/pdf/1904.09675.pdf

[BERTScore]

  • SemDist (Sentence Semantic Distance) : 단위가 "complete sentence"일 때의 Error Rate입니다. SentenceBERT를 활용해 sentence embedding을 만들고, 두 벡터를 Consine Similarity를 통해 구하는 방법입니다.
    **참조 : Evaluating User Perception of Speech Recognition System Quality with Semantic Distance Metric(arxiv'22) https://arxiv.org/pdf/2110.05376.pdf

[SemDist]

 


2. Why? (원인)

  • X

3. How? (해결책)

먼저 editdistance를 위한 라이브러리를 설치합니다.

pip3 install editdistance

 

 

자이제 WER혹은 CER을 직접 측정하는 모듈을 살펴보겠습니다. 직접 구현할 것이 아니라 NeMo프레임워크에 구현된 소스(https://github.com/NVIDIA/NeMo/blob/main/nemo/collections/asr/metrics/wer.py)를 가져와보았습니다.

from typing import List
import editdistance

def word_error_rate(hypotheses: List[str], references: List[str], use_cer=False) -> float:
    """
    Computes Average Word Error rate between two texts represented as
    corresponding lists of string.

    Hypotheses and references must have same length.

    Args:
        hypotheses (list): list of hypotheses
        references(list) : list of references
        use_cer (bool): set True to enable cer

    Returns:
        wer (float): average word error rate
    """
    scores = 0
    words = 0
    if len(hypotheses) != len(references):
        raise ValueError(
            "In word error rate calculation, hypotheses and reference"
            " lists must have the same number of elements. But I got:"
            "{0} and {1} correspondingly".format(len(hypotheses), len(references))
        )
    for h, r in zip(hypotheses, references):
        if use_cer:
            h_list = list(h)
            r_list = list(r)
        else:
            h_list = h.split()
            r_list = r.split()
        words += len(r_list)
        # May deprecate using editdistance in future release for here and rest of codebase
        # once we confirm jiwer is reliable.
        scores += editdistance.eval(h_list, r_list)
    if words != 0:
        wer = 1.0 * scores / words
    else:
        wer = float('inf')
    return wer

 

파일 내용이 아래와 같은 텍스트의 나열이라고 할때, 다음과 같은 코드를 통해서 읽겠습니다. 

나는 그래도 이럴때 이렇게 하는데 너는 도대체 왜 그렇게까지 하는지 모르겠어
너는 글쎄 이러면 이렇게 해야된단 걸 너는 대체 왜 그렇게는 인지 모르겠으
...
def read_dataset(file_path):
    output = []
    with open(file_path) as f :
        for line in f:
            text = line.strip()
            output.append(text)
        return output
        
refs_for_wer = read_dataset("reference.txt")
hyps_for_wer = read_dataset("hypothesis.txt")

 

1. WER 측정

 

위를 활용해 WER을 먼저 측정해보겠습니다.

wer = word_error_rate(hypotheses=hyps_for_wer, references=refs_for_wer, use_cer=False)
print(f"WER : {wer}")

 

2. CER 측정

 

이번엔 CER을 측정해보겠습니다. use_cer옵션만 바꾸어주면 됩니다.

cer = word_error_rate(hypotheses=hyps_for_wer, references=refs_for_wer, use_cer=True)
print(f"CER : {cer}")

https://hal.science/hal-03712735v1/file/Thibault_Roux___InterSpeech_2022_v2.pdf

728x90
반응형