Calculate PRDC score based on accumulated extracted features from the two distributions. Implementation inspired by `Fid Score`_
(self)
| 144 | self.fake_features.append(features) |
| 145 | |
| 146 | def compute(self) -> Tuple[Tensor, Tensor]: |
| 147 | """Calculate PRDC score based on accumulated extracted features from the two distributions. |
| 148 | Implementation inspired by `Fid Score`_ |
| 149 | """ |
| 150 | real_features = dim_zero_cat(self.real_features) |
| 151 | fake_features = dim_zero_cat(self.fake_features) |
| 152 | |
| 153 | real_nearest_neighbour_distances = compute_nearest_neighbour_distances( |
| 154 | real_features, self.nearest_k) |
| 155 | fake_nearest_neighbour_distances = compute_nearest_neighbour_distances( |
| 156 | fake_features, self.nearest_k) |
| 157 | distance_real_fake = compute_pairwise_distance( |
| 158 | real_features, fake_features) |
| 159 | |
| 160 | precision = ( |
| 161 | distance_real_fake < |
| 162 | np.expand_dims(real_nearest_neighbour_distances, axis=1) |
| 163 | ).any(axis=0).mean() |
| 164 | |
| 165 | recall = ( |
| 166 | distance_real_fake < |
| 167 | np.expand_dims(fake_nearest_neighbour_distances, axis=0) |
| 168 | ).any(axis=1).mean() |
| 169 | |
| 170 | density = (1. / float(self.nearest_k)) * ( |
| 171 | distance_real_fake < |
| 172 | np.expand_dims(real_nearest_neighbour_distances, axis=1) |
| 173 | ).sum(axis=0).mean() |
| 174 | |
| 175 | coverage = ( |
| 176 | distance_real_fake.min(axis=1) < |
| 177 | real_nearest_neighbour_distances |
| 178 | ).mean() |
| 179 | |
| 180 | d = dict(precision=precision, recall=recall, |
| 181 | density=density, coverage=coverage) |
| 182 | if self.realism: |
| 183 | """ |
| 184 | Large errors, even if they are rare, would undermine the usefulness of the metric. |
| 185 | We tackle this problem by discarding half of the hyperspheres with the largest radii. |
| 186 | In other words, the maximum in Equation 3 is not taken over all φr ∈ Φr but only over |
| 187 | those φr whose associated hypersphere is smaller than the median. |
| 188 | """ |
| 189 | mask = real_nearest_neighbour_distances < np.median(real_nearest_neighbour_distances) |
| 190 | |
| 191 | d['realism'] = ( |
| 192 | np.expand_dims(real_nearest_neighbour_distances[mask], axis=1)/distance_real_fake[mask] |
| 193 | ).max(axis=0) |
| 194 | return d |
| 195 | |
| 196 | def reset(self) -> None: |
| 197 | if not self.reset_real_features: |
nothing calls this directly
no test coverage detected