COLDSURFCOLDSURF
COLDSURFB-SIDE

// Entry · Engineering

모델을 바꾸지 마세요, 인코딩을 바꾸세요

오선지 위에 손으로 그려진 음표들이 빼곡한 악보.
Photo: Fabian Kleiser · Unsplash

서강대 아트&테크놀로지에서 나온 논문 하나(육룡이 나르샤 궁중음악 AI 복원)를 주말에 직접 돌려봤어요. 진짜 무기는 신형 모델이 아니라 정간보식 인코딩이었죠. 그걸 한국 장단으로 축소해 재현하다 두 번 틀렸고, Python과 TypeScript로 각각 돌린 끝에 "인코딩의 이득은 학습 난이도에 달렸다"는 걸 손으로 확인한 기록이에요.

By @coldsurf2026.07.12Engineering@coldsurf사람이 직접 쓴 글

지난 글에서 서강대 아트&테크놀로지 이야기를 하며, 코드와 음악이 만나는 자리엔 아직 줄이 없다고 했어요. 그런데 손가락으로 지도만 가리키고 끝내면 그건 여전히 남 얘기잖아요. 그래서 이번엔 그 학과에서 나온 논문 한 편을 골라, 주말에 제 노트북에서 직접 돌려봤어요.

고른 논문은 이거예요. 〈Six Dragons Fly Again〉 (arXiv 2408.01096). 서강대 아트&테크놀로지·AI과와 KAIST, 킹스칼리지 런던이 함께 쓴 글이고요. 15세기 세종 때 만들어졌다가 악보만 남고 연주가 끊긴 궁중음악 두 곡 — 『용비어천가』("육룡이 나르샤")에 붙은 치화평과 취풍형 — 을 AI로 되살려, 국립국악원 정악단이 실제로 무대에 올린 프로젝트예요.

제목만 보면 "AI가 옛 음악을 복원했다"는 낭만적인 이야기 같죠. 그런데 논문을 열어 진짜 심장을 들여다보면, 거긴 음악학이 아니라 표현(representation)의 문제가 앉아 있어요. 그리고 그 지점이 개발자인 저에게 곧장 말을 걸었어요.

논문의 진짜 무기는 모델이 아니었어요

먼저 오해부터 걷어낼게요. 이 논문이 대단한 건 무슨 신비한 신형 모델을 만들어서가 아니에요. 오히려 그 반대예요. 저자들이 쓴 건 우리가 다 아는 그 표준 트랜스포머예요. BERT류 마스킹 모델과 encoder-decoder, 요즘 흔한 그 구조들이요.

승부처는 딴 데 있었어요. 바로 인코딩이에요.

전통 악보인 정간보는 서양 악보와 셈법이 달라요. 서양은 음의 길이를 온음표·점음표처럼 별도 기호로 적죠. 정간보는 한 칸(정간) 안에서 음표가 놓인 위치가 곧 리듬이에요. 저자들은 이 구조를 그대로 살려서, 음의 길이를 별도 토큰이 아니라 0부터 15까지의 위치 값으로 표현했어요. 이렇게 하니 길이와 관련된 어휘(vocabulary)가 확 줄고, 학습 데이터가 극도로 적은데도 모델이 잘 배웠고요.

한 문장으로 줄이면 이래요. 모델은 갖다 썼고, 데이터를 어떻게 적느냐로 이겼다. LLM 파인튜닝을 해본 사람이라면 익숙한 이야기죠. 모델보다 토크나이징과 표현이 결과를 가르는 그 감각이요.

이 한 문장이 진짜인지, 저는 믿기보다 확인하고 싶었어요.

그래서 장단으로 축소해봤어요

궁중음악 전곡을 다룰 순 없으니, 문제를 작게 잘랐어요. 소재는 한국 장단 — 굿거리, 자진모리, 세마치, 그리고 박이 비대칭인 엇모리(3+2+3+2)까지 네 종류를 골랐어요. 정간보의 "칸 안 위치 = 리듬"만 리듬에서 순수하게 떼어낸 거죠. 데이터는 손으로 34개를 적었어요. 적다는 게 흠이 아니라, 그게 바로 논문이 처했던 "데이터가 없는" 조건을 재현하는 거예요.

