Job Transcribe
2023 public experiment revisit

3,922문장과 3개 콜센터 시나리오로 다시 본 한국어 STT 벤치마크

2023년에 직접 설계하고 수행했던 한국어 ASR/STT 실험을 실제 레포 데이터로 다시 분석했다. 평균 CER 하나가 아니라 분포, threshold 통과율, paired comparison, worst case, 숫자 표기 민감도까지 함께 본다.

이 분석은 2023년에 공개적으로 접근 가능한 제품과 오픈소스 모델을 사용해 수행한 개인 프로젝트성 실험 결과를 재정리한 것이다. 현재 Microsoft/Azure, AWS, Clova, GCP, OpenAI/Whisper 제품 성능을 대표하지 않으며, 각 회사의 공식 벤치마크나 내부 성능 데이터가 아니다.
3,922 single-speaker utterances
2.22% Whisper large mean CER
83.20% Whisper large CER <= 5%
Essay

기고문 뒤에 남은 실험 기록

이 글은 모델 순위표를 다시 만드는 작업이 아니다. 2023년에 공개 제품과 공개 모델로 한국어 STT를 테스트하면서, 어떤 질문을 세웠고 어떤 기준으로 결과를 읽었는지 정리한 기록이다.

당시의 질문은 단순했다. "한국어 음성을 텍스트로 바꾸는 일을 실제 업무에 붙인다면, 어떤 모델이 얼마나 잘 맞히는가?" 하지만 테스트를 시작하자 곧 더 중요한 질문이 생겼다. "잘 맞혔다"는 말을 어떤 숫자로, 어떤 정답지 기준으로, 어느 정도의 오류 허용선 안에서 말할 것인가.

당시 공개 기고문: ITDaily ComputerWorld

상황: 모델 출력보다 먼저 평가 기준이 필요했다

공개 클라우드 STT와 오픈소스 Whisper 모델은 모두 transcript를 반환하지만, 그 transcript가 같은 방식으로 틀리지는 않았다. 어떤 결과는 띄어쓰기만 달랐고, 어떤 결과는 숫자를 한글로 풀어썼고, 어떤 결과는 고유명사나 외래어에서 크게 흔들렸다. 그래서 원문과 출력문을 눈으로 읽는 것만으로는 비교가 끝나지 않았다. 같은 음성, 같은 정답지, 같은 오류 계산식이 필요했다.

이때 별도로 만든 것이 Compute STT Error Rate, 즉 Nlptutti 패키지다. 공개 레포는 computing-Korean-STT-error-rates이고, 테스트 코드에서는 nlptutti로 import해 사용했다. Nlptutti는 get_cer, get_wer, get_crr와 키워드 패턴 유틸리티로 구성했다. 내부적으로 Levenshtein edit distance를 사용해 substitutions, deletions, insertions를 세고, 공백과 문장부호 처리 같은 한국어 STT 평가의 민감한 기준을 코드로 고정했다.

직접 만들었던 이유도 분명했다. 기존 방식처럼 reference 길이만 분모로 두면 insertion이 많은 transcript에서 CER가 1을 넘거나 원하는 0-1 범위 밖으로 튈 수 있었다. 그래서 Nlptutti는 오류항 S+D+I를 numerator로 두되, denominator를 S+D+I+C로 잡아 insertion까지 포함한 normalized error rate로 계산했다. 이 작은 정규화 항이 한국어 STT 결과를 반복 비교할 수 있게 만든 핵심이었다.

진행: 두 개의 테스트면으로 나눴다

첫 번째 테스트는 단일 화자 3,922문장 벤치마크였다. 같은 file_nameground_truth를 기준으로 AWS Transcribe와 Whisper base, medium, large의 transcript를 모았다. 각 행에는 정답 문장, 모델 출력, CER가 남도록 했다. 이 데이터는 모델별 평균 성능뿐 아니라 문장 단위로 누가 더 자주 낮은 CER를 보였는지 비교할 수 있는 기준면이 됐다.

