🧠

Mel-Band RoFormer Karaoke 모델 분석 — 리드 보컬만 골라내는 913MB의 비밀

RoPE + 멜 스케일 주파수 분해 + 계층적 시간·주파수 Transformer — 코드와 설정까지

모델 파일 정보

항목
파일명 mel_band_roformer_karaoke_aufr33_viperx_sdr_10.1956.ckpt
크기 913 MB
형식 PyTorch pickle checkpoint (OrderedDict + FloatStorage)
설정 파일 config_mel_band_roformer_karaoke.yaml (1.72 kB)
호스팅 HuggingFace
SHA256 1de20d459332fe8869aeb01327a31df0032262706e1365114e852dc271779813

audio-separator 패키지가 첫 실행 시 UVR 모델 저장소에서 자동 다운로드한다.

RoFormer란 — Rotary Position Embedding

일반 Transformer는 위치 정보를 absolute position encoding이나 relative position encoding으로 처리한다. RoFormer는 RoPE(Rotary Position Embedding)를 쓴다.

RoPE는 Query와 Key 벡터를 위치에 따라 회전시킨다. 거리가 먼 토큰 간의 어텐션이 자연스럽게 감소한다. 학습된 위치 임베딩 없이도 가변 길이 시퀀스를 처리할 수 있다.

실제 코드 (mel_band_roformer.py):

from rotary_embedding_torch import RotaryEmbedding

time_rotary_embed = RotaryEmbedding(dim=64)   # dim_head=64
freq_rotary_embed = RotaryEmbedding(dim=64)

# Attention.forward() 안에서:
q = self.rotary_embed.rotate_queries_or_keys(q)
k = self.rotary_embed.rotate_queries_or_keys(k)

시간 축과 주파수 축에 각각 별도의 RoPE를 쓴다.

Mel-Band vs Band-Split — 핵심 차이

기존 BS-RoFormer(Band-Split RoFormer)는 주파수를 62개의 비중복 밴드로 나눈다. Mel-Band RoFormer는 멜 스케일로 60개의 중복 밴드를 만든다.

BS-RoFormer Mel-Band RoFormer
밴드 분할 휴리스틱, 비중복, 62개 멜 스케일, 50% 중복, 60개
지각적 가중치 없음 있음 (인간 청각에 맞춤)
파라미터 (L=6) 72.2M 84.2M

멜 스케일은 인간이 저주파보다 고주파의 차이를 덜 느끼는 특성을 반영한다. 저주파 구간은 좁게, 고주파 구간은 넓게 나눈다. 50% 중복은 밴드 경계에서 발생하는 아티팩트를 줄여준다.

실제 코드:

# librosa로 멜 필터 뱅크 생성
mel_filter_bank_numpy = filters.mel(sr=44100, n_fft=2048, n_mels=60)
mel_filter_bank = torch.from_numpy(mel_filter_bank_numpy)

# 이진화: 각 주파수 빈이 어느 밴드에 속하는지
freqs_per_band = mel_filter_bank > 0

# 인덱스 매핑: 어떤 주파수가 어느 밴드로 가는지
repeated_freq_indices = repeat(torch.arange(freqs), 'f -> b f', b=num_bands)
freq_indices = repeated_freq_indices[freqs_per_band]

전체 추론 파이프라인

MelBandRoformer.forward()의 단계:

1단계 — STFT

원본 스테레오 오디오를 복소 스펙트로그램으로 변환.

입력: [batch, 2, samples] (스테레오 파형)
STFT: n_fft=2048, hop_length=441, win_length=2048
출력: [batch, 1025, time_frames, 2] (주파수 빈 × 시간 × 실수/허수)

441 hop은 44,100Hz에서 100fps. 1025개 주파수 빈은 0~22,050Hz를 커버한다.

2단계 — 멜 밴드 프로젝션

1025개 주파수 빈을 60개 멜 밴드로 분해한다. 각 밴드에 속하는 주파수 빈을 모아서 BandSplit 모듈의 밴드별 선형 레이어로 임베딩한다.

1025 주파수 빈 → 60개 멜 밴드로 그룹핑
각 밴드 → 선형 레이어 → [batch, time, 60, dim=384]

3단계 — 계층적 Transformer (6레이어)

각 레이어에서 시간 Transformer와 주파수 Transformer를 교대로 실행한다:

a) 시간 Transformer — 각 밴드 내에서 시간 축을 처리

[batch, 60, time, 384] → reshape → [batch×60, time, 384]
→ RoPE Attention + Gated Output + FFD

b) 주파수 Transformer — 각 시간 프레임 내에서 밴드 축을 처리

[batch, time, 60, 384] → reshape → [batch×time, 60, 384]
→ RoPE Attention + Gated Output + FFD

시간 Transformer가 "이 밴드에서 시간적으로 보컬이 어디 있는지"를 잡고, 주파수 Transformer가 "이 시점에서 밴드 간 관계(하모닉 구조)"를 잡는다.

4단계 — 마스크 추정

각 밴드에서 MLP(depth=2)로 복소 마스크를 생성한다:

384 → 1536 → freq_bins × 2 (GLU 활성화)
→ 중복 밴드 기여를 평균
→ 원본 STFT에 마스크를 곱함

5단계 — ISTFT