그리고 같은 데이터를 두 가지 방식으로 적었어요. 이게 이 실험의 전부예요.

  • v1 (길이식): deong d2 gideok d1 kung d2 … — 서양식으로 음마다 지속 길이를 붙여요. 박 경계가 없어요.
  • v2 (위치식): |3 p0 deong p2 kung |2 p0 deok p1 kung … — 논문처럼 칸 경계(|3)와 칸 안 위치(p0)를 명시해요.

엇모리 한 마디를 두 방식으로 나란히 놓으면 차이가 눈에 보여요.

v1: deong d2 kung d1 deok d1 kung d1 deong d2 gideok d1 deok d1 kung d1
v2: |3 p0 deong p2 kung  |2 p0 deok p1 kung  |3 p0 deong p2 gideok  |2 p0 deok p1 kung

v1엔 박이 어디서 끊기는지 아무 표시가 없어요. 모델이 "장단답게" 만들려면 길이의 합이 3+2+3+2가 되도록 스스로 외워야 하죠. v2엔 |3 |2가 토큰으로 박혀 있고요. 나머지는 똑같아요. 모델도, 데이터도, 학습 스텝도, 시드도 전부 고정하고 — 딱 인코딩 하나만 바꿔서 각각 밑바닥부터 학습시켰어요.

첫 번째로 틀렸어요 — 어휘는 줄지 않았어요

논문의 핵심은 "위치 인코딩 → 어휘 축소"였잖아요. 그래서 저는 당연히 v2의 어휘가 더 작을 줄 알았어요. 돌려보니 반대였어요.

v1(길이식) 어휘 = 8    v2(위치식) 어휘 = 10

v2가 오히려 더 컸어요. 이유는 금방 나왔어요. 논문의 어휘 폭발은 음 길이가 온음표부터 잘게 쪼갠 음표까지 범위가 넓어서 생긴 거예요. 그런데 장단은 타점이 촘촘해서 지속 길이가 기껏 d1~d3밖에 안 나와요. 길이 토큰이 애초에 몇 개 안 되니, 그걸 위치로 바꿔봤자 줄어들 게 없죠. 오히려 v2는 칸 경계와 위치 토큰이 더 붙어서 커졌고요.

순진한 가정 하나가 데이터한테 깨진 거예요. "정간보식 = 무조건 어휘 이득"은 틀렸어요.

두 번째로 틀렸어요 — 그 대신 세운 가설도요

그럼 v2의 이점은 뭘까. 어휘가 아니라 구조라고 다시 가설을 세웠어요. v2엔 박 경계가 명시돼 있으니, 생성할 때 박 구조를 덜 깨뜨릴 거라고요. 특히 비대칭인 엇모리에서요.

두 모델에서 온도(temperature)를 올려가며 각각 200개씩 장단을 생성하게 했어요. 여기서 온도는 모델이 생성을 얼마나 모험적으로 하게 만들지 정하는 손잡이예요. 낮으면 배운 걸 거의 그대로 재생하고, 높이면 확률이 낮은 토큰까지 과감히 집어 새 조합을 시도하는 대신 실수도 늘죠. 그렇게 만들어진 게 유효한 장단 길이(9·10·12박)에 드는지 세어봤어요. 결과는 이랬어요.

온도 2.0에서 유효율:  v1  72%    v2  66.5%

고온에서 오히려 v1이 더 잘 지켰어요. 가설이 또 기각된 거죠. 이유 역시 명확했어요. v2는 토큰이 많아서(칸·위치가 다 붙으니) 시퀀스가 길고, 그만큼 샘플링에서 토큰 하나가 어긋날 기회가 많아요. 구조를 명시한 대가로 실수할 표면이 넓어진 거예요.

여기까지가 파이썬으로 낸 결론이었어요. 논문 주장이 이 장단 레짐에선 깔끔하게 재현되지 않는다. 김빠지는 결과 같죠. 그런데 저는 이게 실험이 준 진짜 선물이라고 생각해요. "왜 재현이 안 되는가"를 알게 됐으니까요. 위치 인코딩의 이득은 무조건이 아니라, 음 길이 범위가 넓고 성부가 복잡한 논문의 그 조건에서만 나는 거였어요.

