input → 사전학습 모델 → output — AI 추론의 본질은 이 한 줄이다
STFT도 마스킹도 잊어라 — 모델이 하는 일은 딱 하나, 입력을 받아 출력을 내는 것
핵심: 신경망이 하는 일은 딱 한 줄이다
음원 분리 파이프라인을 다시 보자:
song.mp3
↓ torchaudio.load() ← 파일 읽기 (수학)
↓ torch.stft() ← 푸리에 변환 (수학)
↓ .abs() / .angle() ← 복소수 분리 (수학)
↓ model(magnitude) ← ★ 여기만 신경망 ★
↓ magnitude × mask ← 행렬 곱셈 (수학)
↓ × exp(j × phase) ← 복소수 복원 (수학)
↓ torch.istft() ← 역 푸리에 변환 (수학)
vocals.wav
model(magnitude) — 이 한 줄이 신경망을 사용하는 유일한 부분이다.
나머지는 전부 결정적인 수학 연산이다. 같은 입력을 넣으면 같은 출력이 나온다. 학습이 필요 없고, 파라미터도 없다.
신경망이 하는 일: "이 주파수×시간 위치가 보컬일 확률"을 출력하는 것. 그게 전부다. 모델이 80MB든 913MB든, 하는 일의 본질은 같다.
패턴: input → model → output
모든 AI 추론은 이 구조다:
output = model(input)
사전 훈련된 모델을 불러오고, 입력을 넣고, 출력을 받는다. 아래 5가지 예제 전부 이 패턴이다.
예제 1: 숫자 이미지 분류 (가장 단순)
input: 손글씨 숫자 이미지 (28×28 픽셀)
model: 사전 훈련된 CNN
output: 0~9 중 어떤 숫자인지
import torch
import torch.nn as nn
from torchvision import datasets, transforms
# 1. 사전 훈련된 모델 정의 + 가중치 로드
class SimpleNet(nn.Module):
def __init__(self):
super().__init__()
self.flatten = nn.Flatten()
self.fc = nn.Sequential(
nn.Linear(28*28, 128),
nn.ReLU(),
nn.Linear(128, 10) # 10개 클래스 (0~9)
)
def forward(self, x):
return self.fc(self.flatten(x))
model = SimpleNet()
# 실제로는 torch.load("pretrained.pt")로 가중치를 불러온다
# 여기서는 구조만 보여주기 위해 생략
model.eval()
# 2. input 준비
test_data = datasets.MNIST('.', download=True, train=False,
transform=transforms.ToTensor())
image, label = test_data[0] # 28×28 이미지 1장
# 3. ★ 이 한 줄이 전부 ★
with torch.no_grad():
output = model(image.unsqueeze(0)) # [1, 10] — 각 숫자의 점수
predicted = output.argmax(dim=1).item()
print(f"input: 28×28 이미지 → model → output: {predicted} (정답: {label})")
output = model(image) — 이게 추론의 전부다.
예제 2: 오디오 분류 — "이게 무슨 소리?"
input: 오디오 파형 (1D 배열)
model: 사전 훈련된 Audio Spectrogram Transformer
output: "Dog", "Rain", "Music" 등 527개 카테고리 중 하나
from transformers import pipeline
# 1. 사전 훈련된 모델 로드 (자동 다운로드 ~350MB)
classifier = pipeline("audio-classification",
model="MIT/ast-finetuned-audioset-10-10-0.4593")
# 2. ★ input → model → output ★
result = classifier("dog_bark.wav")
# 3. output
print(result[0])
# → {'label': 'Dog', 'score': 0.9834}
내부에서 일어나는 일:
dog_bark.wav → 멜 스펙트로그램 변환 → model() → 527개 클래스 확률 → 가장 높은 것 = "Dog"
멜 스펙트로그램 변환은 수학이다. model()만 신경망.
예제 3: 음성 인식 — "뭐라고 말했어?"
input: 음성 오디오
model: 사전 훈련된 Whisper
output: 텍스트
import whisper
# 1. 사전 훈련된 모델 로드 (tiny=75MB)
model = whisper.load_model("tiny")
# 2. ★ input → model → output ★
result = model.transcribe("speech.mp3")
# 3. output
print(result["text"])
# → "안녕하세요 오늘 날씨가 좋네요"
내부에서 일어나는 일:
speech.mp3 → 멜 스펙트로그램 → model() → 토큰 시퀀스 → 디코딩 → "안녕하세요..."
model()이 스펙트로그램을 받아서 토큰(단어 조각)을 하나씩 출력한다. 토큰을 텍스트로 바꾸는 건 룩업 테이블(수학).
예제 4: 음원 분리 — "보컬만 빼줘"
input: 음악 스펙트로그램
model: 사전 훈련된 Demucs
output: 마스크 (어디가 보컬인지)
from demucs.pretrained import get_model
from demucs.apply import apply_model
import torchaudio
# 1. 사전 훈련된 모델 로드 (~80MB)
model = get_model("htdemucs")
model.eval()
# 2. input 준비
wav, sr = torchaudio.load("song.mp3")
# 3. ★ input → model → output ★
with torch.no_grad():
sources = apply_model(model, wav[None], device="cpu")[0]
# sources: [4, 2, samples] — 4개 스템
# 4. output
vocals = sources[3] # index 3 = vocals
torchaudio.save("vocals.wav", vocals, sr)
print(f"input: song.mp3 → model → output: vocals.wav")
apply_model(model, wav) 안에서 일어나는 일:
wav → 청크 분할 → STFT → model() → 마스크 → 마스크 적용 → ISTFT → 오버랩-애드
model() 호출만 신경망이고 나머지는 전부 수학.
예제 5: 음성 합성 — "이 텍스트를 읽어줘"
input: 텍스트 문자열
model: 사전 훈련된 TTS
output: 음성 파형
from TTS.api import TTS
# 1. 사전 훈련된 모델 로드 (~1.8GB)
tts = TTS("tts_models/multilingual/multi-dataset/xtts_v2")
# 2. ★ input → model → output ★
tts.tts_to_file(
text="안녕하세요",
language="ko",
file_path="hello.wav"
)
print(f"input: '안녕하세요' → model → output: hello.wav")
내부에서 일어나는 일:
"안녕하세요" → 음소 변환 → model() → 오디오 토큰 생성 → 보코더 → hello.wav
음소 변환은 규칙 기반(수학/룩업), 보코더도 신경망이지만 핵심은 model()이 텍스트에서 오디오 표현을 생성하는 것.
공통 패턴 정리
| 태스크 | input | model() | output |
|---|---|---|---|
| 이미지 분류 | 28×28 픽셀 | CNN | 0~9 확률 |
| 소리 분류 | 멜 스펙트로그램 | AST Transformer | 527개 카테고리 확률 |
| 음성 인식 | 멜 스펙트로그램 | Whisper Transformer | 토큰 시퀀스 (→텍스트) |
| 음원 분리 | 스펙트로그램 | Demucs/RoFormer | 마스크 (→분리된 음원) |
| 음성 합성 | 텍스트 (음소) | XTTS/GPT-SoVITS | 오디오 토큰 (→음성) |
전부 같은 구조다:
# 1. 모델 로드
model = load_pretrained("model_name")
# 2. 추론
output = model(input)
# 3. 후처리
result = postprocess(output)
model() 앞의 전처리(STFT, 토크나이징, 멜 변환)와 뒤의 후처리(ISTFT, 디코딩, 보코더)는 각 태스크마다 다르지만, 핵심은 항상 model(input) 한 줄이다.
사전 훈련된 모델의 파라미터(가중치)가 "어떻게 변환할지"를 이미 학습해놨기 때문에, 우리는 input만 넣으면 된다.
그래서 모델 크기가 왜 다른가
model(input) → output
이 한 줄에서 model의 크기가 다른 이유:
| 모델 | 파라미터 수 | 파일 크기 | 왜 이렇게 큰가 |
|---|---|---|---|
| MNIST CNN | ~60K | ~0.2 MB | 28×28 흑백 → 10개 숫자. 단순 |
| Whisper tiny | 39M | 75 MB | 오디오 → 텍스트. 다국어 |
| Demucs | 26.3M | 80 MB | 곡 → 4스템. 시간+주파수 처리 |
| AST | 87M | 350 MB | 오디오 → 527개 분류 |
| Whisper large | 1.5B | 3 GB | 99개 언어 지원 |
| UVR RoFormer | 84.2M | 913 MB | 리드/백킹 구분 (더 어려운 태스크) |
파라미터가 많을수록 더 복잡한 패턴을 학습할 수 있다. 근데 하는 일의 본질은 동일하다 — input을 받아서 output을 내는 것.
핵심 개념
model = load_pretrained("name") — HuggingFace/GitHub에서 사전 훈련된 가중치를 다운로드
input = preprocess(raw_data) — STFT, 토크나이징, 멜 변환 등 (전부 수학, 신경망 아님)
output = model(input) — ★ 신경망을 사용하는 유일한 부분 ★
result = postprocess(output) — ISTFT, 디코딩, 보코더 등 (전부 수학)