def calculate_fid(input_1, input_2, **kwargs): feat_layer_name = get_kwarg('feature_layer_fid', kwargs) feat_extractor = create_feature_extractor( get_kwarg('feature_extractor', kwargs), [feat_layer_name], **kwargs) metric = fid_inputs_to_metric(input_1, input_2, feat_extractor, feat_layer_name, **kwargs) return metric
def estimate_implementation_exactness(cuda, batch_size=8, rng_seed=2020): model_tf = TestInception.get_inception_tf() model_pt = create_feature_extractor( 'inception-v3-compat', ['2048', 'logits_unbiased'], cuda=cuda, ) ds = prepare_input_from_id('cifar10-train', datasets_root=tempfile.gettempdir()) rng = np.random.RandomState(rng_seed) batch_pt = torch.cat([ ds[i].unsqueeze(0) for i in rng.choice(len(ds), batch_size, replace=False) ], dim=0) f1_pt, f2_pt = TestInception.forward_pt(model_pt, batch_pt, cuda) f1_tf, f2_tf = TestInception.forward_tf(model_tf, batch_pt) return { '2048': { 'pt': [f1_pt], 'tf': [f1_tf] }, 'logits_unbiased': { 'pt': [f2_pt], 'tf': [f2_tf] } }
def calculate_isc(input_id, **kwargs): feature_extractor = get_kwarg('feature_extractor', kwargs) feat_layer_name = get_kwarg('feature_layer_isc', kwargs) feat_extractor = create_feature_extractor(feature_extractor, [feat_layer_name], **kwargs) metric = isc_input_id_to_metric(input_id, feat_extractor, feat_layer_name, **kwargs) return metric
def calculate_kid(**kwargs): feature_extractor = get_kwarg('feature_extractor', kwargs) feat_layer_name = get_kwarg('feature_layer_kid', kwargs) feat_extractor = create_feature_extractor(feature_extractor, [feat_layer_name], **kwargs) featuresdict_1 = extract_featuresdict_from_input_id_cached( 1, feat_extractor, **kwargs) featuresdict_2 = extract_featuresdict_from_input_id_cached( 2, feat_extractor, **kwargs) metric = kid_featuresdict_to_metric(featuresdict_1, featuresdict_2, feat_layer_name, **kwargs) return metric
def calculate_kid(input_1, input_2, **kwargs): feat_layer_name = get_kwarg('feature_layer_kid', kwargs) feat_extractor = create_feature_extractor( get_kwarg('feature_extractor', kwargs), [feat_layer_name], **kwargs) cacheable_input1_name = get_input_cacheable_name( input_1, get_kwarg('cache_input1_name', kwargs)) cacheable_input2_name = get_input_cacheable_name( input_2, get_kwarg('cache_input2_name', kwargs)) featuresdict_1 = extract_featuresdict_from_input_cached( input_1, cacheable_input1_name, feat_extractor, **kwargs) featuresdict_2 = extract_featuresdict_from_input_cached( input_2, cacheable_input2_name, feat_extractor, **kwargs) metric = kid_featuresdict_to_metric(featuresdict_1, featuresdict_2, feat_layer_name, **kwargs) return metric
def calculate_metrics(**kwargs): """ Calculates metrics for the given inputs. Keyword arguments: .. _ISC: https://arxiv.org/pdf/1606.03498.pdf .. _FID: https://arxiv.org/pdf/1706.08500.pdf .. _KID: https://arxiv.org/pdf/1801.01401.pdf .. _PPL: https://arxiv.org/pdf/1812.04948.pdf Args: input1 (str or torch.utils.data.Dataset or GenerativeModelBase): First input, which can be either of the following values: - Name of a registered input. See :ref:`registry <Registry>` for the complete list of preregistered inputs, and :meth:`register_dataset` for registering a new input. The following options refine the behavior wrt dataset location and downloading: :paramref:`~calculate_metrics.datasets_root`, :paramref:`~calculate_metrics.datasets_download`. - Path to a directory with samples. The following options refine the behavior wrt directory traversal and samples filtering: :paramref:`~calculate_metrics.samples_find_deep`, :paramref:`~calculate_metrics.samples_find_ext`, and :paramref:`~calculate_metrics.samples_ext_lossy`. - Path to a generative model in the :obj:`ONNX<torch:torch.onnx>` or `PTH` (:obj:`JIT<torch:torch.jit>`) format. This option also requires the following kwargs: :paramref:`~calculate_metrics.input1_model_z_type`, :paramref:`~calculate_metrics.input1_model_z_size`, and :paramref:`~calculate_metrics.input1_model_num_classes`. - Instance of :class:`~torch:torch.utils.data.Dataset` encapsulating a fixed set of samples. - Instance of :class:`GenerativeModelBase`, implementing the generative model. Default: `None`. input2 (str or torch.utils.data.Dataset or GenerativeModelBase): Second input, which can be either of the following values: - Name of a registered input. See :ref:`registry <Registry>` for the complete list of preregistered inputs, and :meth:`register_dataset` for registering a new input. The following options refine the behavior wrt dataset location and downloading: :paramref:`~calculate_metrics.datasets_root`, :paramref:`~calculate_metrics.datasets_download`. - Path to a directory with samples. The following options refine the behavior wrt directory traversal and samples filtering: :paramref:`~calculate_metrics.samples_find_deep`, :paramref:`~calculate_metrics.samples_find_ext`, and :paramref:`~calculate_metrics.samples_ext_lossy`. - Path to a generative model in the :obj:`ONNX<torch:torch.onnx>` or `PTH` (:obj:`JIT<torch:torch.jit>`) format. This option also requires the following kwargs: :paramref:`~calculate_metrics.input2_model_z_type`, :paramref:`~calculate_metrics.input2_model_z_size`, and :paramref:`~calculate_metrics.input2_model_num_classes`. - Instance of :class:`~torch:torch.utils.data.Dataset` encapsulating a fixed set of samples. - Instance of :class:`GenerativeModelBase`, implementing the generative model. Default: `None`. cuda (bool): Sets executor device to GPU. Default: `True`. batch_size (int): Batch size used to process images; the larger the more memory is used on the executor device (see :paramref:`~calculate_metrics.cuda`). Default: `64`. isc (bool): Calculate ISC_ (Inception Score). Default: `False`. fid (bool): Calculate FID_ (Frechet Inception Distance). Default: `False`. kid (bool): Calculate KID_ (Kernel Inception Distance). Default: `False`. ppl (bool): Calculate PPL_ (Perceptual Path Length). Default: `False`. feature_extractor (str): Name of the feature extractor (see :ref:`registry <Registry>`). Default: `inception-v3-compat`. feature_layer_isc (str): Name of the feature layer to use with ISC metric. Default: `logits_unbiased`. feature_layer_fid (str): Name of the feature layer to use with FID metric. Default: `"2048"`. feature_layer_kid (str): Name of the feature layer to use with KID metric. Default: `"2048"`. feature_extractor_weights_path (str): Path to feature extractor weights (downloaded if `None`). Default: `None`. isc_splits (int): Number of splits in ISC. Default: `10`. kid_subsets (int): Number of subsets in KID. Default: `100`. kid_subset_size (int): Subset size in KID. Default: `1000`. kid_degree (int): Degree of polynomial kernel in KID. Default: `3`. kid_gamma (float): Polynomial kernel gamma in KID (automatic if `None`). Default: `None`. kid_coef0 (float): Polynomial kernel coef0 in KID. Default: `1.0`. ppl_epsilon (float): Interpolation step size in PPL. Default: `1e-4`. ppl_reduction (str): Reduction type to apply to the per-sample output values. Default: `mean`. ppl_sample_similarity (str): Name of the sample similarity to use in PPL metric computation (see :ref:`registry <Registry>`). Default: `lpips-vgg16`. ppl_sample_similarity_resize (int): Force samples to this size when computing similarity, unless set to `None`. Default: `64`. ppl_sample_similarity_dtype (str): Check samples are of compatible dtype when computing similarity, unless set to `None`. Default: `uint8`. ppl_discard_percentile_lower (int): Removes the lower percentile of samples before reduction. Default: `1`. ppl_discard_percentile_higher (int): Removes the higher percentile of samples before reduction. Default: `99`. ppl_z_interp_mode (str): Noise interpolation mode in PPL (see :ref:`registry <Registry>`). Default: `lerp`. samples_shuffle (bool): Perform random samples shuffling before computing splits. Default: `True`. samples_find_deep (bool): Find all samples in paths recursively. Default: `False`. samples_find_ext (str): List of comma-separated extensions (no blanks) to look for when traversing input path. Default: `png,jpg,jpeg`. samples_ext_lossy (str): List of comma-separated extensions (no blanks) to warn about lossy compression. Default: `jpg,jpeg`. datasets_root (str): Path to built-in torchvision datasets root. Default: `$ENV_TORCH_HOME/fidelity_datasets`. datasets_download (bool): Download torchvision datasets to :paramref:`~calculate_metrics.dataset_root`. Default: `True`. cache_root (str): Path to file cache for features and statistics. Default: `$ENV_TORCH_HOME/fidelity_cache`. cache (bool): Use file cache for features and statistics. Default: `True`. input1_cache_name (str): Assigns a cache entry to input1 (when not a registered input) and forces caching of features on it. Default: `None`. input1_model_z_type (str): Type of noise, only required when the input is a path to a generator model (see :ref:`registry <Registry>`). Default: `normal`. input1_model_z_size (int): Dimensionality of noise (only required when the input is a path to a generator model). Default: `None`. input1_model_num_classes (int): Number of classes for conditional (0 for unconditional) generation (only required when the input is a path to a generator model). Default: `0`. input1_model_num_samples (int): Number of samples to draw (only required when the input is a generator model). This option affects the following metrics: ISC, FID, KID. Default: `None`. input2_cache_name (str): Assigns a cache entry to input2 (when not a registered input) and forces caching of features on it. Default: `None`. input2_model_z_type (str): Type of noise, only required when the input is a path to a generator model (see :ref:`registry <Registry>`). Default: `normal`. input2_model_z_size (int): Dimensionality of noise (only required when the input is a path to a generator model). Default: `None`. input2_model_num_classes (int): Number of classes for conditional (0 for unconditional) generation (only required when the input is a path to a generator model). Default: `0`. input2_model_num_samples (int): Number of samples to draw (only required when the input is a generator model). This option affects the following metrics: FID, KID. Default: `None`. rng_seed (int): Random numbers generator seed for all operations involving randomness. Default: `2020`. save_cpu_ram (bool): Use less CPU RAM at the cost of speed. May not lead to improvement with every metric. Default: `False`. verbose (bool): Output progress information to STDERR. Default: `True`. Returns: : Dictionary of metrics with a subset of the following keys: - :const:`torch_fidelity.KEY_METRIC_ISC_MEAN` - :const:`torch_fidelity.KEY_METRIC_ISC_STD` - :const:`torch_fidelity.KEY_METRIC_FID` - :const:`torch_fidelity.KEY_METRIC_KID_MEAN` - :const:`torch_fidelity.KEY_METRIC_KID_STD` - :const:`torch_fidelity.KEY_METRIC_PPL_MEAN` - :const:`torch_fidelity.KEY_METRIC_PPL_STD` - :const:`torch_fidelity.KEY_METRIC_PPL_RAW` """ verbose = get_kwarg('verbose', kwargs) input1, input2 = get_kwarg('input1', kwargs), get_kwarg('input2', kwargs) have_isc = get_kwarg('isc', kwargs) have_fid = get_kwarg('fid', kwargs) have_kid = get_kwarg('kid', kwargs) have_ppl = get_kwarg('ppl', kwargs) need_input1 = have_isc or have_fid or have_kid or have_ppl need_input2 = have_fid or have_kid vassert( have_isc or have_fid or have_kid or have_ppl, 'At least one of "isc", "fid", "kid", "ppl" metrics must be specified') vassert( input1 is not None or not need_input1, 'First input is required for "isc", "fid", "kid", and "ppl" metrics') vassert(input2 is not None or not need_input2, 'Second input is required for "fid" and "kid" metrics') metrics = {} if have_isc or have_fid or have_kid: feature_extractor = get_kwarg('feature_extractor', kwargs) feature_layer_isc, feature_layer_fid, feature_layer_kid = (None, ) * 3 feature_layers = set() if have_isc: feature_layer_isc = get_kwarg('feature_layer_isc', kwargs) feature_layers.add(feature_layer_isc) if have_fid: feature_layer_fid = get_kwarg('feature_layer_fid', kwargs) feature_layers.add(feature_layer_fid) if have_kid: feature_layer_kid = get_kwarg('feature_layer_kid', kwargs) feature_layers.add(feature_layer_kid) feat_extractor = create_feature_extractor(feature_extractor, list(feature_layers), **kwargs) # isc: input - featuresdict(cached) - metric # fid: input - featuresdict(cached) - statistics(cached) - metric # kid: input - featuresdict(cached) - metric if (not have_isc) and have_fid and (not have_kid): # shortcut for a case when statistics are cached and features are not required on at least one input metric_fid = fid_inputs_to_metric(feat_extractor, **kwargs) metrics.update(metric_fid) else: vprint(verbose, f'Extracting features from input1') featuresdict_1 = extract_featuresdict_from_input_id_cached( 1, feat_extractor, **kwargs) featuresdict_2 = None if input2 is not None: vprint(verbose, f'Extracting features from input2') featuresdict_2 = extract_featuresdict_from_input_id_cached( 2, feat_extractor, **kwargs) if have_isc: metric_isc = isc_featuresdict_to_metric( featuresdict_1, feature_layer_isc, **kwargs) metrics.update(metric_isc) if have_fid: cacheable_input1_name = get_cacheable_input_name(1, **kwargs) cacheable_input2_name = get_cacheable_input_name(2, **kwargs) fid_stats_1 = fid_featuresdict_to_statistics_cached( featuresdict_1, cacheable_input1_name, feat_extractor, feature_layer_fid, **kwargs) fid_stats_2 = fid_featuresdict_to_statistics_cached( featuresdict_2, cacheable_input2_name, feat_extractor, feature_layer_fid, **kwargs) metric_fid = fid_statistics_to_metric( fid_stats_1, fid_stats_2, get_kwarg('verbose', kwargs)) metrics.update(metric_fid) if have_kid: metric_kid = kid_featuresdict_to_metric( featuresdict_1, featuresdict_2, feature_layer_kid, **kwargs) metrics.update(metric_kid) if have_ppl: metric_ppl = calculate_ppl(1, **kwargs) metrics.update(metric_ppl) return metrics
def estimate_implementation_exactness(self, cuda): model_pt = create_feature_extractor('inception-v3-compat', ['2048'], cuda=cuda) conv_pt = model_pt.Conv2d_1a_3x3.conv batch_size = 1 # keep_filters = 16 # anything less makes the backends diverge and causes much different results # conv_pt.weight.data = conv_pt.weight[0:keep_filters] # conv_pt.out_channels = keep_filters ds = prepare_input_from_id('cifar10-train', datasets_root=tempfile.gettempdir()) rng = np.random.RandomState(2020) x_pt = torch.cat([ ds[i].unsqueeze(0) for i in rng.choice(len(ds), batch_size, replace=False) ], dim=0) if cuda: x_pt = x_pt.cuda() x_pt = x_pt.float() x_pt = interpolate_bilinear_2d_like_tensorflow1x(x_pt, size=(299, 299), align_corners=False) x_pt = (x_pt - 128) / 128 out_tf = self.forward_tf(conv_pt, x_pt) out_pt_builtin = self.forward_pt(conv_pt, x_pt) out_pt_manualchw = self.forward_pt_manualchw(conv_pt, x_pt) out_pt_manualhwc = self.forward_pt_manualhwc(conv_pt, x_pt) err_abs_tf_pt_builtin = (out_tf - out_pt_builtin).abs() err_abs_tf_pt_manualchw = (out_tf - out_pt_manualchw).abs() err_abs_tf_pt_manualhwc = (out_tf - out_pt_manualhwc).abs() err_abs_pt_builtin_manualchw = (out_pt_builtin - out_pt_manualchw).abs() err_abs_pt_builtin_manualhwc = (out_pt_builtin - out_pt_manualhwc).abs() suffix = f'convolution_{"gpu" if cuda else "cpu"}' self.save(out_tf, f'{suffix}_conv_tf.png') self.save(out_pt_builtin, f'{suffix}_conv_pt_builtin.png') self.save(err_abs_tf_pt_builtin, f'{suffix}_err_abs_tf_pt_builtin.png') self.save(err_abs_tf_pt_manualchw, f'{suffix}_err_abs_tf_pt_manualchw.png') self.save(err_abs_tf_pt_manualhwc, f'{suffix}_err_abs_tf_pt_manualhwc.png') self.save(err_abs_pt_builtin_manualchw, f'{suffix}_err_abs_pt_builtin_manualchw.png') self.save(err_abs_pt_builtin_manualhwc, f'{suffix}_err_abs_pt_builtin_manualhwc.png') flipping_pixel_err_abs = err_abs_tf_pt_builtin[0, 0, -1, -1].item() print( f'{suffix}_bottom_right_flipping_pixel_err_abs={flipping_pixel_err_abs}', file=sys.stderr) err_abs = err_abs_tf_pt_builtin.max().item() print(f'{suffix}_max_pixelwise_err_abs={err_abs}', file=sys.stderr) err_rel = err_abs / out_tf.abs().max().clamp_min(1e-9).item() print(f'{suffix}_max_pixelwise_err_rel={err_rel}', file=sys.stderr) return err_rel
def calculate_metrics(input_1, input_2=None, **kwargs): have_isc, have_fid, have_kid = get_kwarg('isc', kwargs), get_kwarg('fid', kwargs), get_kwarg('kid', kwargs) assert have_isc or have_fid or have_kid, 'At least one of "isc", "fid", "kid" metrics must be specified' assert (not have_fid) and (not have_kid) or input_2 is not None, \ 'Both inputs are required for "fid" and "kid" metrics' verbose = get_kwarg('verbose', kwargs) feature_layer_isc, feature_layer_fid, feature_layer_kid = (None,) * 3 feature_layers = set() if have_isc: feature_layer_isc = get_kwarg('feature_layer_isc', kwargs) feature_layers.add(feature_layer_isc) if have_fid: feature_layer_fid = get_kwarg('feature_layer_fid', kwargs) feature_layers.add(feature_layer_fid) if have_kid: feature_layer_kid = get_kwarg('feature_layer_kid', kwargs) feature_layers.add(feature_layer_kid) feat_extractor = create_feature_extractor( get_kwarg('feature_extractor', kwargs), list(feature_layers), **kwargs ) # isc: input - featuresdict(cached) - metric # fid: input - featuresdict(cached) - statistics(cached) - metric # kid: input - featuresdict(cached) - metric metrics = {} if (not have_isc) and have_fid and (not have_kid): # shortcut for a case when statistics are cached and features are not required on at least one input metric_fid = fid_inputs_to_metric(input_1, input_2, feat_extractor, feature_layer_fid, **kwargs) metrics.update(metric_fid) return metrics cacheable_input1_name = get_input_cacheable_name(input_1, get_kwarg('cache_input1_name', kwargs)) cacheable_input2_name = get_input_cacheable_name(input_2, get_kwarg('cache_input2_name', kwargs)) if verbose: print(f'Extracting features from input_1', file=sys.stderr) featuresdict_1 = extract_featuresdict_from_input_cached(input_1, cacheable_input1_name, feat_extractor, **kwargs) featuresdict_2 = None if input_2 is not None: if verbose: print(f'Extracting features from input_2', file=sys.stderr) featuresdict_2 = extract_featuresdict_from_input_cached( input_2, cacheable_input2_name, feat_extractor, **kwargs ) if have_isc: metric_isc = isc_featuresdict_to_metric(featuresdict_1, feature_layer_isc, **kwargs) metrics.update(metric_isc) if have_fid: fid_stats_1 = fid_featuresdict_to_statistics_cached( featuresdict_1, cacheable_input1_name, feat_extractor, feature_layer_fid, **kwargs ) fid_stats_2 = fid_featuresdict_to_statistics_cached( featuresdict_2, cacheable_input2_name, feat_extractor, feature_layer_fid, **kwargs ) metric_fid = fid_statistics_to_metric(fid_stats_1, fid_stats_2, get_kwarg('verbose', kwargs)) metrics.update(metric_fid) if have_kid: metric_kid = kid_featuresdict_to_metric(featuresdict_1, featuresdict_2, feature_layer_kid, **kwargs) metrics.update(metric_kid) return metrics
def calculate_metrics(input_1, input_2=None, **kwargs): r""" Calculate metrics for the given inputs. Args: input_1: str or torch.util.data.Dataset First positional input, can be either a Dataset instance, or a string containing a path to a directory of images, or one of the registered input sources (see registry.py). input_2: str or torch.util.data.Dataset Second positional input (not used in unary metrics, such as "isc"), can be either a Dataset instance, or a string containing a path to a directory of images, or one of the registered input sources (see registry.py). cuda: bool (default: True) Sets executor device to GPU. batch_size: int (default: 64) Batch size used to process images; the larger the more memory is used on the executor device (see "cuda" argument). isc: bool (default: False) Calculate ISC (Inception Score). fid: bool (default: False) Calculate FID (Frechet Inception Distance). kid: bool (default: False) Calculate KID (Kernel Inception Distance). feature_extractor: str (default: inception-v3-compat) Name of the feature extractor (see registry.py). feature_layer_isc: str (default: logits_unbiased) Name of the feature layer to use with ISC metric. feature_layer_fid: str (default: 2048) Name of the feature layer to use with FID metric. feature_layer_kid: str (default: 2048) Name of the feature layer to use with KID metric. feature_extractor_weights_path: str (default: None) Path to feature extractor weights (downloaded if None). isc_splits: int (default: 10) Number of splits in ISC. kid_subsets: int (default: 100) Number of subsets in KID. kid_subset_size: int (default: 1000) Subset size in KID. kid_degree: int (default: 3) Degree of polynomial kernel in KID. kid_gamma: float (default: None) Polynomial kernel gamma in KID (automatic if None). kid_coef0: float (default: 1) Polynomial kernel coef0 in KID. samples_shuffle: bool (default: True) Perform random samples shuffling before computing splits. samples_find_deep: bool (default: False) Find all samples in paths recursively. samples_find_ext: str (default: png,jpg,jpeg) List of extensions to look for when traversing input path. samples_ext_lossy: str (default: jpg,jpeg) List of extensions to warn about lossy compression. datasets_root: str (default: None) Path to built-in torchvision datasets root. Defaults to $ENV_TORCH_HOME/fidelity_datasets. datasets_download: bool (default: True) Download torchvision datasets to dataset_root. cache_root: str (default: None) Path to file cache for features and statistics. Defaults to $ENV_TORCH_HOME/fidelity_cache. cache: bool (default: True) Use file cache for features and statistics. cache_input1_name: str (default: None) Assigns a cache entry to input1 (if a path) and forces caching of features on it if not None. cache_input2_name: str (default: None) Assigns a cache entry to input2 (if a path) and forces caching of features on it if not None. rng_seed: int (default: 2020) Random numbers generator seed for all operations involving randomness. save_cpu_ram: bool (default: False) Use less CPU RAM at the cost of speed. verbose: bool (default: True) Output progress information to STDERR. Return: a dictionary of metrics. """ have_isc, have_fid, have_kid = get_kwarg('isc', kwargs), get_kwarg('fid', kwargs), get_kwarg('kid', kwargs) vassert(have_isc or have_fid or have_kid, 'At least one of "isc", "fid", "kid" metrics must be specified') vassert( (not have_fid) and (not have_kid) or input_2 is not None, 'Both inputs are required for "fid" and "kid" metrics' ) verbose = get_kwarg('verbose', kwargs) feature_layer_isc, feature_layer_fid, feature_layer_kid = (None,) * 3 feature_layers = set() if have_isc: feature_layer_isc = get_kwarg('feature_layer_isc', kwargs) feature_layers.add(feature_layer_isc) if have_fid: feature_layer_fid = get_kwarg('feature_layer_fid', kwargs) feature_layers.add(feature_layer_fid) if have_kid: feature_layer_kid = get_kwarg('feature_layer_kid', kwargs) feature_layers.add(feature_layer_kid) feat_extractor = create_feature_extractor( get_kwarg('feature_extractor', kwargs), list(feature_layers), **kwargs ) # isc: input - featuresdict(cached) - metric # fid: input - featuresdict(cached) - statistics(cached) - metric # kid: input - featuresdict(cached) - metric metrics = {} if (not have_isc) and have_fid and (not have_kid): # shortcut for a case when statistics are cached and features are not required on at least one input metric_fid = fid_inputs_to_metric(input_1, input_2, feat_extractor, feature_layer_fid, **kwargs) metrics.update(metric_fid) return metrics cacheable_input1_name = get_input_cacheable_name(input_1, get_kwarg('cache_input1_name', kwargs)) vprint(verbose, f'Extracting features from input_1') featuresdict_1 = extract_featuresdict_from_input_cached(input_1, cacheable_input1_name, feat_extractor, **kwargs) featuresdict_2 = None if input_2 is not None: cacheable_input2_name = get_input_cacheable_name(input_2, get_kwarg('cache_input2_name', kwargs)) vprint(verbose, f'Extracting features from input_2') featuresdict_2 = extract_featuresdict_from_input_cached( input_2, cacheable_input2_name, feat_extractor, **kwargs ) if have_isc: metric_isc = isc_featuresdict_to_metric(featuresdict_1, feature_layer_isc, **kwargs) metrics.update(metric_isc) if have_fid: fid_stats_1 = fid_featuresdict_to_statistics_cached( featuresdict_1, cacheable_input1_name, feat_extractor, feature_layer_fid, **kwargs ) fid_stats_2 = fid_featuresdict_to_statistics_cached( featuresdict_2, cacheable_input2_name, feat_extractor, feature_layer_fid, **kwargs ) metric_fid = fid_statistics_to_metric(fid_stats_1, fid_stats_2, get_kwarg('verbose', kwargs)) metrics.update(metric_fid) if have_kid: metric_kid = kid_featuresdict_to_metric(featuresdict_1, featuresdict_2, feature_layer_kid, **kwargs) metrics.update(metric_kid) return metrics