중심 데이터인 3,922문장은 직접 읽고 녹음한 내 음성 데이터였다. 집 안에서 비교적 조용하고 반향이 적은 서재에서 하루 50문장을 목표로 읽었다. 문장은 멀티 패턴 USB 콘덴서 마이크의 단일 지향성(cardioid) 수음 모드로 하나씩 WAV 파일로 남겼고, 누적 리딩과 녹음 시간은 거의 8시간에 가까웠다. 실험 설계부터 녹음, STT 실행, 결과 수집, metric 고정까지 약 3개월 동안 직접 리딩한 작업이었다.

두 번째 테스트는 금융 콜센터를 가정한 3개 persona였다. PB 채권 주문, 신생기업 대출 안내, 자동차 보험료 할증 문의처럼 전화번호, 계좌번호, 금액, 날짜 같은 숫자 정보가 자주 등장하는 상담을 짧게 검증해보기 위한 간이 테스트였다. 팀원 몇 명과 30분 정도 미팅하고 녹음했고, 미팅룸 공간을 고려해 개인 비용으로 준비한 멀티 패턴 USB 콘덴서 마이크를 양방향(bidirectional) 수음 모드로 두어 1:1 대화의 양쪽 음성을 균형 있게 담아보려 했다. 표본이 작기 때문에 provider 순위를 내기 위한 용도는 아니었다. 대신 같은 상담이 한글 정답지와 숫자 정답지에서 얼마나 다르게 평가되는지, 숫자 표기 정책이 CER를 어떻게 흔드는지 보기 위한 case analysis였다.

액션: 평균 하나 대신 운영 가능한 메트릭을 골랐다

결과를 읽을 때는 평균 CER만 보지 않았다. 평균은 전체 경향을 주지만, 실제 workflow에서는 "자동 통과시킬 수 있는 문장이 몇 개인가", "검수 queue로 보내야 할 tail이 얼마나 남는가"가 더 직접적이다. 그래서 완전 인식률, 5% 이하 pass rate, 10% 초과 tail risk, paired delta, worst/disagreement examples, scenario heatmap을 함께 만들었다.

가장 번거로웠던 부분은 모델을 실행하는 것보다 결과를 같은 좌표에 올리는 일이었다. provider마다 JSON, TXT, CSV 형태가 달랐고, 한국어에서는 띄어쓰기와 문장부호, 숫자 표기 하나가 CER를 크게 바꿨다. 특히 보험료 할증 문의처럼 번호, 금액, 날짜가 섞인 상담에서는 "의미는 비슷하지만 문자는 다른" 결과가 반복됐다. 그래서 이 글의 콜센터 결과는 ranking이 아니라 정답지 정책과 도메인 민감도를 설명하는 자료로 읽어야 한다.

결론: 벤치마크는 리더보드보다 측정 규칙이다

단일 화자 데이터에서는 Whisper large와 medium이 강한 결과를 보였고, AWS Transcribe는 Whisper base보다 안정적인 결과를 보였다. 하지만 이 결론은 2023년 당시의 공개 제품/공개 모델, 이 레포의 데이터, 당시 CER 산출 방식 안에서만 유효하다. 더 오래 남는 교훈은 특정 모델명이 아니라 측정 방법이다. ASR 품질 평가는 평균 하나로 끝나지 않고, 정답지 정책과 threshold, tail risk를 함께 공개해야 읽는 사람이 결과를 재현하고 해석할 수 있다.

Dataset

두 개의 평가면

단일 화자 데이터는 모델 성능 분포를 보기 위한 중심 벤치마크로, 콜센터 데이터는 숫자와 금융 도메인 문맥에 대한 작은 case analysis로 사용했다.

Area Samples Compared systems Interpretation
Single speaker 3,922 utterances AWS Transcribe, Whisper base, Whisper medium, Whisper large 같은 화자/녹음 조건에서 모델별 CER 분포와 threshold 통과율 비교
Financial call center 3 scenarios x 2 ground-truth bases AWS, Azure, Clova, GCP n=3 case analysis. Provider ranking이 아니라 숫자/도메인 민감도 확인
Single speaker

