Post

GPU 없이 25MB로 구현하는 사람의 목소리: KittenTTS 아키텍처 딥다이브

GPU 없이 25MB로 구현하는 사람의 목소리: KittenTTS 아키텍처 딥다이브

최근 사이드 프로젝트로 라즈베리파이 5 기반의 완전 오프라인 홈 어시스턴트를 구축하면서, 제가 마주한 가장 크고 단단한 벽은 다름 아닌 TTS(Text-to-Speech) 엔진이었습니다. 현업에서 10년 넘게 온갖 시스템을 뜯어보고 연결해 본 저에게도 로컬 음성 합성의 세계는 녹록지 않았죠. STT(음성 인식)는 Whisper의 양자화 버전을 쓰면 그럭저럭 돌아가고, 두뇌 역할을 하는 LLM은 Llama.cpp를 활용해 간신히 라즈베리파이 메모리에 구겨 넣을 수 있었습니다. 문제는 ‘입’이었습니다.

기존의 선택지들을 살펴볼까요? XTTS 같은 최신 오픈소스 모델은 음질은 훌륭하지만 기본적으로 수 GB의 VRAM을 요구합니다. 애초에 GPU가 없는 환경에서는 추론 속도가 절망적인 수준으로 떨어지죠. 그렇다고 ElevenLabs나 OpenAI의 TTS API를 쓰자니, 네트워크 지연(Latency Jitter)으로 인해 대화의 맥락이 끊기고 API 호출 비용이 눈덩이처럼 불어납니다. 게다가 집안의 사적인 대화 내용이나 일정을 매번 클라우드 서버로 전송해야 한다는 프라이버시 문제도 찜찜했습니다. 결국 ‘적당히 가벼우면서도 사람처럼 말하는’ Piper TTS에 정착하는 듯했으나, 특유의 기계적인 억양과 종종 튀는 발음 때문에 아쉬움이 남았습니다. “진정 GPU 없이, 감자 같은 저사양 환경에서도 찰떡같이 돌아가는 웰메이드 로컬 TTS는 정녕 불가능한 걸까?” 하며 반쯤 포기하고 있던 찰나였습니다.

그러던 중 2026년 3월 말, v0.8 업데이트와 함께 개발자 커뮤니티에 혜성처럼 등장한 프로젝트를 발견했습니다. 이름부터 심상치 않은 KittenTTS입니다. “설마 15M 파라미터, 25MB짜리 모델이 얼마나 자연스럽겠어?”라고 코웃음을 치며 로컬 환경에 올려본 순간, 저는 제 귀를 의심할 수밖에 없었습니다. 이 녀석은 진짜였습니다.

KittenTTS의 핵심 가치 (TL;DR) KittenTTS는 단 15M(Nano)에서 80M(Mini) 파라미터를 가진 초경량 오픈소스(Apache 2.0) 음성 합성 모델입니다. GPU 없이 오직 CPU와 25MB 수준의 메모리만으로도 브라우저나 엣지 디바이스에서 클라우드 서버급의 자연스러운 24kHz 음성을 실시간으로 뽑아내는, 그야말로 ‘미친 가성비’를 자랑하는 로컬 전용 TTS 엔진입니다.

표면적인 찬사는 이쯤 해두고, 10년 차 개발자의 시선에서 도대체 이 녀석이 내부적으로 어떻게 돌아가길래 이토록 가볍고 빠른지 그 아키텍처를 밑바닥부터 뜯어보겠습니다.

KittenTTS의 근간은 음성 합성계에서 호평을 받았던 StyleTTS2 아키텍처에 뿌리를 두고 있습니다. 하지만 원본 StyleTTS2를 그대로 쓴 것이 아니라, 철저하게 ‘엣지 디바이스와 로컬 환경’을 타겟팅하여 뼈를 깎는 다이어트를 감행했습니다. 거대한 모델 가중치를 줄이기 위해 구조를 극단적으로 단순화하고, 특히 Nano 모델의 경우 Int8 양자화(Quantization)를 적용해 디스크 차지 용량을 고작 25MB 이하로 압축했습니다. 단순히 크기만 줄인 게 아닙니다. 이 모델이 텍스트를 오디오로 변환하는 과정을 살펴보면, 한정된 자원을 극한으로 짜내는 우아한 설계 철학을 엿볼 수 있습니다.

