고차원을 저차원으로 압축해주는 high quality neural compression model이 필요하다.
여기서는 44.1kHz 오디오를 90배 압축한다.
speech, sound, music 전부 데이터 사용
오픈소스로 코드, weight를 풀었다.
We hope our work can lay the foundation for the next generation of high-fidelity audio modeling.
압축하여 latent를 만드는건 생성 모델링 이전에 필수적이다.
VQ를 하는게 특히 모델링이 어려운 것 같다. SoundStream과 EnCodec이 시도했고 잘 하지만, GAN-based 방법들의 문제가 있고 아티팩트가 존재한다.
DAC는 BigVGAN의 방식에 몇가지 변경사항을 추가한다. BigVGAN은 HifiGAN에 Snake act를 추가했고 HifiGAN은 MelGAN에 multi-period waveform discriminator와 추가적인 mel-recon loss를 사용했고 MelGAN은 GAN base에 multi-scale waveform discriminator 사용
Encodec처럼 loss balancer를 사용하지 않는다.
핵심 구현 사항들
아키텍처
- Fully Convolutional encoder-decoder like Sound Stream
→ Residual VQ, adverserial, perceptual loss 사용한다.

frame rate = sampling rate / striding factor
코드북은 9개, 각 코드북당 1024개의 entry가 있다.
encoder의 continuous output latent는 1024 dimension, 여기서 8 dimension만을 사용해서 codebook entry를 서치한다.
즉 44.1kHz 1초 오디오가 들어왔을 때
- continuous latent : (86, 1024)
- quantized output : (86, 9 - nums of codebooks)
Leaky ReLU 대신 오디오의 주기성에 대한 inductive bias가 들어간 snake activation function을 사용한다.
오디오 waveform은 특히 주기성이 높다(소리는 파동에 의해 만들어지기 때문에)
더군다나, 흔히 사용되는 활성화함수들은(Leaky ReLU같은) 주기성에 기반한 예측을 잘 못한다. 오디오가 주기성이 높다는 inductive bias를 사용해서 Snake activation func을 사용했다.



가장 위와 4번째를 비교해보면 차이가 있는걸 알 수 있다.
늘 좋을까?
전체 코드북 중 일부만 사용하는 codebook collapse 문제를 해결

VQ가 보통 제일 많이 쓰이지만 여전히 학습시의 문제가 많다.
vanilla VQ-VAE들은 초기값이 좋지않으면 모든 코드북을 활용하지 않고 일부만 사용하게 된다 → 낮은 퀄리티
이걸 해결하기 위해 최근의 오디오 코덱들은 k-means 클러스터링을해서 코드북 벡터를 초기화한다. 그리고 몇번의 배치동안 사용되지 않은 코드북은 다시 새로운 값으로 초기화된다(from JukeBox paper)
이를 위해 ‘Vector-quantized image modeling with improved vqgan’ 논문을 참조해서 두가지 주요한 테크닉을 사용했다.
- Factorization을 통해 code lookup과 code embedding을 분리한다.
lookup은 low dim(8d or 32d), code embedding은 고차원으로 만들어서(1024d)
직관적으로, 입력값의 principle components만을 사용해서 code를 선택하도록 해준다고 이해할 수 있다.

codebook의 각 entry도 8d로 관리하고, projection matrix로 1024로 만든다.
- encoded vector와 codebook 벡터에 L2 정규화를 적용해서(L2 norm으로 나누어 크기를 1로 만들어서), euclidean distance를 cosine similarity로 바꾸어서 stability와 quality를 높였다.
quantizer dropout의 단점을 분석하고 해결

1초를 몇개의 프레임으로 압축할지는 고정, 각 프레임당 latent dimension도 고정된다.
이걸 Residual을 통해서 Nq개의 codebook vector로 구성하게 되는데, Sound Stream에서는 이 때 몇개를 쓸지를 랜덤하게 정해서 학습한다.(N개 → 아래에서부터 N개의 코드북 사용)
근데 이렇게하면 최종적으로 최대한 썼을 때의 퀄리티도 낮아진다 → 50%확률로 dropout 하도록 조정
dropout을 해야, 낮은 index의 residual codebook일수록 더 coarse하게 중요한 정보, 올라갈수록 디테일한 정보를 가지도록 학습될 수 있기 때문에 유용한 테크닉이긴하다.
Discriminator design

