| from typing import Any |
| from copy import deepcopy |
|
|
| import numpy as np |
| import torch |
| import torch.nn as nn |
| import sklearn.covariance |
| from tqdm import tqdm |
|
|
| from .base_postprocessor import BasePostprocessor |
| from .info import num_classes_dict |
|
|
|
|
| class MDSPostprocessor(BasePostprocessor): |
| def __init__(self, config): |
| self.config = config |
| self.num_classes = num_classes_dict[self.config.dataset.name] |
| self.setup_flag = False |
|
|
| def setup(self, net: nn.Module, id_loader_dict, ood_loader_dict): |
| if not self.setup_flag: |
| |
| print('\n Estimating mean and variance from training set...') |
| all_feats = [] |
| all_labels = [] |
| all_preds = [] |
| with torch.no_grad(): |
| for batch in tqdm(id_loader_dict['train'], |
| desc='Setup: ', |
| position=0, |
| leave=True): |
| data, labels = batch['data'].cuda(), batch['label'] |
| logits, features = net(data, return_feature=True) |
| all_feats.append(features.cpu()) |
| all_labels.append(deepcopy(labels)) |
| all_preds.append(logits.argmax(1).cpu()) |
|
|
| all_feats = torch.cat(all_feats) |
| all_labels = torch.cat(all_labels) |
| all_preds = torch.cat(all_preds) |
| |
| train_acc = all_preds.eq(all_labels).float().mean() |
| print(f' Train acc: {train_acc:.2%}') |
|
|
| |
| self.class_mean = [] |
| centered_data = [] |
| for c in range(self.num_classes): |
| class_samples = all_feats[all_labels.eq(c)].data |
| self.class_mean.append(class_samples.mean(0)) |
| centered_data.append(class_samples - |
| self.class_mean[c].view(1, -1)) |
|
|
| self.class_mean = torch.stack( |
| self.class_mean) |
|
|
| group_lasso = sklearn.covariance.EmpiricalCovariance( |
| assume_centered=False) |
| group_lasso.fit( |
| torch.cat(centered_data).cpu().numpy().astype(np.float32)) |
| |
| self.precision = torch.from_numpy(group_lasso.precision_).float() |
| self.setup_flag = True |
| else: |
| pass |
|
|
| @torch.no_grad() |
| def postprocess(self, net: nn.Module, data: Any): |
| logits, features = net(data, return_feature=True) |
| pred = logits.argmax(1) |
|
|
| class_scores = torch.zeros((logits.shape[0], self.num_classes)) |
| for c in range(self.num_classes): |
| tensor = features.cpu() - self.class_mean[c].view(1, -1) |
| class_scores[:, c] = -torch.matmul( |
| torch.matmul(tensor, self.precision), tensor.t()).diag() |
|
|
| conf = torch.max(class_scores, dim=1)[0] |
| return pred, conf |
|
|