import json import os from pathlib import Path import numpy as np import PIL import torch from torchvision import datasets from torchvision.transforms import Compose from .common import ImageFolderWithPaths, SubsetSampler from .imagenet import ImageNet, ImageNetSubsampleValClasses def get_metadata(): metadata = Path(__file__).parent / 'objectnet_metadata' with open(metadata / 'folder_to_objectnet_label.json', 'r') as f: folder_map = json.load(f) folder_map = {v: k for k, v in folder_map.items()} with open(metadata / 'objectnet_to_imagenet_1k.json', 'r') as f: objectnet_map = json.load(f) with open(metadata / 'pytorch_to_imagenet_2012_id.json', 'r') as f: pytorch_map = json.load(f) pytorch_map = {v: k for k, v in pytorch_map.items()} with open(metadata / 'imagenet_to_label_2012_v2', 'r') as f: imagenet_map = {v.strip(): str(pytorch_map[i]) for i, v in enumerate(f)} folder_to_ids, class_sublist = {}, [] classnames = [] for objectnet_name, imagenet_names in objectnet_map.items(): imagenet_names = imagenet_names.split('; ') imagenet_ids = [int(imagenet_map[imagenet_name]) for imagenet_name in imagenet_names] class_sublist.extend(imagenet_ids) folder_to_ids[folder_map[objectnet_name]] = imagenet_ids class_sublist = sorted(class_sublist) class_sublist_mask = [(i in class_sublist) for i in range(1000)] classname_map = {v: k for k, v in folder_map.items()} return class_sublist, class_sublist_mask, folder_to_ids, classname_map def crop(img): width, height = img.size cropArea = (2, 2, width - 2, height - 2) img = img.crop(cropArea) return img class ObjectNetDataset(datasets.ImageFolder): def __init__(self, label_map, path, transform): self.label_map = label_map super().__init__(path, transform=transform) self.samples = [ d for d in self.samples if os.path.basename(os.path.dirname(d[0])) in self.label_map ] self.imgs = self.samples def __len__(self): return len(self.samples) def __getitem__(self, index): path, target = self.samples[index] sample = self.loader(path) if self.transform is not None: sample = self.transform(sample) label = os.path.basename(os.path.dirname(path)) return { 'images': sample, 'labels': self.label_map[label], 'image_paths': path } class ObjectNetBase(ImageNet): def __init__(self, *args, **kwargs): (self._class_sublist, self.class_sublist_mask, self.folders_to_ids, self.classname_map) = get_metadata() super().__init__(*args, **kwargs) self.classnames = sorted(list(self.folders_to_ids.keys())) self.rev_class_idx_map = {} self.class_idx_map = {} for idx, name in enumerate(self.classnames): self.rev_class_idx_map[idx] = self.folders_to_ids[name] for imagenet_idx in self.rev_class_idx_map[idx]: self.class_idx_map[imagenet_idx] = idx self.crop = crop self.preprocess = Compose([crop, self.preprocess]) self.classnames = [self.classname_map[c].lower() for c in self.classnames] def populate_train(self): pass def get_test_dataset(self): subdir = 'objectnet-1.0/images' valdir = os.path.join(self.location, subdir) label_map = {name: idx for idx, name in enumerate(sorted(list(self.folders_to_ids.keys())))} return ObjectNetDataset(label_map, valdir, transform=self.preprocess) def project_logits(self, logits, device): if isinstance(logits, list) or isinstance(logits, tuple): return [self.project_logits(l, device) for l in logits] if logits.shape[1] == 113: return logits if torch.is_tensor(logits): logits = logits.cpu().numpy() logits_projected = np.zeros((logits.shape[0], 113)) for k, v in self.rev_class_idx_map.items(): logits_projected[:, k] = np.max(logits[:, v], axis=1).squeeze() return torch.tensor(logits_projected).to(device) def scatter_weights(self, weights): if weights.size(1) == 1000: return weights new_weights = torch.ones((weights.size(0), 1000)).to(weights.device) * -10e8 for k, v in self.rev_class_idx_map.items(): for vv in v: new_weights[:, vv] = weights[:, k] return new_weights def accuracy(logits, targets, img_paths, args): assert logits.shape[1] == 113 preds = logits.argmax(dim=1) if torch.is_tensor(preds): preds = preds.cpu().numpy() if torch.is_tensor(targets): targets = targets.cpu().numpy() return np.sum(preds == targets), len(preds) class ObjectNetValClasses(ObjectNetBase): def get_test_sampler(self): idx_subsample_list = [range(x * 50, (x + 1) * 50) for x in self._class_sublist] idx_subsample_list = sorted([item for sublist in idx_subsample_list for item in sublist]) sampler = SubsetSampler(idx_subsample_list) return sampler def get_test_dataset(self): return ImageFolderWithPaths(self.get_test_path(), transform=self.preprocess) def project_labels(self, labels, device): projected_labels = [self.class_idx_map[int(label)] for label in labels] return torch.LongTensor(projected_labels).to(device) class ObjectNet(ObjectNetBase): def accuracy(self, logits, targets, img_paths, args): return accuracy(logits, targets, img_paths, args)