평균보다 분포와 threshold

단일 화자 3,922문장에서는 Whisper large와 medium이 강한 결과를 보였다. 하지만 실제 의사결정에는 평균 CER와 함께 완전 인식률, 5% threshold, 10% 초과 tail risk를 함께 봐야 한다.

Model Mean CER Median CER Perfect <=5% CER >10% CER
Whisper large 2.22% 0.00% 70.27% 83.20% 5.69%
Whisper medium 2.64% 0.00% 65.12% 79.50% 7.24%
AWS Transcribe 3.73% 0.00% 56.12% 71.01% 12.32%
Whisper base 9.35% 6.94% 29.12% 41.13% 37.33%
Single-speaker mean CER by model
Figure 1. 단일 화자 3,922문장 기준 평균 CER와 95% bootstrap confidence interval. Source: result/*.csv.
Pass rate by CER threshold
Figure 2. CER threshold별 pass rate. 운영 기준을 가정하면 평균 CER만 볼 때와 다른 질문을 할 수 있다.
Interactive

Model Performance Explorer

Threshold를 직접 바꾸면서 pass/fail 비율이 어떻게 움직이는지 확인한다. Call-center 모드에서는 정답지 기준을 바꿔 provider별 scenario pass 비중을 본다.

Dataset
Model / Provider
CER threshold
5%

Pass rate by model

CER <= 5% 기준

Pass Fail
Selected Whisper large
Mean CER 2.22%
Pass at threshold 83.20%
Tail / max risk 5.69% >10%
Settings

설정값 읽는 법

Explorer의 설정값은 "어떤 데이터에서, 어떤 모델을, 어느 정도 오류까지 통과로 볼지"를 정하는 값이다. 낮은 CER는 정답 문장과 더 비슷하다는 뜻이다.

Dataset

Single speaker는 단일 화자 3,922문장 테스트다. 모델별 기본 성능 비교에 쓴다.

Call center는 금융 콜센터 3개 시나리오다. 표본이 작아서 순위가 아니라 사례 분석으로 본다.

Ground truth basis

정답지를 어떤 표기로 볼지 정한다. Hangul은 숫자도 한글처럼 적은 정답지다.

Numeric은 숫자를 숫자 형태로 적은 정답지다. 숫자 표기 때문에 CER가 달라질 수 있다.

예를 들어 "십오억"과 "15억"은 뜻은 같아도 문자 모양이 달라서 CER에서는 다르게 계산된다.

Model / Provider

요약 카드에서 자세히 볼 대상을 고른다. Single speaker에서는 모델, Call center에서는 provider를 고른다.

CER threshold

통과로 인정할 최대 오류율이다. 예를 들어 5%는 CER가 5% 이하인 문장만 pass로 센다.

값을 낮추면 기준이 엄격해지고, 값을 높이면 더 많은 문장이 pass가 된다.

Pass / Fail

Pass는 선택한 threshold 이하의 결과다. Fail은 threshold를 넘은 결과다.

Call center에서는 3개 시나리오 중 몇 개가 통과했는지를 비율로 보여준다.

Mean CER / Tail risk

Mean CER는 평균 오류율이다. 낮을수록 이 데이터에서는 정답과 더 가까웠다.

Tail risk는 크게 틀린 결과가 얼마나 남는지 보는 값이다. 평균이 낮아도 tail risk가 크면 검수가 필요하다.

Nlptutti CER

원래 측정 스크립트는 nlptutti.get_cer(정답, 인식결과)를 호출하고, 반환값의 cer를 CSV에 저장했다.

이 함수는 S+D+I 오류항을 세고, denominator에 insertion을 포함한 S+D+I+C를 사용해 과도한 삽입 오류가 값 전체를 흔들지 않게 했다.

이 페이지는 저장된 cer 값을 다시 요약하고 시각화한다. 블로그 단계에서 새로 정규화해 재계산하지 않는다.

Call center

Ranking보다 표기 민감도

콜센터 데이터는 3개 시나리오뿐이다. 평균값은 보조 요약으로만 읽고, 실제 상담에서 자주 나오는 숫자, 번호, 금액, 날짜가 정답지 표기에 따라 어떻게 흔들리는지 본다.

이 보조 테스트는 팀원 몇 명과 30분 정도 진행한 짧은 시나리오 녹음이었다. PB 채권 주문, 신생기업 대출 안내, 자동차 보험료 할증 문의처럼 숫자 입력 정확도가 중요한 상담을 골랐고, 미팅룸에서는 개인 비용으로 준비한 멀티 패턴 USB 콘덴서 마이크를 양방향 수음 모드로 두어 1:1 대화의 양쪽 음성을 최대한 균형 있게 담으려 했다.

Call-center mean CER by provider
Figure 3. 금융 콜센터 3개 시나리오의 provider별 평균 CER. n=3 case summary로만 읽는다.
Call-center CER heatmap by scenario
Figure 4. 시나리오 x provider CER heatmap. PB bond order는 여러 provider에서 상대적으로 높은 CER를 보였다.
Insurance persona AWS Azure Clova GCP
Hangul ground truth CER 11.99% 11.54% 30.80% 29.67%
Numeric ground truth CER 14.51% 8.79% 27.10% 28.58%

보험료 할증 문의 persona에서는 숫자 표기 기준을 바꾸자 provider별 CER가 다른 방향으로 움직였다. Azure는 11.54%에서 8.79%로 낮아졌고, AWS는 11.99%에서 14.51%로 높아졌다. 이 차이는 provider ranking보다 "정답지 표기 정책이 CER에 미치는 영향"으로 읽어야 한다.

Reproduce

실제 결과 파일만 사용

이 페이지의 JSON과 PNG는 모두 레포의 실제 결과 파일에서 생성된다. Mock CSV는 사용하지 않는다.

uv run --python /usr/bin/python3 --with pandas --with numpy --with matplotlib python analysis/analyze_asr_benchmarks.py
  • 원 측정은 measure_nlp_cer_job.py, oepnai_job.py, measure_cs_job.py에서 nlptutti.get_cer(...)로 수행
  • 재분석 스크립트는 기존 결과 CSV의 cer 값을 그대로 사용하고 새 CER를 만들지 않음
  • 단일 화자 4개 결과 CSV의 file_name 집합 일치 검증
  • 콜센터 결과 row count와 scenario count 일치 검증
  • docs/assets/*.pngdocs/data/asr-benchmark.json 재생성
Single speaker 측정 흐름

직접 녹음한 3,922개 WAV 파일을 STT 모델 또는 서비스에 넣고 transcript를 만든 뒤, 정답 문장과 transcript를 Nlptutti CER로 비교했다.

결과는 result/result_3922.csv와 Whisper별 result/openai_whisper_*_result_3922.csv에 저장되어 있다.

Call center 측정 흐름

measure_cs_job.py가 한글 정답지와 숫자 정답지를 따로 읽고, AWS/Azure/Clova/GCP transcript와 각각 비교했다.

그래서 같은 보험 상담 transcript라도 cs_hangul_result.csvcs_number_result.csv에서 CER가 달라질 수 있다.

Test

테스트하는 방법

페이지가 제대로 동작하는지는 공개 URL에서 빠르게 확인할 수 있고, 분석 결과는 로컬에서 스크립트를 다시 실행해 재생성할 수 있다.

1. 공개 페이지 열기

https://hyeonsangjeon.github.io/job-transcribe/를 연다.

상단 제목, 면책 문구, 3개 metric card가 보이면 첫 화면은 정상이다.

2. Explorer 기본값 확인

처음에는 Single speaker, CER threshold 5%, Whisper large가 선택되어 있다.

Pass at threshold가 83.20%, Mean CER가 2.22%이면 기본 데이터가 정상 로드된 것이다.

3. Call center 전환 확인

Dataset을 Call center로 바꾸면 Ground truth basis는 Numeric, provider는 Azure, threshold는 10%로 잡힌다.

Pass가 66.67%, Mean CER가 10.59%, Tail / max risk가 max 17.43%이면 정상이다.

보험 persona만 보면 Numeric 기준 Azure CER는 8.79%, Hangul 기준 Azure CER는 11.54%다.

4. 로컬에서 재생성

레포 루트에서 아래 명령을 실행한다.

uv run --python /usr/bin/python3 --with pandas --with numpy --with matplotlib python analysis/analyze_asr_benchmarks.py

docs/assets/*.pngdocs/data/asr-benchmark.json이 다시 만들어지면 분석 재생성이 정상이다.

5. 로컬 페이지 확인

아래 명령으로 정적 서버를 띄운다.

python3 -m http.server 8765 --bind 127.0.0.1

http://127.0.0.1:8765/docs/를 열고 공개 페이지와 같은 값이 보이는지 확인한다.

6. 해석할 때 주의

이 테스트는 2023년 공개 제품/공개 모델 실험이다. 현재 vendor 성능을 대표하지 않는다.

콜센터 결과는 3개 시나리오뿐이므로 provider ranking으로 쓰지 않는다.

Lessons learned

테스트를 하면서 남은 교훈

이 프로젝트에서 가장 오래 남은 작업은 모델 호출 코드가 아니라 평가 기준을 고정하는 일이었다. 아래 항목은 이번 재분석에서도 그대로 유지한 원칙이다.

1. 평균 CER만으로는 운영 판단이 부족하다. 평균은 전체 경향을 보여주지만, 실제 제품에서는 threshold 통과율과 tail risk가 더 직접적인 의사결정 지표가 된다.

2. 정답지 정책은 모델 성능만큼 중요하다. 한국어 STT에서는 띄어쓰기, 문장부호, 숫자 표기, 외래어 표기가 CER를 크게 바꾼다. 그래서 한글 정답지와 숫자 정답지를 분리하고, 콜센터 결과를 ranking이 아니라 표기 민감도 사례로 읽었다.

3. 측정 도구를 직접 만든 이유는 반복성 때문이다. Compute STT Error Rate 프로젝트에서 Nlptutti를 만든 덕분에 3,922문장과 콜센터 transcript를 같은 함수로 계산했다. insertion이 많은 결과에서도 denominator를 S+D+I+C로 고정해 0-1 범위 안에서 비교 가능한 CER를 남겼고, 나중에 다시 분석할 때도 기존 CSV의 cer 값을 추적할 수 있었다.

4. 작은 case analysis는 순위표가 아니다. 콜센터 3개 시나리오는 숫자와 도메인 표현이 어떤 오류를 만드는지 보기 위한 자료다. 이 결과를 현재 vendor 성능이나 일반적인 우열로 확장하지 않는다.

5. 재현 가능한 레포 구조가 결국 기록을 살린다. 직접 읽고 녹음한 3,922문장, 원천 결과, 전처리 CSV, 분석 스크립트, 파생 JSON/PNG가 남아 있었기 때문에 약 3개월 동안 진행했던 3년 전 실험을 새 mock data 없이 다시 읽을 수 있었다.

Limits

해석 범위

이 글은 모델이나 vendor의 현재 우열을 일반화하려는 문서가 아니다. 2023년 당시 실험 자산을 재현 가능한 분석과 시각화로 정리한 것이다.

현재 Microsoft/Azure, AWS, Clova, GCP, OpenAI/Whisper 성능을 대표하지 않는다.

각 회사의 공식 벤치마크, 내부 성능 데이터, 비공개 benchmark가 아니다.

단일 화자 3,922건은 같은 화자와 녹음 조건 안에서의 비교다.

콜센터 데이터는 3개 시나리오의 case analysis이며 provider ranking 근거로 쓰지 않는다.

CER는 의미 보존, 화자 분리, 타임스탬프, punctuation quality를 직접 평가하지 않는다.