추론 파이프라인의 해부: 텍스트가 오디오가 되기까지의 6단계

KittenTTS는 단순히 텍스트를 던지면 오디오가 튀어나오는 마법의 블랙박스가 아닙니다. 모델 내부를 들여다보면 다음과 같은 치밀한 파이프라인을 거칩니다.

  1. Text Preprocessing (텍스트 정규화): 현업에서 실서비스용 TTS를 다뤄보신 분들은 공감하실 겁니다. “$99 off, 1st order” 같은 텍스트를 정제하지 않고 모델에 그대로 넣으면 파서를 망치거나 엉뚱한 발음이 나옵니다. KittenTTS는 clean_text=True 파라미터 하나로 이를 “ninety-nine dollars off, first order”로 자동 변환하는 똑똑한 텍스트 클리너를 내장하고 있습니다. 숫자는 물론 통화, 단위, 약어까지 전처리 단계에서 깔끔하게 정리해 줍니다.
  2. Smart Chunking (스마트 청킹): 긴 텍스트를 한 번에 메모리에 올리면 메모리 스파이크가 발생하거나 첫 번째 오디오 바이트가 나오기까지의 지연 시간(TTFB)이 치솟습니다. KittenTTS는 내부적으로 chunk_text() 함수를 통해 문장을 마침표(‘.’), 느낌표(‘!’), 물음표(‘?’) 기준으로 최대 400자 단위로 쪼갭니다. 만약 400자가 넘어가는 비정상적인 문장이 있다면 단어 단위로 다시 분할하죠. 이 덕분에 메모리 사용량이 극도로 예측 가능해지고, 15M 파라미터 모델이 저사양 CPU에서도 일정한 퍼포먼스를 내게 됩니다.
  3. Phonemization (음소화): 텍스트를 소리 나는 대로 변환하는 단계입니다. 여기서 KittenTTS는 오픈소스 진영의 든든한 우군인 eSpeak-ng를 파이프라인에 끌어들였습니다. 영어(en-us)를 기준으로 강세 마커와 구두점을 보존하면서 텍스트를 “həloʊ, wɜːld.” 같은 국제 음성 기호(IPA) 베이스의 음소로 변환합니다.
  4. Tokenization (토큰화): 앞서 변환된 음소 문자들은 TextCleaner를 통해 정수 ID로 매핑됩니다. 그리고 이 배열 앞뒤로 시작과 끝을 알리는 [0] 토큰이 붙어 최종적인 input_ids 텐서가 완성됩니다.
  5. Style Embedding Lookup (아키텍처의 꽃): 이 부분이 제가 KittenTTS의 설계에서 가장 감탄한 지점입니다. 보통의 거대 모델들은 다양한 목소리와 억양 특성을 모델의 가중치 내부에 전부 욱여넣습니다. 하지만 KittenTTS는 모델의 덩치를 줄이기 위해 목소리 스타일을 분리해 냈습니다. voices.npz라는 별도의 임베딩 파일에 보이스 벡터를 담아두고, 입력된 텍스트의 길이에 따라 다른 스타일 벡터를 동적으로 가져옵니다! 짧은 단답형 문장(“Yes.”)과 긴 서술형 문장의 호흡과 억양이 달라야 한다는 점을 간파한 놀라운 꼼수이자 최적화입니다. “Bella”, “Jasper”, “Rosie” 같은 보이스 파라미터는 바로 이 NPZ 파일의 특정 슬라이스를 타겟팅하는 역할을 합니다.
  6. ONNX Inference (CPU 최적화 추론): 최종적으로 준비된 토큰 텐서와 스타일 임베딩 등 3개의 입력값을 ONNX Runtime 세션에 태웁니다. 파이토치(PyTorch)의 무거운 런타임을 걷어내고, C++ 기반의 가볍고 빠른 ONNX 엔진을 사용함으로써 GPU 의존성을 완전히 끊어냈습니다. 그 결과, 라즈베리파이 같은 기기에서도 24kHz의 고품질 오디오를 실시간에 가까운 속도로 뽑아낼 수 있는 것이죠.

