Speech Recognition
STT model: openai/whisper-small
Evaluation model: gpt-4.1
Dataset: mozilla-foundation/common_voice_17_0
- WER(Word Error Rate): 34.58%
- CER(Character Error Rate): 14.30%
LLM이 어려워하는 대표적인 문제는 음성과 관련된 작업입니다. "열 개의 음절 이내로 답변을 생성해 줘"와 같은 것들이죠.
발음을 학습할 수 있는 데이터셋도 흔하지 않고, 이를 학습하는 것도 쉽지 않습니다.
이와 관련하여 음성을 텍스트로 변환하는 Speech-to-Text(STT) 모델을 평가하던 중에 흥미롭게 분석할 만한 점들이 있어 기록해보고자 합니다.
발음/의미/형식의 유사성을 기반으로 STT 결과를 평가하였습니다.
실험 분석
프롬프트
================================ System Message ================================
# Role
Automatic speech recognition(ASR) 실험 결과를 면밀하게 분석하여 각 실험 별 오류 정보 리스트를 반환해 주세요.
# Error no
1: 발음 유사, 문자추론 완벽, **띄어쓰기 실패**
2: 발음 유사, **문자추론 실패**
3: **발음 실패**
# Examples
<example>
<exp>
- prediction: 무엇을 바라고 있어
- target: 무엇을 바라고 있어
</exp>
<output>
[]
</output>
<reasoning>
오류가 없음
</reasoning>
</example>
<example>
<exp>
- prediction: 이웃을 쳐서 숨도 아니쉬고 거짓증거하는 사람
- target: 이웃을 쳐서 숨도 아니 쉬고 거짓 증거하는 사람
</exp>
<output>
[1]
</output>
<reasoning>
거짓 증거 → 거짓증거
</reasoning>
</example>
<example>
<exp>
- prediction: 무릎 경영은 의논함으로 성취하나니 전쟁할 진이라
- target: 무릇 경영은 의논함으로 성취하나니 전쟁할지니라
</exp>
<output>
[1, 2]
</output>
<reasoning>
무릇 → 무릎, 전쟁할지니라 → 전쟁할 진이라
</reasoning>
</example>
<example>
<exp>
- prediction: 100 정확한 예측은 불가능한데요
- target: 백프로 정확한 예측은 불가능한데요
</exp>
<output>
[3]
</output>
<reasoning>
백프로 → 100
</reasoning>
</example>
<example>
<exp>
- prediction: 의사에게 사망선고를 받은 줄도 모르는 영신은 주사기운의 의식을 회복하였다
- target: 의사로부터 죽음의 선고를 받은 줄도 모르고 영신은 주사기운에 의식을 회복하였다
</exp>
<output>
[1, 2, 3]
</output>
<reasoning>
의사로부터 → 의사에게, 죽음의 선고 → 사망선고, 주사기운에 → 주사기운의
</reasoning>
</example>
================================ Human Message =================================
<exp_0>
- prediction: 그 이웃을 쳐서 거짓증거하는 사람은 방망이오 카리오 뾰족한 살인이다
- target: 그 이웃을 쳐서 거짓 증거하는 사람은 방망이요 칼이요 뾰족한 살이니라
</exp_0>
<exp_1>
- prediction: 무릎 경영은 의논함으로 성취하나니 보략을 베풀고 전쟁할 진이라
- target: 무릇 경영은 의논함으로 성취하나니 모략을 베풀고 전쟁할지니라
</exp_1>
<exp_2>
- prediction: 그와 동시에 예상적이던 기분은 구름과 같이 흩어지고 안개처럼 쓰러졌다
- target: 그와 동시에 애상적이던 기분은 구름과 같이 흩어지고 안개처럼 스러졌다
</exp_2>
<exp_3>
- prediction: 하면서도 기처는 동력이가 먹는다는 바람에 숨도 아니시고 쭉 들이켰다
- target: 하면서도 기천은 동혁이가 먹는다는 바람에 숨도 아니 쉬고 쪼옥 들이켰다
</exp_3>
<exp_4>
- prediction: 다 좋았는데 원두만큼은 조금 신 것 같아 아쉬웠어
- target: 다 좋았는데 원두만큼은 조금 신 것 같아 아쉬웠어
</exp_4>
<exp_5>
- prediction: 그것은 회원들이 여러 달을 두고 조사해 온 것으로 매우 정확한 통계였다
- target: 그 것은 회원들이 여러 달을 두고 조사해 온 것으로 매우 정확한 통계였다
</exp_5>
<exp_6>
- prediction: 옷 그렇게 벗지 말라고
- target: 옷 그렇게 벗지 말라고
</exp_6>
<exp_7>
- prediction: 의사에게 죽음의 선고를 받은 줄도 모르는 영신은 주사 기운의 조금 의식을 회복하였다
- target: 의사에게 죽음의 선고를 받은 줄도 모르는 영신은 주사 기운에 조금 의식을 회복하였다
</exp_7>
<exp_8>
- prediction: 날씨 또한 100 정확한 예측은 불가능한데요
- target: 날씨 또한 백프로 정확한 예측은 불가능한데요
</exp_8>
<exp_9>
- prediction: 그는 청아를 자기 가슴에 딱 꼭 끼어 안아 보았다
- target: 그는 청아를 자기 가슴에다 꼭 끼어안아 보았다
</exp_9>


