Spaces:
Runtime error
Runtime error
# Copyright (C) 2021 NVIDIA CORPORATION & AFFILIATES. All rights reserved. | |
# | |
# This work is made available under the Nvidia Source Code License-NC. | |
# To view a copy of this license, check out LICENSE.md | |
""" | |
Modified from https://github.com/clovaai/generative-evaluation-prdc | |
Copyright (c) 2020-present NAVER Corp. | |
MIT license | |
""" | |
import os | |
import torch | |
from imaginaire.utils.distributed import is_master | |
from imaginaire.utils.distributed import master_only_print as print | |
from .common import load_or_compute_activations, compute_pairwise_distance, \ | |
compute_nn | |
def compute_prdc(prdc_path, data_loader, net_G, | |
key_real='images', key_fake='fake_images', | |
real_act=None, fake_act=None, | |
sample_size=None, save_act=True, k=10, **kwargs): | |
r"""Compute precision diversity curve | |
Args: | |
""" | |
print('Computing PRDC.') | |
act_path = os.path.join( | |
os.path.dirname(prdc_path), 'activations_real.npy' | |
) if save_act else None | |
# Get the fake activations. | |
if fake_act is None: | |
fake_act = load_or_compute_activations(None, | |
data_loader, | |
key_real, key_fake, net_G, | |
sample_size=sample_size, | |
**kwargs) | |
else: | |
print(f"Using precomputed activations of size {fake_act.shape}.") | |
# Get the ground truth activations. | |
if real_act is None: | |
real_act = load_or_compute_activations(act_path, | |
data_loader, | |
key_real, key_fake, None, | |
sample_size=sample_size, | |
**kwargs) | |
else: | |
print(f"Using precomputed activations of size {real_act.shape}.") | |
if is_master(): | |
prdc_data = _get_prdc(real_act, fake_act, k) | |
return \ | |
prdc_data['precision'], prdc_data['recall'], \ | |
prdc_data['density'], prdc_data['coverage'] | |
else: | |
return None, None, None, None | |
def get_kth_value(unsorted, k, dim=-1): | |
r""" | |
Args: | |
unsorted: numpy.ndarray of any dimensionality. | |
k: int | |
Returns: | |
kth values along the designated axis. | |
""" | |
indices = torch.topk(unsorted, k, dim=dim, largest=False)[1] | |
k_smallests = torch.gather(unsorted, dim=dim, index=indices) | |
kth_values = k_smallests.max(dim=dim)[0] | |
return kth_values | |
def _get_prdc(real_features, fake_features, nearest_k): | |
r""" | |
Computes precision, recall, density, and coverage given two manifolds. | |
Args: | |
real_features: numpy.ndarray([N, feature_dim], dtype=np.float32) | |
fake_features: numpy.ndarray([N, feature_dim], dtype=np.float32) | |
nearest_k: int. | |
Returns: | |
dict of precision, recall, density, and coverage. | |
""" | |
real_nearest_neighbour_distances, _ = compute_nn( | |
real_features, nearest_k) | |
real_nearest_neighbour_distances = \ | |
real_nearest_neighbour_distances.max(dim=-1)[0].cpu() | |
fake_nearest_neighbour_distances, _ = compute_nn( | |
fake_features, nearest_k) | |
fake_nearest_neighbour_distances = \ | |
fake_nearest_neighbour_distances.max(dim=-1)[0].cpu() | |
distance_real_fake = compute_pairwise_distance( | |
real_features, fake_features) | |
precision = ( | |
distance_real_fake < | |
torch.unsqueeze(real_nearest_neighbour_distances, dim=1) | |
).any(dim=0).float().mean().item() | |
recall = ( | |
distance_real_fake < | |
torch.unsqueeze(fake_nearest_neighbour_distances, dim=0) | |
).any(dim=1).float().mean().item() | |
density = (1. / float(nearest_k)) * ( | |
distance_real_fake < | |
torch.unsqueeze(real_nearest_neighbour_distances, dim=1) | |
).sum(dim=0).float().mean().item() | |
# noinspection PyUnresolvedReferences | |
coverage = ( | |
distance_real_fake.min(dim=1)[0] < | |
real_nearest_neighbour_distances | |
).float().mean().item() | |
return dict(precision=precision, recall=recall, | |
density=density, coverage=coverage) | |