그렇다면 이 매력적인 기술을 당장 우리 팀의 프로덕트나 사이드 프로젝트에 어떻게 써먹을 수 있을까요? 실용적이고 파괴적인 유즈케이스 몇 가지를 제안해 보겠습니다.

A. 서버비 Zero! 100% 브라우저 기반의 TTS 익스텐션 단연코 가장 강력한 유즈케이스입니다. WebAssembly(WASM)와 transformers.js, 그리고 ONNX Runtime Web을 결합하면 유저의 웹 브라우저 내부에서 KittenTTS Nano가 직접 돌아갑니다. 백엔드 서버를 띄울 필요도, ElevenLabs에 비싼 API 비용을 낼 필요도 없습니다. 보안에 극도로 민감한 사내 문서를 읽어주는 크롬 익스텐션이나, 시각 장애인을 위한 온디바이스 웹 리더기를 기획 중이라면 이보다 완벽하고 저렴한 대안은 존재하지 않습니다. 최근에는 WebGPU 가속까지 실험적으로 지원하고 있어 브라우저 환경에서의 속도는 더욱 빨라질 전망입니다.

B. 오프라인 인디 게임을 위한 동적 NPC 보이스 생성 수만 줄에 달하는 NPC 대사를 일일이 성우를 써서 녹음하거나 클라우드 API로 실시간 생성하는 것은 인디 게임 개발자에게 엄청난 부담입니다. 게임 클라이언트에 25MB짜리 KittenTTS 모델을 번들링해 보세요. 수십 명의 NPC가 플레이어의 행동에 따라 동적으로 생성된 대사를 말하게 할 수 있습니다. 모델이 워낙 가벼워 게임의 메인 렌더링 스레드를 방해하지 않고도 비동기로 오디오 버퍼를 채워냅니다.

코드 스니펫: 파이썬에서 단 3줄로 시작하는 마법 설치도 매우 직관적입니다. 파이썬 가상환경에서 깃허브 릴리즈의 whl 파일을 직접 설치하거나 pip install을 진행한 뒤, 아래와 같이 코드를 작성하면 끝입니다.

1
2
3
4
5
6
7
8
9
10
11
12
from kittentts import KittenTTS

# 허깅페이스 허브에서 모델과 voices.npz를 자동 다운로드 (최초 1회)
# 로컬 캐시에 저장되며 이후로는 완전 오프라인으로 동작합니다.
model = KittenTTS(model_size="nano")

# 음성 생성: CPU만으로도 실시간(RTF < 1.0) 수준의 속도를 뽐냅니다.
# clean_text=True로 알아서 정규화까지 처리합니다.
audio_array = model.generate("$99 off, 1st order!", voice="Bella", speed=1.0, clean_text=True)

# 파일로 바로 저장하고 싶다면 아래 메서드를 활용하세요.
model.generate_to_file("output.wav", text="This is running locally!", voice="Jasper", speed=1.0, sample_rate=24000, clean_text=True)

하지만, 찬양 일색의 리뷰는 진짜 기술 블로그가 아니죠. 솔직히 말합시다. 10년 차 개발자로서 이 모델을 실제 상용 프로덕션에 도입하려 할 때 부딪히게 될 ‘현실적인 벽’과 단점들을 비판적으로 짚고 넘어가야겠습니다.

