Numpy implementation of the Frechet Distance. The Frechet distance between two multivariate Gaussians X_1 ~ N(mu_1, C_1) and X_2 ~ N(mu_2, C_2) is d^2 = ||mu_1 - mu_2||^2 + Tr(C_1 + C_2 - 2*sqrt(C_1*C_2)). Stable version by Dougal J. Sutherland. Params: -- mu1 : Num
(mu1, sigma1, mu2, sigma2, eps=1e-6)
| 54 | |
| 55 | |
| 56 | def calculate_frechet_distance(mu1, sigma1, mu2, sigma2, eps=1e-6): |
| 57 | """Numpy implementation of the Frechet Distance. |
| 58 | The Frechet distance between two multivariate Gaussians X_1 ~ N(mu_1, C_1) |
| 59 | and X_2 ~ N(mu_2, C_2) is |
| 60 | d^2 = ||mu_1 - mu_2||^2 + Tr(C_1 + C_2 - 2*sqrt(C_1*C_2)). |
| 61 | Stable version by Dougal J. Sutherland. |
| 62 | Params: |
| 63 | -- mu1 : Numpy array containing the activations of a layer of the |
| 64 | inception net (like returned by the function 'get_predictions') |
| 65 | for generated samples. |
| 66 | -- mu2 : The sample mean over activations, precalculated on an |
| 67 | representative data set. |
| 68 | -- sigma1: The covariance matrix over activations for generated samples. |
| 69 | -- sigma2: The covariance matrix over activations, precalculated on an |
| 70 | representative data set. |
| 71 | Returns: |
| 72 | -- : The Frechet Distance. |
| 73 | """ |
| 74 | |
| 75 | mu1 = np.atleast_1d(mu1) |
| 76 | mu2 = np.atleast_1d(mu2) |
| 77 | |
| 78 | sigma1 = np.atleast_2d(sigma1) |
| 79 | sigma2 = np.atleast_2d(sigma2) |
| 80 | |
| 81 | assert mu1.shape == mu2.shape, \ |
| 82 | 'Training and test mean vectors have different lengths' |
| 83 | assert sigma1.shape == sigma2.shape, \ |
| 84 | 'Training and test covariances have different dimensions' |
| 85 | |
| 86 | diff = mu1 - mu2 |
| 87 | |
| 88 | # Product might be almost singular |
| 89 | covmean, _ = linalg.sqrtm(sigma1.dot(sigma2), disp=False) |
| 90 | if not np.isfinite(covmean).all(): |
| 91 | msg = ('fid calculation produces singular product; ' |
| 92 | 'adding %s to diagonal of cov estimates') % eps |
| 93 | print(msg) |
| 94 | offset = np.eye(sigma1.shape[0]) * eps |
| 95 | covmean = linalg.sqrtm((sigma1 + offset).dot(sigma2 + offset)) |
| 96 | |
| 97 | # Numerical error might give slight imaginary component |
| 98 | if np.iscomplexobj(covmean): |
| 99 | if not np.allclose(np.diagonal(covmean).imag, 0, atol=1e-3): |
| 100 | m = np.max(np.abs(covmean.imag)) |
| 101 | raise ValueError('Imaginary component {}'.format(m)) |
| 102 | covmean = covmean.real |
| 103 | |
| 104 | tr_covmean = np.trace(covmean) |
| 105 | |
| 106 | return (diff.dot(diff) + np.trace(sigma1) + np.trace(sigma2) - |
| 107 | 2 * tr_covmean) |
| 108 | |
| 109 | |
| 110 | def calculate_diversity(activation, diversity_times, emb_scale, norm_scale): |