- Supertonic์ ONNX Runtime ๊ธฐ๋ฐ์ ์จ๋๋ฐ์ด์ค(on-device) ๋ฉํฐ๋ง๊ถ TTS ์์คํ
- ํด๋ผ์ฐ๋ยทAPI ํธ์ถ ์์ด ํ ์คํธ์์ ์์ฑ์ ํฉ์ฑํ๋ ๋ก์ปฌ ์์ฑ ํฉ์ฑ ์์ง
- Supertonic 3๋ ์ต์ ๋ฒ์ ์ผ๋ก ~99M ํ๋ผ๋ฏธํฐยท31๊ฐ ์ธ์ด๋ฅผ ์ง์ํ๋ ๊ฒฝ๋ ๋ชจ๋ธ
- Flow Matching ๊ธฐ๋ฐ ์ํคํ ์ฒ๋ก ์์ ํฌ๊ธฐ์๋ ์คํ๋์ค๊ธ(44.1kHz) ์์ง์ ๋ด๋ ๊ตฌ์กฐ
- GPU ์์ด CPU๋ง์ผ๋ก ๋์ํ๋ ์ฃ์ง ๋ฐฐํฌ์ฉ ์ค๊ณ
ํด๋น ๊ฐ๋ ์ด ํ์ํ ์ด์
- ๊ธฐ์กด ์คํ TTS๋ 0.7B~2B ํ๋ผ๋ฏธํฐ๊ธ์ผ๋ก ๋ฌด๊ฒ๊ณ GPUยทVRAM์ ๋ง์ด ์๊ตฌ
- ํด๋ผ์ฐ๋ TTS API๋ ๋น์ฉยท๋คํธ์ํฌ ์ง์ฐยทํ๋ผ์ด๋ฒ์ ๋ ธ์ถ์ด๋ผ๋ ๋ถ๋ด
- ์จ๋๋ฐ์ด์ค๋ก ๋๋ฆฌ๋ ค๋ฉด ๋ชจ๋ธ ํฌ๊ธฐยท๋ฉ๋ชจ๋ฆฌยท์๋๋ฅผ ๋ชจ๋ ์ค์ฌ์ผ ํ๋ ์ ์ฝ
AS-IS (๊ธฐ์กด ๋ํ TTS / ํด๋ผ์ฐ๋ TTS)
sequenceDiagram autonumber participant App as ์ฑ participant Cloud as ํด๋ผ์ฐ๋ TTS API participant GPU as GPU ์๋ฒ(0.7B~2B) App->>Cloud: ํ ์คํธ ์ ์ก (๋คํธ์ํฌ ํ์) Cloud->>GPU: ๋ํ ๋ชจ๋ธ ์ถ๋ก (VRAM ๅค) GPU-->>Cloud: ํฉ์ฑ ์์ฑ Cloud-->>App: ์์ฑ ๋ฐํ (์ง์ฐยท๋น์ฉยทํ๋ผ์ด๋ฒ์ ๋ ธ์ถ)
TO-BE (Supertonic 3 ์จ๋๋ฐ์ด์ค)
sequenceDiagram autonumber participant App as ์ฑ participant TTS as Supertonic 3 (~99M, ONNX) participant CPU as ๋ก์ปฌ CPU App->>TTS: ํ ์คํธ ์ ๋ ฅ TTS->>CPU: ๊ฒฝ๋ ๋ชจ๋ธ ์ถ๋ก (GPU ๋ถํ์) CPU-->>TTS: latent โ 44.1kHz WAV TTS-->>App: ์์ฑ ๋ฐํ (์คํ๋ผ์ธยท์ ์ง์ฐยทํ๋ผ์ด๋ฒ์ ๋ณด์กด)
์ํคํ ์ฒ 3๋จ ๊ตฌ์ฑ
Flow Matching ๊ธฐ๋ฐ์ผ๋ก ํ
์คํธ๋ฅผ ์์ฑ์ผ๋ก ๋ฐ๊พธ๋ ์ธ ๋ชจ๋๋ก ๊ตฌ์ฑ๋๋ค. ์ค์ ๋ก๋ ๋จ์ผ ํ์ผ์ด ์๋๋ผ ์ฌ๋ฌ ๊ฐ์ .onnx ๋ชจ๋์ด ๋จ๊ณ๋ณ๋ก ONNX Runtime ์์์ ์คํ๋๋ฉฐ, ๊ทธ ์๋จ์ ํ
์คํธ ์ ์ฒ๋ฆฌ์ voice style ์๋ฒ ๋ฉ์ด ๊ฒฐํฉ๋๋ค.
- Speech Autoencoder โ ์ค๋์ค๋ฅผ ์ ์ฌ(latent) ํํ์ผ๋ก ์ธ์ฝ๋ฉยท๋์ฝ๋ฉ
- Text-to-Latent ๋ชจ๋ โ Flow Matching์ผ๋ก ํ ์คํธ๋ฅผ ์ํฅ ์ ์ฌ ํํ์ผ๋ก ๋ณํ
- Vocoder โ ์ ์ฌ ์ฝ๋๋ก๋ถํฐ 44.1kHz ์ค๋์ค๋ฅผ ๋ณต์
flowchart LR T["ํ ์คํธ ์ ๋ ฅ<br/>(+ ํํ ํ๊ทธ)"] --> P[ํ ์คํธ ์ ์ฒ๋ฆฌ] V["voice style<br/>์๋ฒ ๋ฉ (M1 ๋ฑ)"] --> M2 P --> M2["text-to-latent.onnx<br/>(flow matching, total_steps)"] M2 --> M3["vocoder.onnx"] M3 --> W["44.1kHz WAV ์์ฑ"] subgraph RT["ONNX Runtime (CPU/๋ธ๋ผ์ฐ์ )"] M2 M3 end
from supertonic import TTS์ TTS ๊ฐ์ฒด๊ฐ ์ด ONNX ๋ชจ๋๋ค์ ONNX Runtime์ผ๋ก ๊ตฌ๋ํ๋ ๋ํผ(wrapper)๋ค. ์ฌ์ฉ์๋ ONNX ํ์ผ์ ์ง์ ๋ค๋ฃจ์ง ์๊ณ tts.synthesize(text, ...) ํ ์ค๋ก TTS๋ฅผ ์ด๋ค.
CPU๋ง ์ฐ๋๊ฐ? โ โGPU ๋ถํ์(CPU๋ก ์ถฉ๋ถ)โ
Supertonic 3๋ GPU ์์ด CPU๋ง์ผ๋ก ๋์ํ๋๋ก ์ค๊ณ๋ ๊ฒ์ด ํต์ฌ์ด๋ค. ์ค์ ๋ก CPU ์ถ๋ก ์ด A100 GPU์์ ์ธก์ ํ ๋ ํฐ ๋ชจ๋ธ๋ค๋ณด๋ค๋ ๋น ๋ฅธ ์ง์ฐ์๊ฐ์ ๋ด๊ณ ๋ฉ๋ชจ๋ฆฌ๋ ํจ์ฌ ์ ๊ฒ ์ด๋ค. ๋ค๋ง โCPU ์ ์ฉโ์ ์๋๋ค. ๋ฐ๋จ์ด ONNX Runtime์ด๋ฏ๋ก GPU๊ฐ ์์ผ๋ฉด CUDA ๊ฐ์ Execution Provider๋ ๋ธ๋ผ์ฐ์ ์ WebGPU๋ก GPU ๊ฐ์๋ ์ ํ์ ์ผ๋ก ํ์ฉํ ์ ์๋ค. ์ฆ โGPU๊ฐ ํ์๊ฐ ์๋๋คโ๊ฐ ์ ํํ ํํ์ด๋ค.
Supertonic์ด ๊ธฐ๋ฐํ ๋ ผ๋ฌธ 3๊ฐ
| ๋ ผ๋ฌธ | ์ญํ |
|---|---|
| SupertonicTTS | ์ ์ฒด ์ํคํ ์ฒ์ ํจ์จ์ ์ค๊ณ |
| Length-Aware RoPE | cross-attention์์ ํ ์คํธ-์์ฑ ์ ๋ ฌ(alignment) ๊ฐ์ |
| Self-Purifying Flow Matching | ๋ ธ์ด์ฆ ์๋ ๋ผ๋ฒจ๋ก ํ์ตํ ๋ ์์ ํ |
๋ฒ์ ๋น๊ต
| ๋ฒ์ | ์ํ | ํ๋ผ๋ฏธํฐ | ์ธ์ด | ํต์ฌ ํน์ง |
|---|---|---|---|---|
| Supertonic 3 | ์ต์ | ~99M | 31 | ํํ ํ๊ทธยท๋ฉํฐ๋ง๊ถ |
| Supertonic 2 | ์์ | ~66M | 5 | ๊ธฐ๋ฐ ๋ฆด๋ฆฌ์ค |
| Supertonic 1 | ๋ ๊ฑฐ์ | ~66M | 1 (์์ด) | ์ต์ด ๋ฒ์ |
์ฃผ์ ๊ธฐ๋ฅ
- ํํ ํ๊ทธ(Expression Tags):
<laugh>,<breath>,<sigh>๋ฑ 10์ข ์ ์ธ๋ผ์ธ์ผ๋ก ์ฝ์ ํด ์์ฐ์ค๋ฌ์ ์ถ๊ฐ - Zero-shot ์ปค์คํ ๋ณด์ด์ค: Voice Builder๋ก ํ์ต ์์ด ์ ๋ชฉ์๋ฆฌ ์์ฑ
- ์คํ๋์ค ์์ง: 44.1kHz 16-bit WAV ์ง์ ์ถ๋ ฅ
- ๊ด๋ฒ์ํ ํ๋ซํผ SDK: Python, Node.js, Browser(WebGPU/WASM), Java, C++, C#, Go, Swift, iOS, Rust, Flutter
์ฌ์ฉ๋ฒ
from supertonic import TTS
tts = TTS(auto_download=True)
style = tts.get_voice_style(voice_name="M1")
wav, duration = tts.synthesize(
text="Supertonic is lightning fast TTS.",
lang="en",
voice_style=style,
total_steps=8, # ํ์ง: 5-12 (= flow matching ODE ์คํ
์)
speed=1.05 # ์๋: 0.7-2.0
)
tts.save_audio(wav, "output.wav")