치명적인 단점 1: eSpeak-ng 의존성의 저주 파이썬 환경에서 패키지만 설치하면 모든 게 우아하게 끝날 줄 아셨나요? 아쉽게도 그렇지 않습니다. 내부 파이프라인에서 음소화를 담당하는 eSpeak-ng는 시스템 레벨의 C 라이브러리입니다. 리눅스(Ubuntu) 생태계라면 sudo apt install espeak-ng 한 줄로 끝나지만, Windows 환경에서 개발하거나 일반 유저를 대상으로 데스크톱 앱을 배포해야 한다면 이야기가 다릅니다. 사용자가 직접 eSpeak-ng 릴리즈 페이지에 가서 인스톨러를 다운받아 설치하고, 환경 변수까지 잡아줘야 하는 번거로움이 발생합니다. 개발자 편의성을 넘어 최종 사용자 경험(UX) 관점에서는 이 C 라이브러리 의존성을 어떻게 패키징에 숨길 것인지가 가장 큰 골칫거리가 될 것입니다.

치명적인 단점 2: ‘연기력’의 부재와 감정 표현의 한계 v0.8 업데이트로 기본 음질이 비약적으로 상승했고 24kHz의 깨끗한 출력을 자랑하지만, 감정 표현(Expressiveness)의 깊이는 여전히 한계가 명확합니다. ElevenLabs 모델이 보여주는 소름 돋는 한숨 소리, 미세하게 떨리는 목소리, 상황에 맞는 극적인 속삭임 같은 디테일한 ‘연기’를 기대한다면 실망하실 겁니다. 억양이 다소 평탄하게 느껴질 때가 있으며, 특수 기호나 괄호가 복잡하게 얽힌 문장에서는 문맥의 텐션을 잘못 파악해 로봇처럼 읽어 내려가는 현상이 종종 발생합니다. ‘정보 전달’ 목적이라면 100점이지만, ‘오디오북 감정 연기’ 목적이라면 60점 수준입니다.

단점 3: 다국어 지원의 목마름 현재(2026년 3월 기준) KittenTTS는 철저히 영어를 주력으로 설계되어 있습니다. 향후 업데이트 로드맵에 지역별 최적화 목소리와 다국어 지원 확장이 포함되어 있지만, 당장 한국어를 포함한 비영어권 언어의 유창함은 아직 완벽한 프로덕션 레벨이라고 보기 어렵습니다. 로컬라이제이션이 필수적인 글로벌 크로스보더 서비스라면 당장 전면 도입하기엔 리스크가 따릅니다.

마치며: 로컬 AI 생태계가 던지는 묵직한 메시지

이러한 단점들에도 불구하고, KittenTTS 프로젝트가 우리 개발 생태계에 시사하는 바는 실로 거대합니다. 우리는 지난 몇 년간 “더 큰 파라미터, 더 많은 GPU, 더 거대한 클라우드”라는 빅테크들의 최면 속에서 살아왔습니다. 하지만 KittenTTS는 “현실 세계의 수많은 비즈니스 문제는 거대한 클라우드 서버나 고가의 GPU 없이, 단 25MB짜리 최적화된 로컬 모델로도 충분히 훌륭하게 해결할 수 있다”는 사실을 코드와 결과물로 증명해 냈습니다.

모든 애플리케이션이 항상 초고속 네트워크에 연결되어 있을 거란 가정은 오만입니다. 프라이버시가 생명인 로컬 어시스턴트, 열악한 네트워크 환경의 오프라인 디바이스, 서버 유지비에 허덕이는 인디 서비스 분야에서 KittenTTS는 단순한 오픈소스 툴을 넘어 하나의 강력한 게임 체인저가 될 자격이 충분합니다.

이번 주말, 서랍 속에 먼지가 뽀얗게 쌓인 라즈베리파이를 꺼내 전원을 넣어보는 건 어떨까요? 그리고 그 작은 보드 위에 25MB의 목소리를 올려보세요. 어쩌면 그 조촐한 셋업이, 오랫동안 묵혀두었던 여러분의 사이드 프로젝트를 완성해 줄 마지막 퍼즐 조각이 될지도 모릅니다.

References

  • https://github.com/KittenML/KittenTTS
  • https://huggingface.co/KittenML/kitten-tts-nano-0.1
  • https://sonusahani.com/kittentts-how-to-set-up-this-25mb-ai-voice-model-locally
This post is licensed under CC BY 4.0 by the author.