본문 바로가기
C.W.K.
Stream
Lesson 04 of 04 · published

결정은 귀가 해

~12 min · listening-tests, model-choice, voice-design, judgment

Level 0음소거
0 XP0/35 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"Model quality bar: Dad's ears." — 음성 엔진 제공자 정책의 제목

새것이 곧 판결은 아니야

Eleven v4는 공개 음성 순위표 맨 위에 올라서 나왔고, 피파와 아빠 목소리는 하루 만에 그리로 옮겨 갔어. 그러니 가족의 모든 목소리가 따라가야 한다고 결론 내리기 쉬워. 안 그랬어. 그 이유가 이 레슨이야. 음성 엔진의 정책은 품질 기준을 쉬운 말로 적어 둬. 아빠의 귀. 그리고 그 귀가 나머지에겐 아니라고 했어.

같은 날 밤 음성 엔진에 디자이너가 생겼어. 녹음을 복제하는 대신, 제공자의 음성 디자인 도구로 설명을 주고 새 소울 목소리를 만드는 작업실이야. 아빠가 그 디자인 도구의 v3 세대로 만든 후보들을 들어보니, 연기가 과하고 음색이 캐릭터보다 어리게 들렸어. 그때 공개 API는 음성 디자인을 v3 세대까지만 열어 두고 있어서, 더 새로운 걸 해볼 수도 없었어. 그래서 결정은 정확했어. 새로 만든 피파와 아빠 클론은 v4를 쓰고, 다른 소울 전부와 새 프로필은 더 새로운 세대로 한 음성 디자인 실험이 다른 답을 줄 때까지 v3에 남아. 엔진은 이제 지원되는 디자인 모델 목록을 코드에 박아 두지 않고 제공자의 API 명세에서 읽어 와. 그래서 더 새로운 게 나오는 날 코드 수정 없이 바로 해볼 수 있어.

귀는 전에도 아니라고 했어

처음이 아니야. 8월에 eleven_v3와 더 빠른 대화형 변형을 같은 글로 A/B 했더니 결과가 분명했어. 대화형 테이크가 귀에 들리게 탁했고, 같은 말을 늘여서 파일도 조금 더 길었어. 그 뒤론 값도 속도도 상관없어졌고, 대화형 모델은 절대 기본값이 아니야. 더 빠른 Flash라는 모델도 밋밋하다고 제쳐 뒀고, 어차피 트랙 8에서 잰 지연 바닥 때문에 그 속도는 의미가 없어.

목소리는 둘레의 시스템을 바꿔

새 목소리는 아무도 계획 안 한 걸 하나 바꿨어. v4는 더 표현력이 있어서 가끔 답을 큰 웃음으로 시작해. 웹에선 아빠가 끼어들 수 있게 피파가 말하는 동안에도 마이크가 열려 있는데, 끼어들기 감지기가 그 웃음을 아빠로 듣고 숨 중간에 피파를 멈췄어. 고친 방법은 피파 목소리가 시작되는 짧은 유예 창이었고, 그날 밤 바로 나갔고, 트랙 7의 세 번째 레슨 주제야. 목소리는 떼어서 갈아 끼우면 끝나는 부품이 아니야. 그 근처에서 듣는 건 전부 다시 확인해야 해.

조율은 계속돼

모델과 클론을 고른 건 시작이지 끝이 아니야. 안정성 같은 설정, 말 턴이 오디오 태그를 얼마나 자유롭게 쓰는지도 목소리가 어떻게 들리는지를 똑같이 좌우해. 이 퀘스트를 쓴 날에도 그 조율은 계속되고 있었어. 귀로, A/B 한 번씩.

Code

눈 가린 A/B 한 판: 섞은 테이크, 선택이 먼저, 이름은 마지막·python
import random
from collections import Counter


def blind_round(takes: dict[str, list[str]], choose, seed: int) -> Counter:
    """takes: arm -> list of files for the SAME sentences, in the same order.

    The listener hears two unlabeled takes of one sentence at a time and
    picks one. Labels are revealed only after every choice is made.
    """
    rng = random.Random(seed)
    arms = list(takes)
    wins = Counter()
    for index in range(len(next(iter(takes.values())))):
        for a in range(len(arms)):
            for b in range(a + 1, len(arms)):
                pair = [arms[a], arms[b]]
                rng.shuffle(pair)                        # order must not leak the arm
                picked = choose(takes[pair[0]][index], takes[pair[1]][index])
                wins[pair[picked]] += 1
    return wins


takes = {
    "v3-clone/v3": ["a1.mp3", "a2.mp3"],
    "v3-clone/v4": ["b1.mp3", "b2.mp3"],
    "v4-clone/v4": ["c1.mp3", "c2.mp3"],
}


def listener(first: str, second: str) -> int:
    """Stand-in for a human: prefers the fresh clone, else the first heard."""
    return 1 if second.startswith("c") else 0


result = blind_round(takes, listener, seed=929)
for arm in sorted(takes, key=lambda arm: -result[arm]):
    print(f"{arm:12s} {result[arm]} wins")

External links

Exercise

눈 가린 판을 돌려보고, 대역 청취자를 명령줄에서 직접 묻는 걸로 바꿔봐(두 파일을 아무 재생기로 틀고 1이나 2를 입력). 정당하게 비교해도 되는 목소리 둘로 돌려. 이름을 밝히기 전에 어느 갈래가 이길지 적어 두고, 밝힌 다음 비교해.
Hint
대부분 한 번은 놀라. 그 놀람이 가족 정책이 순위표 대신 귀를 기준으로 적는 이유야. 눈 가린 채로 직접 듣는 것만이, 실제로 같이 살 목소리를 재는 유일한 벤치마크야.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인 — 댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.