| from typing import Any |
|
|
| from copy import deepcopy |
| import torch |
| import torch.nn as nn |
| from tqdm import tqdm |
|
|
| from .base_postprocessor import BasePostprocessor |
| from .info import num_classes_dict |
|
|
|
|
| def distance(penultimate, target, metric='inner_product'): |
| if metric == 'inner_product': |
| return torch.sum(torch.mul(penultimate, target), dim=1) |
| elif metric == 'euclidean': |
| return -torch.sqrt(torch.sum((penultimate - target)**2, dim=1)) |
| elif metric == 'cosine': |
| return torch.cosine_similarity(penultimate, target, dim=1) |
| else: |
| raise ValueError('Unknown metric: {}'.format(metric)) |
|
|
|
|
| class SHEPostprocessor(BasePostprocessor): |
| def __init__(self, config): |
| super(SHEPostprocessor, self).__init__(config) |
| self.args = self.config.postprocessor.postprocessor_args |
| self.num_classes = num_classes_dict[self.config.dataset.name] |
| self.activation_log = None |
| self.setup_flag = False |
|
|
| def setup(self, net: nn.Module, id_loader_dict, ood_loader_dict): |
| if not self.setup_flag: |
| net.eval() |
|
|
| all_activation_log = [] |
| all_labels = [] |
| all_preds = [] |
| with torch.no_grad(): |
| for batch in tqdm(id_loader_dict['train'], |
| desc='Eval: ', |
| position=0, |
| leave=True): |
| data = batch['data'].cuda() |
| labels = batch['label'] |
| all_labels.append(deepcopy(labels)) |
|
|
| logits, features = net(data, return_feature=True) |
| all_activation_log.append(features.cpu()) |
| all_preds.append(logits.argmax(1).cpu()) |
|
|
| all_preds = torch.cat(all_preds) |
| all_labels = torch.cat(all_labels) |
| all_activation_log = torch.cat(all_activation_log) |
|
|
| self.activation_log = [] |
| for i in range(self.num_classes): |
| mask = torch.logical_and(all_labels == i, all_preds == i) |
| class_correct_activations = all_activation_log[mask] |
| self.activation_log.append( |
| class_correct_activations.mean(0, keepdim=True)) |
|
|
| self.activation_log = torch.cat(self.activation_log).cuda() |
| self.setup_flag = True |
| else: |
| pass |
|
|
| @torch.no_grad() |
| def postprocess(self, net: nn.Module, data: Any): |
| output, feature = net(data, return_feature=True) |
| pred = output.argmax(1) |
| conf = distance(feature, self.activation_log[pred], self.args.metric) |
| return pred, conf |
|
|