마스크된 스펙트로그램을 역 STFT로 시간 도메인 파형으로 복원.

카라오케 전용 동작의 비밀

학습 설정(YAML)이 핵심이다:

training:
  instruments:

    - karaoke      # = 반주 + 백킹 보컬

    - other        # = 리드 보컬
  target_instrument: karaoke

일반적인 음원 분리 모델의 학습 데이터:

  • vocals = 리드 + 백킹 전체

  • instrumental = 보컬 없음

이 모델의 학습 데이터:

  • karaoke = 반주 + 백킹 보컬 + 코러스

  • other = 리드 보컬만

모델이 출력하는 건 karaoke 스템이다. 잔차(원본 - karaoke)가 리드 보컬이 된다. 백킹 보컬은 karaoke 스템에 남아있으므로 반주가 자연스럽다.

SDR 10.1956의 의미

SDR(Signal-to-Distortion Ratio)은 분리 품질을 데시벨로 측정한다. 높을수록 좋다.

모델 Vocal SDR 비고
Spleeter (2020) ~5.91 dB 오래된 베이스라인
HTDemucs (2022) ~9.20 dB 4-스템 범용 분리
이 모델 10.20 dB 리드 보컬만 (더 어려운 태스크)
Mel-RoFormer L=6 (논문) 11.21 dB 전체 보컬 (리드+백킹)
BS-RoFormer-Viperx 12.98 dB 전체 보컬, 최고 성능

리드 보컬만 분리하는 건 전체 보컬 분리보다 어렵다. 백킹 보컬과 리드 보컬의 주파수 대역이 겹치기 때문이다. 10.20 dB는 이 태스크에서 상당히 높은 수치다.

직접 테스트하는 방법

1. audio-separator로 간단 테스트:

pip install audio-separator[gpu]  # GPU 가속
# 또는
pip install audio-separator[cpu]  # CPU만

audio-separator song.mp3 \
  --model_filename mel_band_roformer_karaoke_aufr33_viperx_sdr_10.1956.ckpt

첫 실행 시 913MB 모델을 자동 다운로드한다. 출력:

  • song_(Vocals)_mel_band_roformer_karaoke_aufr33_viperx_sdr_10.1956.wav

  • song_(Instrumental)_mel_band_roformer_karaoke_aufr33_viperx_sdr_10.1956.wav

2. Python에서 직접:

from audio_separator.separator import Separator

sep = Separator(
    model_file_dir="/tmp/models",
    output_dir="/tmp/output"
)
sep.load_model(
    "mel_band_roformer_karaoke_aufr33_viperx_sdr_10.1956.ckpt"
)
output_files = sep.separate("song.mp3")
print(output_files)
# → ['song_(Vocals)_...wav', 'song_(Instrumental)_...wav']

3. 코드 레벨에서 분석하려면:

핵심 파일 3개:

  • audio_separator/separator/separator.py — 엔트리 포인트, 모델 로딩

  • audio_separator/separator/architectures/mdxc_separator.py — 추론 오케스트레이션 (demix() 메서드)

  • audio_separator/separator/uvr_lib_v5/roformer/mel_band_roformer.py모델 아키텍처 구현 (471줄)

mel_band_roformer.pyMelBandRoformer 클래스가 전체 아키텍처다. forward() 메서드가 위에 설명한 5단계 파이프라인을 구현한다.

모델 설정값 전체

audio:
  chunk_size: 485100    # 441 × (1101-1) ≈ 11초
  dim_f: 1024
  dim_t: 1101
  hop_length: 441       # 44100/441 = 100fps
  n_fft: 2048
  num_overlap: 4        # 추론 시 오버랩 수
  sample_rate: 44100
  stem_name: karaoke
  num_stems: 1          # 출력 스템 1개 (나머지는 잔차)

model:
  dim: 384              # 임베딩 차원
  depth: 6              # Transformer 레이어 수
  stereo: true
  time_transformer_depth: 1   # 레이어당 시간 Transformer
  freq_transformer_depth: 1   # 레이어당 주파수 Transformer
  num_heads: 8
  dim_head: 64
  attn_dropout: 0.0
  ff_dropout: 0.0
  num_bands: 60         # 멜 밴드 수
  mask_estimator_depth: 2

핵심 개념

1

STFT — 스테레오 오디오를 복소 스펙트로그램으로 변환 (n_fft=2048, hop=441)

2

멜 밴드 프로젝션 — 1025개 주파수 빈을 60개 중복 멜 밴드로 분해 + 선형 임베딩

3

계층적 Transformer ×6 — 시간 축 Transformer → 주파수 축 Transformer 교대 실행 (RoPE)

4

마스크 추정 — 밴드별 MLP로 복소 마스크 생성 → 원본 STFT에 곱셈

5

ISTFT — 마스크된 스펙트로그램을 시간 도메인 파형으로 복원

6

잔차 계산 — 원본 - karaoke(모델 출력) = 리드 보컬

사용 사례

카라오케 반주 생성 — 리드 보컬만 제거하고 백킹 보컬·코러스는 유지 보컬 추출 — 깨끗한 리드 보컬만 분리 (WhisperX 전사 입력으로 활용) ML 모델 아키텍처 학습 — Transformer 기반 오디오 처리 파이프라인 이해