2024. 10. 15. 22:50ㆍDevelopers 공간 [Shorts]/Vision & Audio
<분류>
A. 수단
- OS/Platform/Tool : Linux, Kubernetes(k8s), Docker, AWS
- Package Manager : node.js, yarn, brew,
- Compiler/Transpillar : React, Nvcc, gcc/g++, Babel, Flutter
- Module Bundler : React, Webpack, Parcel
B. 언어
- C/C++, python, Javacsript, Typescript, Go-Lang, CUDA, Dart, HTML/CSS
C. 라이브러리 및 프레임워크 및 SDK
- OpenCV, OpenCL, FastAPI, PyTorch, Tensorflow, Nsight
1. What? (현상)
FID(Frechet Inception Distance)란 생성모델이 생성한 이미지들의 feature와 다른 Test Set의 feature를 비교하는 방법으로, 생성된 이미지의 Quality와 Diversity를 측정하는 방법입니다.
아래 식과 같이 구하며 Test Set 이미지 집합 $T$와 G로 생성한 이미지 집합 $I_G$일 때, $\mu$는 mean, $\Sigma$는 covariance를 의미합니다.
$$FID(T,I_G)=\underbrace{\|\mu_T-\mu_{I_G}\|^2_2}_{\text{Quality}}+\underbrace{Tr(\Sigma_T+\Sigma_{I_G}-2(\Sigma_T\Sigma_{I_G})^{\frac{1}{2}})}_{\text{Diversity}}$$
이번 글에서는 이를 구하는 코드에 대해 살펴보겠습니다.
2. Why? (원인)
- X
3. How? (해결책)
먼저 원하는 embedding의 mean과 variance를 아래 코드로 구해냅니다.
- embd_list : 원하는 embedding들을 쌓아서 아래와 같은 차원으로 만들어 넣어줍니다.
- shape : (원하는 embedding의 전체 개수, embedding의 차원)
- mu : 해당 embedding의 mean를 의미합니다.
- shape : (embedding의 차원)
- sigma : 해당 embedding의 covariance를 의미합니다.
- shape : (embedding의 차원, embedding의 차원)
import numpy as np
def calculate_embd_statistics(embd_lst):
if isinstance(embd_lst, list):
embd_lst = np.array(embd_lst)
mu = np.mean(embd_lst, axis=0)
sigma = np.cov(embd_lst, rowvar=False)
return mu, sigma
위와 같이 얻은 두개의 embedding의 각 mean과 variance를 통해 아래와 같은 코드로 FID를 구해냅니다.
- mu1, mu2 : 생성된 샘플들(mu1)과 Reference 샘플들(mu2)의 embedding의 평균
- np.atleast_1d : input이 최소 1차원이 되도록 만들어줍니다.
- shape : (embedding의 차원)
- sigma1, sigma2 : 생성된 샘플들(sigma1)과 Reference 샘플들(sigma2)의 embedding의 covariance
- np.atleast_2d :input이 최소 2차원이 되도록 만들어줍니다.
- shape : (embedding의 차원, embedding의 차원)
- diff : mu1과 mu2의 차이
- shape : (embedding의 차원)
$$FID(T,I_G)=\underbrace{\|{\color{red}\mu_T-\mu_{I_G}}\|^2_2}_{\text{Quality}}+\underbrace{Tr(\Sigma_T+\Sigma_{I_G}-2(\Sigma_T\Sigma_{I_G})^{\frac{1}{2}})}_{\text{Diversity}}$$
- tr_covmean : sigma1과 sigma2의 곱의 square root를 구한 후 diagonal의 합을 얻어냅니다.
- linalg.sqrtm : matrix의 square root를 구해냅니다. 각 element별 square root가 아니라 $A=B^2$일 때 A matrix를 받아 B matrix를 구해냅니다.
- np.trace : 2D matrix인 경우, 0차원과 1차원에 대해 diagonal의 합을 return합니다.
- shape : (embedding의 차원, embedding의 차원)
$$FID(T,I_G)=\underbrace{\|\mu_T-\mu_{I_G}\|^2_2}_{\text{Quality}}+\underbrace{{\color{red}Tr(}\Sigma_T+\Sigma_{I_G}-2{\color{red}(\Sigma_T\Sigma_{I_G})^{\frac{1}{2}}}{\color{red})}}_{\text{Diversity}}$$
import numpy as np
from scipy import linalg
def calculate_frechet_distance(mu1, sigma1, mu2, sigma2, eps=1e-6):
mu1 = np.atleast_1d(mu1)
mu2 = np.atleast_1d(mu2)
sigma1 = np.atleast_2d(sigma1)
sigma2 = np.atleast_2d(sigma2)
assert mu1.shape == mu2.shape, \
'Training and test mean vectors have different lengths'
assert sigma1.shape == sigma2.shape, \
'Training and test covariances have different dimensions'
diff = mu1 - mu2
# product might be almost singular
covmean, _ = linalg.sqrtm(sigma1.dot(sigma2), disp=False)
if not np.isfinite(covmean).all():
msg = ('fid calculation produces singular product; '
'adding %s to diagonal of cov estimates') % eps
print(msg)
offset = np.eye(sigma1.shape[0]) * eps
covmean = linalg.sqrtm((sigma1 + offset).dot(sigma2 + offset))
# numerical error might give slight imaginary component
if np.iscomplexobj(covmean):
if not np.allclose(np.diagonal(covmean).imag, 0, atol=1e-3):
m = np.max(np.abs(covmean.imag))
raise ValueError('Imaginary component {}'.format(m))
covmean = covmean.real
tr_covmean = np.trace(covmean)
return (diff.dot(diff)+np.trace(sigma1)+np.trace(sigma2)-2*tr_covmean)
위 함수를 보면, matrix의 square root를 얻어내는 과정에서 infinity가 발생하는 경우, 위에서 사용할 sigma에 작은 값을 더해 다시 구해내는 과정이 추가됩니다.
- np.isfinite() : 각 element가 $\infty$인지 확인해 array를 얻습니다.
- np.all() : 모든 element가 True인지 확인합니다.
- np.eye() : 2D 단위행렬을 생성합니다.
또한 당연히 matrix의 square root를 얻어내는 과정에서 complex값이 생기는 경우, 결과에서 실수부만 활용합니다.
- np.iscomplexobj() : element 중 complex type이 있는지 확인합니다.
- np.allclose() : 두개의 array를 element마다 비교해 tolerance 한에서 같다고 볼 수 있는지 확인합니다.
- np.diagonal() : 2D array인 경우, diagonal 값의 집합 array를 얻습니다.
- np.imag() : complex 값의 imaginary(허수부)를 얻어냅니다.
- np.abs() : 절대값을 얻습니다.
- np.max() : 최대값을 얻습니다.
- np.real() : complex 값의 real(실수부)를 얻어냅니다.
https://github.com/Stability-AI/stable-audio-metrics/blob/main/src/openl3_fd.py
Adapted from: https://github.com/mseitzer/pytorch-fid/blob/master/src/pytorch_fid/fid_score.py
Adapted from: https://github.com/gudgud96/frechet-audio-distance/blob/main/frechet_audio_distance/fad.py
'Developers 공간 [Shorts] > Vision & Audio' 카테고리의 다른 글
[Data Science] Embedding을 2차원 Visualize하기 (0) | 2024.11.10 |
---|---|
[Audio] Python Pedalboard를 활용해 Audio를 바꾸기 (2) | 2024.10.10 |
[Audio] Python활용해 BPM 측정하기 (0) | 2024.08.08 |
[Audio] Python에서 Audio 불러오기 (0) | 2024.07.15 |
[Audio] Python에서 MIDI 파일 다루기 (0) | 2024.07.15 |