회의를 녹음해 음성 인식에 넣으면 글자는 잘 나온다. 그런데 그 결과를 열어 보면 문장이 줄줄이 이어진 한 덩어리다. "그건 다음 주까지 해 주세요"라는 문장이 누구 입에서 나왔는지가 없다. 회의록으로 쓰려면 그 한 가지가 없어서 결국 사람이 다시 듣게 된다.
화자 분리(speaker diarization)는 녹음의 시간축 위에 "여기서 여기까지는 같은 사람"이라고 표시하는 일이다. 이름을 알아내는 것이 아니다. 그 파일 안에서 몇 명이 말했고 각자 어느 구간을 차지했는지만 낸다.
이름을 모르는 채로 사람을 가른다
먼저 헷갈리기 쉬운 둘을 갈라 두자.
- 화자 인식(speaker identification)은 "이 목소리가 등록된 김민수인가"를 묻는다. 미리 등록된 목소리 견본이 있어야 한다
- 화자 분리는 "이 두 구간이 같은 사람인가"만 묻는다. 등록된 것이 아무것도 없어도 된다
그래서 화자 분리가 내놓는 라벨은 화자 1, 화자 2 같은 번호다. 이 번호는 그 파일 안에서만 통한다. 같은 회의를 두 번 녹음하면 같은 사람이 한 번은 1번, 한 번은 3번이 될 수 있다. 실제 이름을 붙이려면 화자 인식을 한 겹 더 얹거나, 사람이 한 번 보고 매핑을 정해 줘야 한다.
이 구분이 중요한 이유는 개인정보 성격이 다르기 때문이다. 화자 분리 결과 그 자체는 신원 정보가 아니다. 등록된 목소리 견본을 두는 순간부터는 생체정보를 보관하는 시스템이 된다. 회의록 제품에서 대개 분리까지만 하고 이름 매핑은 사용자에게 맡기는 데는 이유가 있다.
네 걸음으로 나뉜다
전통적인 방식은 아래 네 단계를 순서대로 밟는다. 요즘 나오는 통합 모델도 안에서 하는 일은 크게 다르지 않다.
- 말 찾기. 소리가 있는 구간과 침묵을 가른다. 앞서 다룬 음성 활동 감지(VAD, voice activity detection)가 그 일을 한다 — 오디오를 짧은 프레임으로 잘라 프레임마다 사람 말소리가 있는지 판정하는 작은 모델이다. 여기서 놓친 구간은 뒤에서 절대 복구되지 않는다
- 잘게 자르기. 말이 있는 구간을 1~2초짜리 조각으로 나눈다. 보통 조금씩 겹쳐 가며 자른다
- 목소리 벡터. 조각마다 "누구 목소리인지"를 담은 벡터를 뽑는다. 이 벡터를 화자 임베딩이라 부르고, 같은 사람이면 가깝고 다른 사람이면 먼 공간에 놓이도록 학습된 모델이 만든다
- 묶기. 비슷한 벡터끼리 모아 무리를 만든다. 무리 하나가 화자 하나다
말로만 보면 평범한 군집화 문제 같다. 실제로 어려운 것은 아래 세 자리다.
몇 명인지를 모른다
군집화를 하려면 보통 무리 개수를 알려 줘야 한다. 그런데 회의 녹음을 받을 때 우리는 참석자 수를 모른다. 3명일 수도 있고 8명일 수도 있다.
그래서 이 계열은 개수를 미리 안 받는 군집화를 쓴다. 자주 쓰이는 것이 응집형 계층 군집화(agglomerative clustering)다 — 조각 하나하나를 무리로 시작해서 가장 비슷한 둘을 계속 합쳐 나가다가, 남은 무리들이 충분히 멀어지면 멈춘다. 멈추는 지점을 정하는 값이 임계값이고, 이 값 하나가 결과를 좌우한다.
임계값을 낮게 잡으면 잘 안 합쳐서 한 사람이 여러 화자로 쪼개진다. 높게 잡으면 목소리가 비슷한 두 사람이 한 명으로 붙는다. 그리고 좋은 임계값은 녹음마다 다르다. 마이크가 다르고, 방 울림이 다르고, 참석자 조합이 다르다.
실무에서 가장 값싼 해법은 임계값을 잘 맞추는 것이 아니라 개수를 아는 것이다. 화상회의 도구를 쓴다면 참석자 수를 시스템이 이미 알고 있다. 그 수를 넘겨 주는 것만으로 오류가 크게 준다. 알 수 있는데 안 알려 주고 추정하게 두는 것이 흔한 낭비다.
겹쳐 말하면 하나만 고른다
두 사람이 동시에 말하는 구간은 실제 회의에서 전체의 5~20%를 차지한다. 맞장구가 많은 한국어 대화에서는 더 높다.
문제는 위의 네 걸음이 한 조각에 화자 하나를 배정한다는 것이다. 겹친 구간의 벡터는 두 목소리가 섞인 값이라 둘 중 어느 무리에도 잘 안 맞고, 결국 하나가 배정되면서 나머지 한 사람의 발화는 통째로 사라진다. 겹침이 10%인 녹음에서는 이것만으로 오류가 10% 가까이 깔리고 시작한다.
이 자리를 다루는 방법이 셋 있다.
- 겹침 감지 모델을 따로 둔다. "여기는 두 명 이상"이라고 표시된 구간에만 두 번째 화자를 채워 넣는다. 기존 파이프라인에 얹기 쉬운 대신 감지가 틀리면 그대로 틀린다
- 소리를 먼저 분리한다. 섞인 소리를 사람별 트랙으로 갈라낸 뒤 각각 처리한다. 잘 되면 가장 깨끗하지만 분리 자체가 어렵고 무겁다
- 처음부터 여러 명을 낼 수 있게 만든다. 아래 종단형이 이쪽이다
가장 확실한 답은 사실 기술 바깥에 있다. 채널을 나눠 녹음할 수 있으면 그게 답이다. 화상회의 도구는 참가자별 오디오 트랙을 따로 갖고 있고, 그 트랙을 그대로 받으면 화자 분리 문제가 아예 없어진다. 한 방에 모여 마이크 하나로 녹음한 파일에서만 이 문제가 생긴다.
두 갈래 접근
| 군집형 | 종단형(EEND 계열) | |
|---|---|---|
| 구성 | VAD · 임베딩 · 군집을 따로 이어 붙인다 | 하나의 신경망이 오디오에서 바로 화자별 활성 구간을 낸다 |
| 겹침 | 기본적으로 못 다룬다. 별도 모듈이 필요 | 화자마다 독립 출력이라 자연스럽게 다룬다 |
| 화자 수 | 임계값으로 추정. 알려 주면 훨씬 정확 | 모델이 다룰 수 있는 최대 인원에 묶인다 |
| 학습 자료 | 임베딩 모델만 있으면 된다 | 화자 구간이 표시된 대화 녹음이 필요 |
| 긴 녹음 | 두세 시간도 문제없다 | 길이가 길어지면 나눠서 처리하고 이어 붙여야 한다 |
| 고치기 | 단계별로 끊어 보며 원인을 찾는다 | 안이 안 보인다 |
실무 제품은 대개 섞어 쓴다. 군집형으로 전체 뼈대를 잡고, 겹침이 의심되는 짧은 구간에만 종단형이나 겹침 전용 모델을 태우는 식이다. 긴 녹음에서 군집형의 안정성을 버리기 어렵기 때문이다.
DER은 세 가지를 한 숫자로 합친다
이 분야의 표준 지표는 DER(diarization error rate)이다. 틀린 시간을 전체 발화 시간으로 나눈 값이고, 안에 세 가지가 들어 있다.
셋을 합쳐 하나로 내기 때문에 같은 DER 20%라도 원인이 전혀 다를 수 있다. 누락이 대부분이면 VAD가 말을 놓치고 있는 것이고, 화자 혼동이 대부분이면 임계값이나 임베딩이 문제다. 고칠 자리가 정반대이므로 숫자를 받으면 반드시 세 조각으로 나눠 봐야 한다.
그리고 DER 수치를 비교할 때 확인해야 할 조건이 둘 있다.
- 겹침 구간을 세었는가. 겹침을 평가에서 빼면 DER이 크게 떨어진다. 겹침을 못 다루는 시스템에 유리한 조건이라, 이 조건을 안 밝힌 비교는 의미가 없다
- 경계에 여유를 뒀는가. 화자가 바뀌는 지점 앞뒤 0.25초를 채점에서 빼는 관행이 있다. 사람이 붙인 정답도 그 정도는 흔들리기 때문인데, 여유를 두면 숫자가 더 좋아진다
두 조건이 다르면 같은 시스템의 DER이 두 배 넘게 벌어진다. 논문 표의 숫자와 우리 시스템의 숫자를 직접 비교하기 전에 이 둘부터 맞춰야 한다.
음성 인식과 붙이는 자리
실제로 원하는 결과는 화자 구간이 아니라 화자가 붙은 회의록이다. 여기서 한 번 더 일이 생긴다.
음성 인식은 단어마다 시각을 함께 내줄 수 있다. 화자 분리는 구간마다 번호를 낸다. 둘을 시각으로 맞춰 단어마다 화자를 붙이면 된다 — 원리는 간단한데, 경계에서 어긋난다.
문장의 경계와 화자의 경계가 안 맞는다. 인식 결과가 "네 그러면 다음 안건으로 넘어갈게요"라는 한 문장인데, 앞의 "네"만 다른 사람의 맞장구인 경우가 흔하다. 단어 단위로 화자를 붙이면 한 문장 안에서 화자가 바뀌어 읽기가 나빠지고, 문장 단위로 붙이면 맞장구가 통째로 다른 사람 몫이 된다.
쓸 만한 절충은 이렇다.
- 문장 단위로 붙이되 다수결로 정한다. 그 문장의 단어들이 가장 많이 걸쳐 있는 화자를 그 문장의 화자로 삼는다
- 아주 짧은 조각은 흡수시킨다. 0.5초 미만이면서 앞뒤가 같은 화자면 그 화자로 합친다. 맞장구를 별도 발화로 남길지 말지는 제품이 정할 문제다
- 경계의 첫 단어 한둘은 의심한다. 화자가 바뀌는 지점 바로 앞뒤 단어는 틀릴 확률이 눈에 띄게 높다
녹음 조건이 절반이다
모델을 바꾸는 것보다 입력을 바꾸는 쪽이 효과가 큰 경우가 많다.
- 마이크와의 거리. 멀리 놓인 마이크 하나로 받은 회의는 방 울림이 목소리 특징을 흐려 임베딩이 뭉개진다. 사람마다 가까운 마이크가 있으면 문제가 거의 사라진다
- 표본 주파수. 전화 녹음은 8kHz로 잘려 있어 목소리를 가르는 고역 정보가 없다. 전화용으로 학습된 모델을 쓰는 편이 낫다
- 짧은 발화. 1초 미만 발화는 임베딩이 불안정하다. "네", "그쵸" 같은 맞장구가 많은 대화에서 오류가 몰리는 자리가 여기다
- 배경 음악과 잡음. VAD가 음악을 말로 착각하면 오검출이 쌓인다. 음악이 섞이는 자료라면 VAD부터 그에 맞는 것으로 바꾼다
정리
- 화자 분리는 "누가 언제 말했는가"를 시간축에 적는 일이다. 이름을 알아내는 화자 인식과는 다른 문제이고, 나오는 번호는 그 파일 안에서만 통한다
- 처리는 말 찾기 · 자르기 · 목소리 벡터 · 묶기의 네 걸음이다. 1단계에서 놓친 말은 뒤에서 복구되지 않는다
- 화자 수를 모르는 것이 첫 번째 어려움이다. 알 수 있으면 반드시 알려 준다 — 임계값을 손보는 것보다 훨씬 값이 좋다
- 겹쳐 말한 구간은 한 조각에 화자 하나만 배정하는 구조 탓에 통째로 오류가 된다. 회의 녹음의 5~20%가 여기다
- 채널을 나눠 녹음할 수 있으면 이 문제 전체가 사라진다. 기술로 풀기 전에 이 길이 있는지 먼저 본다
- DER은 누락 · 오검출 · 화자 혼동을 합친 값이다. 받으면 반드시 셋으로 나눠 봐야 고칠 자리가 보인다
- DER을 비교할 때는 겹침을 세었는지와 경계 여유를 뒀는지를 먼저 맞춘다. 조건이 다르면 두 배 넘게 벌어진다
- 회의록으로 합칠 때는 문장 단위 다수결로 붙이고 아주 짧은 조각은 흡수시킨다. 문장 경계와 화자 경계는 원래 안 맞는다
읽어주셔서 감사합니다. 😊

