Voxtral TTS, 왜 주목해야 할까?
최근 Mistral이 공개한 Voxtral-4B-TTS는 40억 개의 파라미터를 가진 TTS 모델로, LLM 기반의 오토리그레시브 백본(Ministral 3B)을 사용해 음성 토큰을 생성한다. 문제는 Mistral이 오디오 오토인코더의 인코더 가중치를 공개하지 않았다는 점이다. 따라서 사용자는 Mistral이 준비한 몇 가지 음성만 사용할 수 있고, 임의의 음성을 클론할 수는 없다.
하지만 필자는 이 글에서 (1) Voxtral TTS 아키텍처의 상세 분석, (2) 오디오 오토인코더의 동작 원리, (3) 공개된 디코더와 오토리그레시브 모델만으로도 그래디언트 디센트를 통해 임의의 음성을 재구성할 수 있는 방법을 공유한다.
이 기술이 왜 중요한지 개인적인 경험을 하나 들자면, 과거 Whisper가 공개되기 전인 2021년, 필자는 Wav2Vec2 논문을 읽고 이 기술이 오디오 이해 영역의 새로운 클래식이 될 것이라고 확신했다. Voxtral TTS를 보며 똑같은 느낌을 받았다.

Voxtral TTS 아키텍처 핵심 분석
기본 구조
Voxtral-4B-TTS는 3B 백본(Ministral 3B) 위에 오디오 토큰을 생성하는 autoregressive LLM 구조를 사용한다. 입력으로는 클론할 음성을 나타내는 오디오 토큰과 발화할 텍스트 토큰을 받고, 출력으로 음성 토큰을 생성한다.
핵심 포인트는 두 가지다:
- 독립적인 오디오 토큰: 각 토큰은 80ms의 오디오를 나타내며, 겹치지 않고 독립적이다. 이 덕분에 네이티브 오디오 스트리밍이 가능하다.
- 복잡한 헤드(Head): 선형 헤드(discrete token 예측)와 flow-matching transformer(diffusion 기반 연속 분포 근사)를 결합한 구조다. 이는 현재 오디오 생성의 두 가지 주요 접근법(이산 토큰 예측 + 확산 모델)을 하나로 합친 것이다.
오디오 오토인코더: Voxtral Codec
Voxtral Codec은 350M 파라미터의 오토인코더로, 80ms 오디오 프레임당 37개의 이산 토큰을 생성한다. 구조는 Encoder -> Bottleneck -> Decoder의 전형적인 오토인코더 형태지만, Mistral은 Encoder 가중치를 공개하지 않았다.
병목(Bottleneck)에서 생성되는 두 가지 토큰 타입은 다음과 같다:
- Semantic Token (256차원): Vector Quantization(VQ)을 통해 8192개의 코드북 중 하나로 매핑된다. Whisper 디코더의 latent state와 정렬되도록 학습되어, 의미(semantics)와 연관된다.
- Acoustic Token (36개의 스칼라): Finite Scalar Quantization(FSQ)을 통해 0~21 사이의 정수로 양자화된다. 음색(voice) 자체를 표현한다.
# Voxtral Codec의 FSQ 양자화 예시 (vllm-omni 기반)
import torch
import torch.nn.functional as F
# 설정: 36개 차원, 각 22레벨 (0~21)
num_frames = 100 # 예시 프레임 수
acoustic_levels = 22
# 연속 값 (인코더 출력에서 분할된 36차원)
continuous_values = torch.randn(num_frames, 36) # [-inf, +inf]
# Scaled Tanh로 [-1, 1]로 매핑
normalized = torch.tanh(continuous_values)
# [0, 1] -> [0, 21] 스케일링 후 반올림 (양자화)
scaled = ((normalized + 1) / 2) * (acoustic_levels - 1)
quantized = scaled.round().long() # 이산 코드
print(f"양자화된 코드 shape: {quantized.shape}") # [100, 36]
print(f"코드 범위: {quantized.min().item()} ~ {quantized.max().item()}")
Semantic Token은 정말 의미를 담을까?
필자가 궁금했던 점: semantic token이 실제로 발화할 단어(의미)를 결정하고, acoustic token이 음색을 결정할까?
실험 결과는 **'아니오'**였다. Semantic token을 무작위로 변경해도 음성이 깨지지 않고 유지되었으며, 오히려 음색이 변하는 현상이 관찰되었다. 즉, semantic token은 이름과 달리 의미를 명확히 분리하지 못하며, 음성 생성에 있어 두 토큰이 복합적으로 작용한다.
인코더 없이 음성 복원하기: 그래디언트 디센트 접근법
핵심 아이디어
인코더가 없으므로, 디코더와 오토리그레시브 백본만으로 임의의 오디오에 대한 코드를 직접 학습시키는 방법을 고안했다. 즉, 코드 자체를 nn.Parameter로 초기화하고, 원본 오디오와의 재구성 손실을 최소화하도록 학습한다.
이산 토큰의 도전과제
이산 토큰은 LLM의 토큰과 유사하게, A에서 B로 점진적으로 최적화할 수 없다. 이를 해결하기 위해 **Straight-Through Estimator (STE)**를 사용한다.
Acoustic Token (FSQ) 학습:
# 학습 가능한 acoustic 코드 (연속 값으로 초기화)
self.acoustic_values = nn.Parameter(torch.randn(num_frames, 36))
# Forward: 양자화된 이산 값을 사용, Backward: 연속 값을 통해 그래디언트 전달
acoustic_normalized = torch.tanh(self.acoustic_values)
acoustic_scaled = ((acoustic_normalized + 1) / 2) * (acoustic_levels - 1)
acoustic_quantized = acoustic_scaled.round()
# STE: forward는 quantized, backward는 continuous
acoustic_codes = acoustic_scaled + (acoustic_quantized - acoustic_scaled).detach()
Semantic Token (VQ) 학습:
# 학습 가능한 로짓 (8192개 코드북 중 선택)
semantic_vocab = 8192
self.semantic_logits = nn.Parameter(torch.randn(num_frames, semantic_vocab))
# Soft 확률 (그래디언트 전달용)
probs = F.softmax(self.semantic_logits, dim=-1) # [T, 8192]
# Hard 선택 (Forward pass)
hard_codes = probs.argmax(dim=-1) # [T] 정수 인덱스
# 임베딩 테이블 조회 (실제 코드북 사용)
sem_embedding = tokenizer.quantizer.semantic_codebook.embedding # [8192, 256]
# Soft 임베딩 (그래디언트용)
soft_emb = torch.matmul(probs, sem_embedding) # [T, 256]
# Hard 임베딩 (Forward용)
hard_emb = F.embedding(hard_codes, sem_embedding) # [T, 256]
# STE: forward는 hard, backward는 soft
semantic_emb = soft_emb + (hard_emb - soft_emb).detach() # [T, 256]
손실 함수 설계
고주파 오디오 신호를 복원하기 위해서는 단순 L1 Loss만으로는 부족하다. 다음과 같은 추가 손실을 적용했다:
- L1 재구성 손실: 시간 도메인에서의 파형 차이
- STFT 손실: 주파수 도메인에서의 차이 (Mistral 논문 참고, 8개 STFT 크기 사용)
- Speaker Embedding 손실: SpeechBrain의 speaker embedding 모델을 사용하여 화자 유사도 보존
# STFT 손실 예시 (간소화)
def stft_loss(pred_audio, target_audio, fft_size=512):
# Short-Time Fourier Transform
pred_spec = torch.stft(pred_audio, n_fft=fft_size, return_complex=True)
target_spec = torch.stft(target_audio, n_fft=fft_size, return_complex=True)
# L1 손실 on magnitude spectrogram
loss = F.l1_loss(torch.abs(pred_spec), torch.abs(target_spec))
return loss
실험 결과
약 8초 분량의 단일 샘플에 대해 5000 에폭 학습(약 1시간, Mac M 시리즈) 결과, 원본과 매우 유사한 음성을 복원할 수 있었다. Speaker diarization 손실을 추가하면 학습 속도는 느려지지만 최종 음질이 개선되었다.
참고: 이 실험은 단일 샘플에 대한 과적합(overfitting)이 목적입니다. 즉, 학습 파라미터가 해당 오디오를 완벽히 재현하도록 하는 것이 목표입니다.

