Spaces:
Running
on
Zero
Running
on
Zero
| import math | |
| import numpy as np | |
| import torch | |
| import torch.nn.functional as F | |
| from matplotlib import pyplot as plt | |
| from validation.metrics_flow import Fl_kitti_2015, correct_correspondences | |
| def compute_uncertainty_per_image(uncertainty_est, flow_gt, flow_est, mask_valid, dict_list_uncertainties): | |
| # uncert shape is #number_of_elements | |
| for uncertainty_name in uncertainty_est.keys(): | |
| if uncertainty_name == 'inference_parameters' or uncertainty_name == 'log_var_map' or \ | |
| uncertainty_name == 'weight_map' or uncertainty_name == 'warping_mask': | |
| continue | |
| if 'p_r' == uncertainty_name: | |
| # convert confidence map to uncertainty | |
| uncert = (1.0 / (uncertainty_est['p_r'] + 1e-6))[mask_valid.unsqueeze(1)] | |
| else: | |
| uncert = uncertainty_est[uncertainty_name][mask_valid.unsqueeze(1)] | |
| # compute metrics based on uncertainty | |
| uncertainty_metric_dict = compute_aucs(flow_gt, flow_est, uncert, intervals=50) | |
| if uncertainty_name not in dict_list_uncertainties.keys(): | |
| # for first image, create the list for each possible uncertainty type | |
| dict_list_uncertainties[uncertainty_name] = [] | |
| dict_list_uncertainties[uncertainty_name].append(uncertainty_metric_dict) | |
| return dict_list_uncertainties | |
| def estimate_average_variance_of_mixture_density(log_var_map): | |
| if isinstance(log_var_map[0], list): | |
| # several uncertainties estimation | |
| log_var = log_var_map[0][-1] | |
| proba_map = torch.nn.functional.softmax(log_var_map[1][-1], dim=1) | |
| else: | |
| log_var = log_var_map[0] | |
| proba_map = torch.nn.functional.softmax(log_var_map[1], dim=1) | |
| avg_variance = torch.sum(proba_map * torch.exp(log_var), dim=1, keepdim=True) # shape is b,1, h, w | |
| R = 1 | |
| var = torch.exp(log_var) | |
| I = torch.sum(proba_map * (1 - torch.exp(- math.sqrt(2)*R/torch.sqrt(var)))**2, dim=1, keepdim=True) | |
| return avg_variance, I | |
| def estimate_probability_of_confidence_interval_of_mixture_density(log_var_map, list_item=-1, R = 1.0): | |
| if isinstance(log_var_map[0], list): | |
| # several uncertainties estimation | |
| log_var = log_var_map[0][list_item] | |
| proba_map = torch.nn.functional.softmax(log_var_map[1][list_item], dim=1) | |
| else: | |
| log_var = log_var_map[0] | |
| proba_map = torch.nn.functional.softmax(log_var_map[1], dim=1) | |
| var = torch.exp(log_var) | |
| I = torch.sum(proba_map * (1 - torch.exp(- math.sqrt(2)*R/torch.sqrt(var)))**2, dim=1, keepdim=True) | |
| return I | |
| def save_sparsification_plot(output, save_path): | |
| EPE_uncer = output["sparse_curve"]["EPE"] | |
| EPE_perfect = output["opt_curve"]["EPE"] | |
| x = output["quants"] | |
| fig, axis = plt.subplots(1, 1, figsize=(25, 25)) | |
| axis.plot(x, np.float32(EPE_uncer) / EPE_uncer[0], marker='o', markersize=13, linewidth=5, label='estimated uncertainty') | |
| axis.plot(x, np.float32(EPE_perfect) / EPE_uncer[0], marker='o', markersize=13, linewidth=5, label='optimal') | |
| axis.set_ylabel('EPE normalized', fontsize='xx-large') | |
| axis.set_xlabel('Removing x fraction of pixels', fontsize='xx-large') | |
| axis.legend(bbox_to_anchor=(1.05, 1), loc=4, borderaxespad=0., fontsize='xx-large') | |
| fig.savefig('{}.png'.format(save_path), | |
| bbox_inches='tight') | |
| plt.close(fig) | |
| def compute_eigen_errors_v2(gt, pred, metrics=['EPE', 'PCK1', 'PCK5'], mask=None, reduce_mean=True): | |
| """Revised compute_eigen_errors function used for uncertainty metrics, with optional reduce_mean argument and (1-a1) computation | |
| """ | |
| results = [] | |
| # in shape (#number_elements, 2) | |
| # mask shape #number_of_elements | |
| if mask is not None: | |
| pred = pred[mask] | |
| gt = gt[mask] | |
| if "EPE" in metrics: | |
| epe = torch.norm(gt - pred, p=2, dim=1) | |
| if reduce_mean: | |
| epe = epe.mean().item() | |
| results.append(epe) | |
| if "Fl" in metrics: | |
| Fl = Fl_kitti_2015(pred, gt) / pred.shape[0] if pred.shape[0] != 0 else 0 | |
| results.append(Fl) | |
| if "PCK1" in metrics: | |
| px_1 = correct_correspondences(pred, gt, alpha=1.0, img_size=1.0) | |
| pck1 = px_1 / (pred.shape[0]) if pred.shape[0] != 0 else 0 | |
| results.append(pck1) | |
| if "PCK5" in metrics: | |
| px_5 = correct_correspondences(pred, gt, alpha=5.0, img_size=1.0) | |
| pck5 = px_5 / (pred.shape[0]) if pred.shape[0] != 0 else 0 | |
| results.append(pck5) | |
| return results | |
| def compute_aucs(gt, pred, uncert, intervals=50): | |
| """ | |
| Computation of sparsification curve, oracle curve and auc metric (area below the difference of the two curves), | |
| for each metrics (AEPE, PCK ..). | |
| Args: | |
| gt: gt flow field, shape #number elements, 2 | |
| pred: predicted flow field, shape #number elements, 2 | |
| uncert: predicted uncertainty measure, shape #number elements | |
| intervals: number of intervals to compute the sparsification plot | |
| Returns: | |
| dictionary with sparsification, oracle and AUC for each metric (here EPE, PCK1 and PCK5). | |
| """ | |
| uncertainty_metrics = ['EPE', 'PCK1', 'PCK5'] | |
| value_for_no_pixels = {'EPE': 0.0, 'PCK1': 1.0, 'PCK5': 1.0} | |
| # results dictionaries | |
| AUSE = {'EPE': 0, 'PCK1': 0, 'PCK5': 0} | |
| # revert order (high uncertainty first) | |
| uncert = -uncert # shape #number_elements | |
| # list the EPE, as the uncertainty. negative because we want high uncertainty first when taking percentile! | |
| true_uncert = - torch.norm(gt - pred, p=2, dim=1) | |
| # prepare subsets for sampling and for area computation | |
| quants = [100. / intervals * t for t in range(0, intervals)] | |
| plotx = [1. / intervals * t for t in range(0, intervals + 1)] | |
| # get percentiles for sampling and corresponding subsets | |
| thresholds = [np.percentile(uncert.cpu().numpy(), q) for q in quants] | |
| subs = [(uncert.ge(t)) for t in thresholds] | |
| # compute sparsification curves for each metric (add 0 for final sampling) | |
| # calculates the metrics for each interval | |
| sparse_curve = { | |
| m: [compute_eigen_errors_v2(gt, pred, metrics=[m], mask=sub, reduce_mean=True)[0] for sub in subs] + | |
| [value_for_no_pixels[m]] for m in uncertainty_metrics} | |
| # human-readable call | |
| ''' | |
| sparse_curve = {"rmse":[compute_eigen_errors_v2(gt,pred,metrics=["rmse"],mask=sub,reduce_mean=True)[0] for sub in subs]+[0], | |
| "a1":[compute_eigen_errors_v2(gt,pred,metrics=["a1"],mask=sub,reduce_mean=True)[0] for sub in subs]+[0], | |
| "abs_rel":[compute_eigen_errors_v2(gt,pred,metrics=["abs_rel"],mask=sub,reduce_mean=True)[0] for sub in subs]+[0]} | |
| ''' | |
| # get percentiles for optimal sampling and corresponding subsets (based on real EPE) | |
| opt_thresholds = [np.percentile(true_uncert.cpu().numpy(), q) for q in quants] | |
| opt_subs = [(true_uncert.ge(o)) for o in opt_thresholds] | |
| # compute sparsification curves for optimal sampling (add 0 for final sampling) | |
| opt_curve = {m: [compute_eigen_errors_v2(gt, pred, metrics=[m], mask=opt_sub, reduce_mean=True)[0] for opt_sub in | |
| opt_subs] + [value_for_no_pixels[m]] for m in uncertainty_metrics} | |
| # compute error and gain metrics | |
| for m in uncertainty_metrics: | |
| max = np.array(opt_curve[m]).max() + 1e-6 | |
| # normalize both to 0-1 first | |
| # error: subtract from method sparsification (first term) the oracle sparsification (second term) | |
| AUSE[m] = np.abs(np.trapz(np.array(sparse_curve[m])/max, x=plotx) - | |
| np.trapz(np.array(opt_curve[m])/max, x=plotx)) | |
| opt_curve[m] = np.array(opt_curve[m]) / max | |
| sparse_curve[m] = np.array(sparse_curve[m]) / max # normalizes each curve to 0 and 1 | |
| # returns a dictionary with AUSE and AURG for each metric | |
| return {'sparse_curve': sparse_curve, 'opt_curve': opt_curve, 'AUSE': AUSE} | |
| def compute_average_of_uncertainty_metrics(list_uncertainty_metrics, intervals=50): | |
| """The sparsification and AUC were computed per image pair. We here compute the average over all image pairs of | |
| a dataset. | |
| Args: | |
| list_uncertainty_metrics: list where each item corresponds to the output of compute_aucs for an image pair. | |
| intervals: number of intervals to compute the sparsification plot | |
| Returns: | |
| dictionary with sparsification, oracle and AUC for each metric (here EPE, PCK1 and PCK5), averaged over all | |
| elements of the provided list (should correspond to all image pairs of the dataset). | |
| """ | |
| # https://github.com/mattpoggi/mono-uncertainty/blob/master/evaluate.py | |
| quants = [1. / intervals * t for t in range(0, intervals + 1)] | |
| uncertainty_metrics = ['EPE', 'PCK1', 'PCK5'] | |
| keys = list(list_uncertainty_metrics[0].keys()) | |
| output_dict = {m: 0.0 for m in keys} | |
| for key in keys: | |
| # list all values | |
| output_dict[key] = {m: [dict[key][m] for dict in list_uncertainty_metrics] for m in uncertainty_metrics} | |
| if 'curve' in key: | |
| # average the curve values | |
| output_dict[key] = {m: np.array(output_dict[key][m], np.float64).mean(0).tolist() | |
| for m in uncertainty_metrics} | |
| else: | |
| output_dict[key] = {m: np.array(output_dict[key][m], np.float64).mean() for m in uncertainty_metrics} | |
| output_dict['quants'] = quants | |
| ''' | |
| output_dict['sparse_curve'] = {m: [dict['sparse_curve'][m] for dict in list_uncertainty_metrics] | |
| for m in uncertainty_metrics} | |
| output_dict['opt_curve'] = {m: [dict['opt_curve'][m] for dict in list_uncertainty_metrics] | |
| for m in uncertainty_metrics} | |
| output_dict['AUSE'] = {m: [dict['AUSE'][m] for dict in list_uncertainty_metrics] for m in uncertainty_metrics} | |
| output_dict['sparse_curve'] = {m: np.array(output_dict['sparse_curve'][m], np.float64).mean(0).tolist() | |
| for m in uncertainty_metrics} | |
| output_dict['opt_curve'] = {m: np.array(output_dict['opt_curve'][m], np.float64).mean(0).tolist() for m in | |
| uncertainty_metrics} | |
| output_dict['AUSE'] = {m: np.array(output_dict['AUSE'][m], np.float64).mean() for m in uncertainty_metrics} | |
| ''' | |
| return output_dict |