같은걸 표현하는데 다른 영어를 써서 매우매우 헷갈리게 표현해두었다. window lengh = window size = filter length. 왜이러는걸까?
우선 Loss가 되게 많다. 가중합했다.
- multi-scale mel-reconstruction loss - 15
- feature matching loss - 2
- adversarial loss - 1
- codebook loss - 1
- commitment loss - 0.25
우선 오디오의 특성을 이해해야 한다.
오디오는 주기함수로 분해된다.
그냥 Fourier transform을 하면 오디오는 해당 오디오를 이루는 frequency(소리의 피치를 결정)와 magnitude(각 주파수의 크기)로 변환된다.

근데 여기서 알 수 있듯이 일정 길이의 오디오를 변환해도 시간정보는 남아있지 않다.
그래서 시간정보를 유지하면서 FT를 적용하기위해, 오디오를 구간별로 쪼갠 뒤 그 구간마다 FT를 적용하고 합쳐서 완성한다 ⇒ STFT : Short Time Fourier Transform
그리고 이 STFT를 사용해서 오디오를 Mel spectrogram으로 변환한다.

3차원이됨. X축은 시간, Y축은 frequency, Z축은 크기를 나타냄.
STFT를 하는 방법
- 오디오를 일정 구간(window size, hop length)으로 잘라서 각 구간별로 Fourier transform을 적용한다.
window size가 1024이고 hop length가 256이면 항상 75%는 겹침(hop length만큼 이동)
- 그렇게 변환한 것들을 이어붙여서 표현한다. 겹쳐진 부분들은 각 윈도우에서 FT를 위해 사용한 방법에 따라 정해지는 가중치로 가중합한다.
논문에서 말한 Multi-scale이 각기 다른 window size에 의해 정해진다. multi-scale을 하는 이유는 윈도우 크기에 따른 장단점이 있기 때문에.
window 크기가 클수록 더 장기간에 걸친 오디오의 특징을 포착해서 주파수 해상도가 높아지지만, 크기가 작으면(=짧으면) 고주파의 세부 정보를 잡아낼 수 있다, 시간해상도가 높아진다(변화에 더 민감해지니까).
위 멜스펙트로그램 사진을 보면 또한 주파수축이, 고주파수는 한 칸의 크기가 4096이고 저주파수는 64인걸 알 수 있다. 인간이 변화를 민감하게 느끼는 주파수에 더 집중하도록 mel-scale을 적용해서 변환한다.
mel bin size는 전체 주파수 구간을 몇개의 구간으로 나눌지를 의미한다. 구간으로 나누었을 때 각 구간을 멜 필터라고 부른다. 위의 이유로 저주파 구간에 더 많은 멜 필터가 배치된다. 각 멜 필터별로 주파수별 에너지를 계산해서 이 주파수별 에너지를 가중합하여 그 필터의 총 에너지를 결정한다. 이걸 Log 취해서 데시벨로 변환하면 mel spectrogram에 사용되는 값이 된다!
mel bin size가 5일 때.
import librosa
import librosa.display
import matplotlib.pyplot as plt
import numpy as np
# 오디오 파일 로드
audio_path = '.test.wav'
y, sr = librosa.load(audio_path, sr=None)
# Mel-spectrogram 생성 (Mel bin size 설정: n_mels)
n_mels = 5 # 원하는 Mel bin size 설정
S = librosa.feature.melspectrogram(y=y, sr=sr, n_mels=n_mels)
# dB 스케일로 변환
S_dB = librosa.power_to_db(S, ref=np.max)
# Mel-spectrogram 시각화
plt.figure(figsize=(10, 4))
librosa.display.specshow(S_dB, sr=sr, x_axis='time', y_axis='mel', fmax=sr/2)
plt.colorbar(format='%+2.0f dB')
plt.title(f'Mel-Spectrogram (n_mels={n_mels})')
plt.tight_layout()
plt.show()



Share article
Subscribe to our newsletter