Prediction: 그 이웃을 쳐서 거짓증거하는 사람은 방망이오 카리오 뾰족한 살인이다
Reference: 그 이웃을 쳐서 거짓 증거하는 사람은 방망이요 칼이요 뾰족한 살이니라
1. 거짓증거 → 거짓 증거
- 발음: 유사
- 의미: 유사
- 형식: 띄어쓰기는 사람도 쉽지 않은 문제이니 납득 가능
2. 방망이요 → 방망이오
- 발음: 납득 가능
- 의미: 유사
- 형식: 유사
3. 칼이요 → 카리오, 살이니라 → 살인이다
- 발음: 유사
- 의미: "뾰족한 살이니라" 라는 일반적이지 않은 문장이 출현하였고, 방망이, 뾰족한 등 다소 폭력적인 주변 콘텍스트들로부터 적당한 단어를 생성한 것으로 분석됩니다.
Voxtral과 같은 최신 SOTA STT 모델들은 encoder, decoder 구조 대신 decoder만을 사용하는데 음성 인식 능력보다 언어 능력 향상에 초점을 두었던 게 아닐까 생각이 들기도 했습니다.
- 형식: 유사
Prediction: 무릎 경영은 의논함으로 성취하나니 보략을 베풀고 전쟁할 진이라
Reference: 무릇 경영은 의논함으로 성취하나니 모략을 베풀고 전쟁할지니라
1. 무릇 → 무릎
- 발음: 유사
- 의미: 콘텍스트를 고려해 봐도 적절해 보이지 않습니다.
"무릇"이라는 자주 사용되지 않는 단어를 제대로 생성하지 못하였고, 발음을 맞출 수 있는 적절한 단어도 찾지 못한 것이 아닌가 생각됩니다.
- 형식: 유사
2. 모략을 → 보략을
- 발음: 유사
- 의미: "무릇"과 마찬가지로 "모략" 역시 많이 사용되지 않는 단어라는 공통점이 있습니다.
- 형식: 유사
3. 전쟁할지니라 → 전쟁할 진이라
- 발음: 유사
- 의미: "~할지니라"라는 말 역시 흔한 말투는 아닙니다. 이에 더해 "전쟁"이라는 콘텍스트로부터 "진"이라는 단어가 유추된 것이 아닐까 싶습니다. 생성 모델의 한계를 답습하고 있다는 생각이 드네요.
- 형식: 유사
Prediction: 그와 동시에 예상적이던 기분은 구름과 같이 흩어지고 안개처럼 쓰러졌다
Reference: 그와 동시에 애상적이던 기분은 구름과 같이 흩어지고 안개처럼 스러졌다
1. 애상적 → 예상적
- 발음: 유사
- 의미: "애상적" 정도면 캐치할 수 있을 것 같은데 어려웠던 모양입니다. "그와 동시에"라는 콘텍스트가 크게 도움이 되지 않았던 것도 한 몫하지 않았을까 싶기도 합니다.
- 형식: 유사
2. 스러졌다 → 쓰러졌다
- 발음: 유사
- 의미: "스러졌다"가 자주 사용하는 표현은 아니죠. "안개처럼 쓰러졌다"라는 표현도 일반적이진 않지만 대체할 단어를 찾지 못한 것 같습니다.
- 형식: 유사
Prediction: 하면서도 기처는 동력이가 먹는다는 바람에 숨도 아니시고 쭉 들이켰다
Reference: 하면서도 기천은 동혁이가 먹는다는 바람에 숨도 아니 쉬고 쪼옥 들이켰다
1. 기천은 → 기처는, 동혁이→ 동력이
- 발음: 유사
- 의미: 인물/사건/지역의 이름 등 생소한 고유명사는 잘 잡아내지 못한 것 같습니다. 고유명사와 관련된 부분에서 학습할 여지가 있어 보이네요. 이러한 한계점은 번역 작업에서도 유사하게 나타날 것 같습니다.
- 형식: 유사
2. 아니 쉬고 → 아니시고
- 발음: 유사
- 의미: "아니"라는 단어도 일반적으로 사용되는 표현은 아닙니다. "아니시고"라는 표현도 대체제가 없어 적당히 생성한 표현으로 보입니다.
- 형식: 유사
3. 쪼옥 → 쭉
- 발음: 유사
- 의미: 유사하지만 조금 더 일반적인 표현으로 대체된 것 같습니다.
- 형식: 유사
Prediction: 날씨 또한 100% 정확한 예측은 불가능한데요
Reference: 날씨 또한 백프로 정확한 예측은 불가능한데요
1. 백프로 → 100% (%는 normalize 과정에서 사라짐)
- 발음: 유사
- 의미: 동일
- 형식: 글자보다 숫자를 우선시하는 것 같습니다.
Prediction: 그는 청아를 자기 가슴에 딱 꼭 끼어 안아 보았다
Reference: 그는 청아를 자기 가슴에다 꼭 끼어안아 보았다
https://huggingface.co/datasets/mozilla-foundation/common_voice_17_0/viewer/ko?row=9
1. 가슴에다 → 가슴에 딱
- 발음: 유사
- 의미: 관련이 없진 않지만 커 보이진 않습니다.
- 형식: 일부 데이터만 봐서 그럴 수도 있지만, 쌍자음이 들어간 단어와 관련돼서 잘 못하는 경향이 있는 것 같습니다.
2. 끼어안아 → 끼어 안아
- 발음: 유사
- 의미: 유사
- 형식: 띄어쓰기는 납득 가능
Prediction: 걸그러운 애 넷조차 주겠다니까 차장이 선배 이쁘대요
Reference: 껄끄러운 애 내쫓아주겠다니까 차장이 선배 이쁘대요
https://huggingface.co/datasets/mozilla-foundation/common_voice_17_0/viewer/ko?row=10
1. 껄끄러운 → 걸그러운, 내쫓아 → 넷조차
- 발음: 쌍기역과 쌍지읒은 확실히 발음이 다른데 이걸 못 맞출까? 약간 의아하네요.
- 의미: "껄끄러운", "내쫓아"라는 표현은 꽤 일반적인 것 같은데 학습 데이터에 많이 포함이 안 됐던 걸까? 좀 더 분석이 필요할 것 같습니다.
- 형식: 유사
결론
전반적으로 잘하는 편이긴 하지만 몇 가지 공통적으로 나타나는 현상들이 있었습니다.
1. 일반적으로 많이 사용되지 않는 단어가 포함될 경우, 발음과 콘텍스트를 고려하여 적당한 단어를 생성
콘텍스트가 충분하지 않으면 더욱 성능이 떨어짐
- 살이니라 → 살인이다
- 무릇 → 무릎
- 모략을 → 보략을
- 전쟁할지니라 → 전쟁할 진이라
- 애상적 → 예상적
- 스러졌다 → 쓰러졌다
- 기천 → 기처, 동혁이→ 동력이 (고유명사)
- 아니 쉬고 → 아니시고
- 쪼옥 → 쭉
2. 숫자가 포함된 경우 글자 대신 숫자를 우선하는 경우도 있음
- 백프로 → 100%
3. 띄어쓰기를 실패하는 경우도 있지만 많지 않음
4. 조금 더 분석해봐야 할 예제들
- 가슴에다 → 가슴에 딱
- 껄끄러운 애 → 걸그러운 애
- 내쫓아주겠다니까 → 넷조차 주겠다니까
모델의 크기가 커지면 몇몇 문제점들은 해결될 수 있지만, domain-dependent 단어들 특히 고유명사를 다루는 것은 여전히 까다로워 보입니다.
인식해야 할 단어들이 어떤 것들인지 파악하고 목적에 맞는 데이터셋을 기반으로 모델을 학습시킨다면 이러한 문제들이 다소 완화될 것으로 기대해 볼 수 있을 것 같습니다.
다음엔 조금 더 큰 mistralai/Voxtral-Mini-3B-2507을 통한 실험 및 학습을 해볼 예정입니다.
그럼 다음에 다시 뵙죠!