주의사항 및 한계
-
과적합 기반 접근법: 이 방법은 단일 오디오 샘플에 과적합되는 방식이므로, 실시간 음성 클로닝에는 부적합하다. 실제 서비스에 적용하려면 더 효율적인 인코더 학습이 필요하다.
-
계산 비용: 8초 오디오에 1시간이 소요되므로, 긴 오디오나 대량 처리에는 적합하지 않다.
-
음질 한계: STE를 통한 근사적 그래디언트 전달로 인해, 원본 인코더를 사용한 경우보다 음질이 저하될 수 있다.
-
법적/윤리적 고려사항: 음성 복제 기술은 동의 없는 사용 시 심각한 윤리적 문제를 야기할 수 있다. 반드시 합법적이고 윤리적인 범위 내에서만 사용해야 한다.
함께 보면 좋은 글

결론: Voxtral TTS, 이렇게 활용하자
Voxtral TTS는 오디오 생성 분야의 새로운 패러다임을 제시한다. 비록 인코더 가중치가 공개되지 않아 제한적이지만, 본 글에서 소개한 그래디언트 디센트 기반 코드 재구성 접근법을 통해 연구 및 실험에 활용할 수 있다.
실무 적용을 위한 조언:
- 연구 목적: 아키텍처 이해와 음성 토큰의 특성 분석에 유용
- 프로토타이핑: 제한된 음성 세트로 TTS 프로토타입 제작 가능
- 향후 학습 방향: Voxtral Codec과 유사한 구조의 오토인코더를 직접 학습하는 방법을 연구해보는 것을 추천
AI 도구(LLM)를 활용한 연구는 생산성을 크게 높여주지만, ML/DL 세부 사항에서는 사람의 판단이 여전히 중요하다. AI를 도구로 사용하되, 결과를 비판적으로 검토하는 습관을 기르자.