그런데 TypeScript로 다시 돌리니 이야기가 달라졌어요

여기서 멈출 수도 있었는데, 같은 파이프라인을 TypeScript로 한 번 더 포팅했어요. 순수 TS로 인코딩·데이터·지표를 짜고, 학습만 @tensorflow/tfjs-node로요. 인코딩 부분은 파이썬과 바이트 단위로 똑같이 나왔어요(패턴 34개, 어휘 8/10, 왕복 검증 실패 0). 그런데 학습 모델은 파이썬 쪽보다 일부러 더 작고 약하게 뒀거든요.

그 약한 모델에서, 파이썬에선 안 보이던 게 나타났어요.

온도 1.0 유효율          v1        v2
파이썬(강한 모델)        100%      99.5%   ← 차이 없음
TypeScript(약한 모델)    61.5%     90%     ← v2 확실히 우위

약한 모델은 v1에서 박 구조가 무너져 내렸는데(61.5%), v2는 칸 경계가 토큰에 박혀 있어서 약한 모델로도 구조를 붙들었어요(90%). 즉 학습이 어려울수록, 모델이 빈약할수록, 위치 인코딩의 구조적 뼈대가 더 중요해진다는 거예요. 파이썬의 강한 모델은 어느 인코딩이든 다 외워버려서 차이가 안 났던 거고요.

두 구현을 나란히 놓으니, 한쪽만으론 안 보이던 문장이 드러났어요. 인코딩의 효과는 학습 난이도에 달려 있다. 논문이 데이터가 적은 상황에서 좋은 인코딩을 강조한 그 방향이, 약한 모델 축에서 다시 살아난 셈이에요.

그래서 무엇이 남았나요

세 가지를 가지고 나왔어요.

첫째, 모델을 더 키우기 전에 데이터를 다르게 적어보세요. 요즘은 문제가 안 풀리면 반사적으로 더 큰 모델을 떠올리죠. 그런데 이 논문도, 제 실험도 같은 말을 해요. 승부는 자주 모델이 아니라 표현에서 나요. 도메인이 이미 가진 표기법 — 정간보든, 여러분 업무의 그 이상한 사내 포맷이든 — 을 모델이 먹기 좋게 번역하는 일, 거기에 시간을 쓰는 게 남는 장사예요.

둘째, '무조건'은 없고 '언제'만 있어요. 위치 인코딩이 좋다는 것도 조건부였어요. 데이터가 어떤 모양인지, 모델이 얼마나 약한지에 따라 이득이 나기도 사라지기도 했죠. 기술을 격언으로 외우지 말고, 자기 데이터에서 조건을 확인하는 습관. 그게 병렬이 아니라 번역이에요.

셋째, 재현은 실패해도 정직하면 남는 게 있어요. 저는 예상을 두 번 틀렸고, 논문 결론을 깨끗이 재현하지도 못했어요. 그런데 그 과정에서 "언제 이 인코딩이 이득인가"라는, 논문 요약만 읽어선 절대 안 나올 감각을 얻었어요. 남의 결론을 외우는 것과, 그 결론이 무너지는 자리를 손으로 만져보는 건 전혀 다른 앎이거든요.

지난 글이 "코드로 음악을 다루는 자리가 있다"는 지도였다면, 이번 글은 그 자리에 실제로 발을 한 번 디뎌본 기록이에요. 대단한 결과는 아니에요. 주말에 노트북 하나로 논문을 열고, 작게 잘라, 직접 돌려보고, 두 번 틀린 이야기죠. 그런데 바로 그게 융합이 시작되는 방식이에요. 논문을 읽고 감탄하는 데서 멈추지 않고, 열어서 돌려보고, 자기 데이터에서 다시 묻는 것.

여러분도 관심 있는 그 논문, 한번 열어서 돌려보세요. 틀려도 괜찮아요. 틀린 자리가 제일 많이 가르쳐 주거든요.

Comments

텍스트만 입력해 주세요. 제3자 저작권을 침해하는 인용·이미지·가사 전문은 *내려질 수 있습니다*. 권리자 또는 독자의 요청은 imcoldsurf@gmail.com 으로 보내 주세요.

댓글을 남기려면 로그인하세요.

// More entries