High-Fidelity Audio Compression with Improved RVQGAN(DAC)

DAC를 읽었다.
김호진's avatar
Oct 02, 2024
High-Fidelity Audio Compression with Improved RVQGAN(DAC)
neural audio compression - 44.1kHz 오디오를 90배 압축해서 토큰으로. 8kbps bandwidth가 된다.
발전된 고품질 오디오 생성 기술과 이미지 도메인에서 발전된 vector quantization 방법론을 결합했다.
all audio
ablation 실험 결과, 코드, 가중치 다 공개했다.
 
Introduction
고품질의 오디오는 초당 44,100개의 샘플이라는 고차원 데이터에 시간길이가 천차만별이라 generative modeling이 어렵다. 이 문제를 해결하기 위해, 오디오 생성은 보통 Mel-spectrogram으로 바꾸고 여기서 모델링을 한다(hierachical generative model).
자연스럽게 VAE 프레임워크로 중간 변수를 학습하는게 대안이 된다.
VQ로 고정된 크기의 코드북으로 변환하면 손실이 있긴 하겠지..
그래도 1) 오디오를 고품질로, 아티팩트없이 변환할 수 있어야 한다. 2) 길이의 측면(시간당 샘플 수)에서 압축률이 높아야 한다. 의미없는 정보는 날리고 중요한 정보만 남기면서 3) 모든 종류의 오디오를 변환가능해야한다.
기존이 이런 모델(SoundStream, Encodec)이 있지만 아티팩트도 많고 특히 high-frequency단에서 정보가 손실이 많음.
 
  • 기존의 방법들은 코드북 중 일부를 사용하지 않는, codebook collapse 문제가 있었다. 이걸 개선된 학습 테크닉으로 해결했다.
  • quantizer dropout의 부작용 - 여러 bitrate를 한 모델이 처리하도록 학습하면 full-bandwidth에서는 오히려 성능이 떨어진다.
  • periodic inductive biases, multi-scale STFT discriminator, multi-scale mel reconstruction loss를 추가해서 뉴럴 오디오 코덱의 디자인을 바꿨다.
 
 
우리도 convolutional encoder-decoder 구조 사용하고, Residual VQ, adverserial, perceptual loss를 넣는다. 여기 몇개 추가되지. Encodec은 loss간의 가중치를 조절하는 loss balancer가 있는데 DAC는 그런거 없다.
 
frame rate = sampling rate / striding factor
 
오디오 waveform은 특히 주기성이 높다(소리는 파동에 의해 만들어지기 때문에)
더군다나, 흔히 사용되는 활성화함수들은(Leaky ReLU같은) 주기성에 기반한 예측을 잘 못한다. 오디오가 주기성이 높다는 inductive bias를 사용해서 Snake activation func을 사용했다.
notion image
notion image
 
3.2 Improved residual vector quatization
VQ가 보통 제일 많이 쓰이지만 여전히 학습시의 문제가 많다.
vanilla VA-VAE들은 좋지않은 초기값으로 인해 코드북을 적게 사용한다.
이걸 해결하기 위해 최근의 오디오 코덱들은 k-means 클러스터링을해서 코드북 벡터를 초기화한다. 그리고 몇번의 배치동안 사용되지 않은 코드북은 다시 새로운 값으로 초기화된다.
두가지 주요한 테크닉을 사용했다 - 이미지 도메인의 VQGAN에서 사용된.
  1. Factorization은 code lookup과 code embedding을 분리한다. lookup은 저차원 공간(8d or 32d), 코드 임베딩은 고차원으로 만들어서(1024d).
    1. 직관적으로, 입력값의 principle components만을 사용해서 code를 선택하도록 해준다고 이해할 수 있다. 실제로 사용하는건 그 코드에 연결된 고차원 벡터를 사용해서 정보도 풍부하게 유지하면서.
  1. encoded vector와 codebook 벡터에 L2 정규화를 적용해서(L2 norm으로 나누어 크기를 1로 만들어서), euclidean distance를 cosine similarity로 바꾸어서 학습의 안정성과 성능을 높였다.
 
Discriminator design
notion image
같은걸 표현하는데 다른 영어를 써서 매우매우 헷갈리게 표현해두었다. window lengh = window size = filter length. 왜이러는걸까?
 
우선 Loss가 되게 많다. 가중합했다.
  1. multi-scale mel-reconstruction loss - 15
  1. feature matching loss - 2
  1. adversarial loss - 1
  1. codebook loss - 1
  1. commitment loss - 0.25
 
우선 오디오의 특성을 이해해야 한다.
오디오는 주기함수로 분해된다.
Fourier transform을 하면 오디오는 해당 오디오를 이루는 frequency(소리의 피치를 결정)와 magnitude(각 주파수의 크기)로 변환된다.
notion image
근데 여기서 알 수 있듯이 일정 길이의 오디오를 변환해도 시간정보는 남아있지 않다. 즉, 시간 정보가 사라진다. 그래서 시간정보를 유지하면서 FT를 적용하기위해, 오디오를 구간별로 쪼갠 뒤 그 구간마다 FT를 적용하고 합쳐서 완성한다 = STFT
그리고 오디오를 Mel spectrogram으로 변환할 때 STFT(short-time fourier transform)이 사용된다.
notion image
3차원이됨. X축은 시간, Y축은 frequency, Z축은 크기를 나타냄.
 
STFT를 하는 방법
  1. window length 단위 크기로 Fourier transform을 적용한다.
  1. hop length만큼 이동해서 다시 FT 적용. 다시말해, window size가 1024이고 hop length가 256이면 항상 75%는 겹치게 한다는 뜻.
  1. 그렇게 변환한 것들을 이어붙여서 표현한다. 겹쳐진 부분들은 각 윈도우에서 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()
notion image
 
 
 
 
 
 
 
notion image
notion image
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Share article
Subscribe to our newsletter
RSSPowered by inblog