from typing import Any import numpy as np import torch import torch.nn as nn from tqdm import tqdm from .base_postprocessor import BasePostprocessor normalizer = lambda x: x / np.linalg.norm(x, axis=-1, keepdims=True) + 1e-10 class DICEPostprocessor(BasePostprocessor): def __init__(self, config): super(DICEPostprocessor, self).__init__(config) self.args = self.config.postprocessor.postprocessor_args self.p = self.args.p self.mean_act = None self.masked_w = None self.args_dict = self.config.postprocessor.postprocessor_sweep self.setup_flag = False def setup(self, net: nn.Module, id_loader_dict, ood_loader_dict): if not self.setup_flag: activation_log = [] net.eval() with torch.no_grad(): for batch in tqdm(id_loader_dict['train'], desc='Setup: ', position=0, leave=True): data = batch['data'].cuda() data = data.float() _, feature = net(data, return_feature=True) activation_log.append(feature.data.cpu().numpy()) activation_log = np.concatenate(activation_log, axis=0) self.mean_act = activation_log.mean(0) self.setup_flag = True else: pass def calculate_mask(self, w): contrib = self.mean_act[None, :] * w.data.squeeze().cpu().numpy() self.thresh = np.percentile(contrib, self.p) mask = torch.Tensor((contrib > self.thresh)).cuda() self.masked_w = w * mask @torch.no_grad() def postprocess(self, net: nn.Module, data: Any): fc_weight, fc_bias = net.get_fc() if self.masked_w is None: self.calculate_mask(torch.from_numpy(fc_weight).cuda()) _, feature = net(data, return_feature=True) vote = feature[:, None, :] * self.masked_w output = vote.sum(2) + torch.from_numpy(fc_bias).cuda() _, pred = torch.max(torch.softmax(output, dim=1), dim=1) energyconf = torch.logsumexp(output.data.cpu(), dim=1) return pred, energyconf def set_hyperparam(self, hyperparam: list): self.p = hyperparam[0] def get_hyperparam(self): return self.p