2026. 8. 24. 10:51ㆍAI빅데이터/Study
벤치마크 점수만 믿다가 알게 된 것들 — 정확도, 오류 성격, 그리고 자원 병목
사내 상담 녹취를 처리하는 STT 엔진을 교체하면서 겪은 과정을 정리했습니다. 결론부터 말하면, 공개 벤치마크에서 가장 높은 점수를 받은 구성이 실제 녹취에서는 가장 나빴습니다. 왜 그런 일이 벌어지는지, 그리고 그 과정에서 발견한 성능 병목까지 함께 다룹니다.
1. 벤치마크는 이겼는데 실전에서 졌다
비교한 구성은 세 가지입니다. 기존 운영 중이던 레거시 구성, 현재 운영 구성, 그리고 검토 중인 신규 모델입니다.
| 구성 | Public 벤치마크 | 실제 녹취 |
| 구 VAD + 구 ETRI (레거시) | 86.8 | 81.8 |
| Silero + 신 ETRI (현행) | 90.9 | 75.0 |
| Silero + Qwen3 (검토) | 94.8 | 84.1 |
※ CER 기반 정확도 점수, 높을수록 정확
현행 구성을 보면 이상합니다. 공개 벤치마크에서는 90.9로 레거시(86.8)를 크게 앞서는데, 실제 녹취에서는 75.0으로 레거시(81.8)보다 6.8포인트나 낮습니다. 순위가 완전히 뒤집힌 겁니다.
처음엔 VAD(음성 구간 검출)를 교체한 게 원인이라고 의심했습니다. 그래서 기존 VAD로 자른 오디오를 신규 엔진에 넣어봤는데, CER 0.2532로 현행(0.2509)과 사실상 동일했습니다. VAD는 범인이 아니었습니다.
2. 같은 점수, 정반대의 오류
점수만 보면 알 수 없는 게 있습니다. 틀리는 방식입니다. STT 오류는 크게 세 종류로 나뉩니다.
• 삭제(deletion) — 말한 것을 놓침. 자막이 비어 보임
• 삽입(insertion) — 없는 말을 만들어냄. 환청에 가까움
• 대체(substitution) — 다른 말로 잘못 들음
이 셋을 나눠서 보니 그림이 완전히 달라졌습니다. (문자 기준, 띄어쓰기 제외)
| 구성 | Public 삭제 | Public 삽입 | 실녹취 삭제 | 실녹취 삽입 |
| 현행 (신 ETRI) | 4.8% | 0.4% | 16.7% | 2.3% |
| 레거시 (구 ETRI) | 0.5% | 7.3% | 5.6% | 4.9% |
| Qwen3 | 0.4% | 0.5% | 4.6% | 3.3% |
패턴이 선명합니다. 현행은 삭제 지배형, 레거시는 삽입 지배형입니다. 현행은 말한 걸 자꾸 빠뜨리고, 레거시는 없는 말을 자꾸 넣습니다.
왜 데이터셋에 따라 순위가 뒤집히는가
핵심은 각 엔진의 지배적 오류가 데이터 조건에 따라 증폭되는 방향이 정반대라는 점입니다.
Public 벤치마크는 5~7어절짜리 짧은 단문입니다. 레거시는 발화 끝마다 “예” 같은 유령 어절을 붙이는 습성이 있는데, 발화가 짧다 보니 어절 4개 중 1개가 삽입인 꼴이 됩니다. 어절 기준 삽입률이 25.6%까지 치솟습니다.
반대로 실제 통화는 깁니다. 세그먼트 수가 많아질수록 현행 엔진이 세그먼트를 통째로 누락하는 사례가 누적되고, 삭제율이 4.8% → 16.7%로 3.5배 증폭됩니다.
여담: CER은 글자 단위라 한 글자짜리 “예” 삽입의 벌점이 작습니다. 그래서 레거시의 Public 점수 86.8은 실제 문제 대비 상당히 완충된 값입니다. 어절 단위로 보면 25.6%라는 심각한 수치가 드러납니다. 지표 하나만 보면 안 되는 이유입니다.
3. 그래서 뭐가 더 나은가 — 용도에 따라 다르다
삭제와 삽입 중 무엇이 더 해로운지는 용도가 결정합니다.
| 용도 | 더 해로운 오류 | 유리한 쪽 |
| 상담사 실시간 자막 | 삭제 (누락되면 못 봄) | 레거시 |
| 기록 · 증빙 · QA | 삽입 (없는 말이 기록됨) | 현행 |
| 키워드 검색 · 통계 | 삭제 (검색 자체가 불가) | 레거시 |
즉 레거시와 현행 사이에 절대 우위는 없고, 용도별 조건부 우위만 존재합니다. 선택은 “어떤 오류를 감당할 수 있는가”로 결정해야 합니다.
한 가지 더. VAD의 패딩 설정을 무음에서 400ms 노이즈로 바꿨더니 삭제율이 16.7% → 10.8%로 크게 줄었습니다. 대신 삽입이 2.3% → 5.1%로 늘었습니다. CER 자체는 개선됐지만, 이 튜닝은 현행 구성을 레거시 쪽 성격으로 이동시키는 조정이기도 합니다.
4. CPU는 24%인데 응답이 27초
정확도 다음은 처리량이었습니다. 여기서 가장 당황스러운 현상을 만났습니다.
32콜까지는 멀쩡했습니다. 그런데 36콜로 올리는 순간 p95 응답 시간이 27초로 폭발했습니다. 그때 CPU 사용률은 24%였습니다.
원인 후보를 하나씩 지웠다
• CPU 부족 → 아님. 코어의 3/4이 놀고 있음
• 엔진 워커 부족 → 아님. 워커 24개가 전부 대기 중
• gRPC 접수 스레드 부족 → 아님. 8→24로 3배 늘려도 같은 지점에서 붕괴
• 메모리·스레드·소켓 고갈 → 아님. 부하 시 스레드 +30개뿐, RAM 여유
결정적 단서는 지연의 모양이었습니다. p50은 0.94초로 멀쩡한데 p95만 27초였습니다. 전체가 느려진 게 아니라 일부만 어딘가에 걸려 있다는 뜻입니다. 자원이 부족해서 느린 거라면 모든 요청이 골고루 느려져야 하니까요.
남은 설명은 하나였습니다. 엔진 내부에 한 번에 하나씩만 통과할 수 있는 직렬 구간(락 또는 순차 처리 큐)이 있다는 것. 8차선 도로에 톨게이트가 하나뿐인 상황입니다. 차선을 24개로 넓혀도(gRPC 스레드 증설) 소용이 없었던 게 이 비유와 정확히 맞아떨어집니다.
대기 행렬은 선형이 아니라 절벽처럼 늘어납니다. 나가는 것보다 들어오는 게 조금이라도 많아지는 순간 줄이 무한정 쌓입니다. 32콜 정상 → 36콜 붕괴가 갑작스러운 이유입니다.
5. 스레드를 늘려도 빨라지지 않는다
병목을 찾는 과정에서 스레드 할당도 실험했습니다. 직관과 다른 결과가 나왔습니다.
| 발화 1건에 준 스레드 | 단건 추론 시간 | 효율 |
| 2 스레드 (기준) | 1.11초 | — |
| 8 스레드 (4배) | 0.63초 | 1.75배 단축 (44%) |
| 16~24 스레드 | 거의 개선 없음 | 급락 |
0.6B 모델은 행렬이 작아서 스레드를 늘릴수록 코어 간 동기화와 메모리 대역폭 경합 비용이 계산 이득을 잡아먹습니다. 4배를 줘도 1.75배밖에 안 빨라지고, 그 너머는 평평합니다.
게다가 치명적인 반대급부가 있습니다. 발화 하나가 코어를 독점하면 나머지가 전부 줄을 섭니다. 실제로 정적 8스레드(3워커) 구성은 단건은 빨라도 최대 8콜에 그쳐 2스레드(12콜)보다 못했고, 과할당 실험(4프로세스 × 16스레드)은 4.6배 느려지는 최악을 기록했습니다.
교훈: 부하가 높을 때 늘려야 할 것은 스레드가 아니라, 스레드를 담을 그릇(워커 수 · 프로세스 수 · GPU)입니다.
6. 진짜 병목은 프런트였다
프런트(요청 접수·VAD·세그먼트 큐잉)와 백엔드(실제 인식)를 나눠서 재보니 답이 나왔습니다.
| 콜 수 | 프런트 | 백엔드 | 합계 | p95 |
| 32콜 | 1.13코어 | 3.96 | 5.09 | 2.31초 |
| 40콜 | 1.62 | 7.36 | 8.99 | 1.91초 |
| 44콜 | 1.80 | 7.50 | 9.30 | 2.40초 |
| 48콜 | 1.91 | 7.21 | 9.12 | 2.82초 |
백엔드가 40콜 이후 7.2~7.5코어에서 정체합니다. 일이 늘었는데 소비가 안 느는 건, 앞단이 못 흘려보내고 있다는 뜻입니다. 프런트가 단일 프로세스라 코어 하나에 묶여 있었던 겁니다.
프런트를 증설하자 32콜 p95가 2.55초에서 1.60초로 37% 단축됐고, 48콜까지 p95 2.8초대로 안정적으로 늘어났습니다.
“24코어 중 1코어만 쓰는데 왜 못 늘리나”라는 질문을 받았습니다. 단일 스레드 프로세스는 코어 하나가 물리적 천장입니다. 계산대 직원 한 명이 아무리 열심히 해도 24명이 되지는 않습니다. 필요한 건 직원을 더 뽑는 것이지 그 한 명을 더 굴리는 게 아닙니다.
7. 신규 모델은 GPU가 전제였다
검토 중이던 Qwen3는 정확도가 가장 높았지만 자원 특성이 완전히 달랐습니다.
| 환경 | 콜당 CPU | 포화 지점 | 실질 상한 |
| CPU (BF16) | 1.2 → 1.8코어 | 12콜에서 21코어 | 12~15콜 |
| GPU (L40S) | 호스트 0.18코어 | 16콜부터 GPU 99% | 36콜 |
기존 엔진의 콜당 CPU가 0.16~0.28코어인 것과 비교하면 6~9배입니다. CPU 단독 운영은 비경제적이라는 결론이었습니다.
vLLM으로 2배
그런데 실행 방식을 바꾸자 상황이 달라졌습니다. 처음엔 HuggingFace Transformers로 돌리고 있었는데, 공식 문서가 권장하는 vLLM 백엔드로 바꾸니 성능이 2배 가까이 올랐습니다.
vLLM이 빠른 이유는 세 가지입니다.
• PagedAttention — 요청마다 최대 길이만큼 메모리를 미리 잡던 방식을 OS 페이징처럼 바꿔 낭비를 60~80%에서 4% 이하로 줄임
• Continuous Batching — 배치 안에서 가장 느린 하나를 기다리지 않고, 끝난 자리에 즉시 새 요청을 투입. 꼬리 지연이 줄어듦
• 최적화된 커널 — FlashAttention, 연산 융합, CUDA 그래프 등이 기본 탑재
논문상 대표 수치는 14~24배인데 2배에 그친 건 자연스럽습니다. 모델이 0.6B로 작고 출력이 짧은 전사문이라, 커널 최적화와 KV 캐시 절약의 이득이 제한적이기 때문입니다.
정리하며
이번 과정에서 얻은 교훈을 정리하면 이렇습니다.
• 공개 벤치마크 점수는 참고치일 뿐이다. 데이터 특성이 다르면 순위가 뒤집힌다. 자기 데이터로 재봐야 한다.
• 총 오류율보다 오류의 성격이 중요하다. 같은 CER이라도 삭제형이냐 삽입형이냐에 따라 쓸 수 있는 용도가 다르다.
• 지표는 여러 단위로 봐야 한다. 문자 단위 CER은 짧은 삽입 오류를 과소평가한다. 어절 단위를 함께 보면 다른 그림이 나온다.
• 자원 여유는 처리량 상한을 보장하지 않는다. CPU 24%에서 응답이 27초로 터질 수 있다. p50과 p95를 나눠 보면 원인의 성격이 드러난다.
• 병목은 대체로 예상 밖의 곳에 있다. 인식 엔진이 아니라 그 앞단의 단일 프로세스가 전체 처리량을 묶고 있었다.
• 모델만큼 실행 방식도 중요하다. 같은 모델이라도 서빙 백엔드를 바꾸면 2배가 달라진다.
가장 크게 배운 건 “왜 그런가”를 끝까지 파고들면 결국 답이 나온다는 점이었습니다. 순위가 뒤집힌 이유를 오류 성격에서 찾았고, 지연이 터진 이유를 소거법으로 좁혔습니다. 숫자 하나를 그냥 받아들이지 않은 게 매번 다음 단계로 이어졌습니다.
'AI빅데이터 > Study' 카테고리의 다른 글
| Attention 구조 비교: MHA vs MQA vs GQA (0) | 2025.05.30 |
|---|---|
| ADSP - 과목 3 - 데이터 분석 (0) | 2024.02.23 |
| ADSP - 과목 2 - 데이터 분석 기획 (0) | 2024.02.19 |
| ADSP - 과목 1 데이터의 이해 (0) | 2024.02.16 |