├── OneForAll ├── LICENSE ├── README.md ├── README_ch.md ├── configs │ ├── common.py │ ├── test_vitbase_jointtraining_config.py │ └── vitbase_jointtraining_config.py ├── data │ ├── __init__.py │ ├── build.py │ ├── build_cls.py │ ├── build_segmentation.py │ ├── build_trafficsign.py │ ├── datasets │ │ ├── __init_.py │ │ ├── bdd100k_datasets.py │ │ ├── cityscapes_datasets.py │ │ ├── fgvc_dataset.py │ │ └── seg_dataset.py │ ├── samplers │ │ ├── clsaware_reader.py │ │ ├── reader.py │ │ └── twosource_sampler.py │ ├── transforms │ │ ├── __init__.py │ │ ├── batch_ops │ │ │ └── batch_operators.py │ │ ├── build.py │ │ ├── detection_ops.py │ │ ├── ops │ │ │ └── fmix.py │ │ ├── random_erasing.py │ │ └── seg_transforms.py │ ├── unitest.py │ └── util │ │ └── coco_hdf5.py ├── detectron2 │ ├── checkpoint │ │ ├── __init__.py │ │ ├── c2_model_loading.py │ │ ├── catalog.py │ │ └── detection_checkpoint.py │ ├── config │ │ ├── __init__.py │ │ ├── compat.py │ │ ├── config.py │ │ ├── defaults.py │ │ ├── instantiate.py │ │ └── lazy.py │ ├── data │ │ ├── __init__.py │ │ ├── benchmark.py │ │ ├── build.py │ │ ├── catalog.py │ │ ├── common.py │ │ ├── dataset_mapper.py │ │ ├── datasets │ │ │ ├── README.md │ │ │ ├── __init__.py │ │ │ ├── builtin.py │ │ │ ├── builtin_meta.py │ │ │ ├── cityscapes.py │ │ │ ├── cityscapes_panoptic.py │ │ │ ├── coco.py │ │ │ ├── coco_panoptic.py │ │ │ ├── lvis.py │ │ │ ├── lvis_v0_5_categories.py │ │ │ ├── lvis_v1_categories.py │ │ │ ├── pascal_voc.py │ │ │ └── register_coco.py │ │ ├── detection_utils.py │ │ ├── samplers │ │ │ ├── __init__.py │ │ │ ├── distributed_sampler.py │ │ │ └── grouped_batch_sampler.py │ │ └── transforms │ │ │ ├── __init__.py │ │ │ ├── augmentation.py │ │ │ ├── augmentation_impl.py │ │ │ └── transform.py │ ├── engine │ │ ├── __init__.py │ │ ├── defaults.py │ │ ├── hooks.py │ │ ├── launch.py │ │ ├── train_loop.py │ │ └── train_loop_moe.py │ ├── evaluation │ │ ├── __init__.py │ │ ├── cityscapes_evaluation.py │ │ ├── coco_evaluation.py │ │ ├── evaluator.py │ │ ├── fast_eval_api.py │ │ ├── lvis_evaluation.py │ │ ├── panoptic_evaluation.py │ │ ├── pascal_voc_evaluation.py │ │ ├── rotated_coco_evaluation.py │ │ ├── sem_seg_evaluation.py │ │ └── testing.py │ ├── solver │ │ ├── __init__.py │ │ ├── build.py │ │ └── lr_scheduler.py │ ├── structures │ │ ├── __init__.py │ │ ├── boxes.py │ │ ├── image_list.py │ │ ├── instances.py │ │ ├── keypoints.py │ │ ├── masks.py │ │ └── rotated_boxes.py │ └── utils │ │ ├── README.md │ │ ├── __init__.py │ │ ├── analysis.py │ │ ├── collect_env.py │ │ ├── colormap.py │ │ ├── comm.py │ │ ├── env.py │ │ ├── events.py │ │ ├── file_io.py │ │ ├── logger.py │ │ ├── memory.py │ │ ├── registry.py │ │ ├── serialize.py │ │ ├── testing.py │ │ ├── video_visualizer.py │ │ └── visualizer.py ├── engine │ └── hooks.py ├── evaluation │ ├── __init__.py │ ├── clas_evaluator.py │ ├── coco_utils.py │ ├── cocodet_evaluator.py │ ├── common_cls_evaluator.py │ ├── evaluator.py │ ├── json_results.py │ ├── rank.py │ ├── rank_cylib │ │ ├── Makefile │ │ ├── __init__.py │ │ ├── rank_cy.c │ │ ├── rank_cy.pyx │ │ ├── roc_cy.c │ │ ├── roc_cy.pyx │ │ ├── setup.py │ │ └── test_cython.py │ ├── seg_evaluator.py │ ├── segmentation_evaluator.py │ └── testing.py ├── fastreid │ ├── data │ │ ├── __init__.py │ │ ├── common.py │ │ ├── data_utils.py │ │ ├── datasets │ │ │ ├── __init__.py │ │ │ ├── bases.py │ │ │ └── cocodet.py │ │ ├── samplers │ │ │ ├── __init__.py │ │ │ ├── data_sampler.py │ │ │ └── triplet_sampler.py │ │ └── transforms │ │ │ └── autoaugment.py │ └── utils │ │ ├── __init__.py │ │ ├── checkpoint.py │ │ ├── file_io.py │ │ └── registry.py ├── layers │ └── any_softmax.py ├── modeling │ ├── __init__.py │ ├── backbones │ │ ├── __init__.py │ │ ├── moe_layer.py │ │ ├── resnet_detr.py │ │ ├── super_module │ │ │ ├── Linear_super.py │ │ │ ├── __init__.py │ │ │ ├── multihead_super.py │ │ │ └── qkv_super.py │ │ ├── swin_transformer.py │ │ ├── vision_transformer.py │ │ ├── vision_transformer_super.py │ │ ├── vision_transformer_super_hardpolicy_moe.py │ │ ├── vit.py │ │ └── vit_cnn.py │ ├── bbox_utils.py │ ├── heads │ │ ├── cbam.py │ │ ├── classification.py │ │ ├── cls_head.py │ │ ├── detr.py │ │ ├── detr_head.py │ │ ├── embedding_head.py │ │ ├── faster_rcnn.py │ │ ├── seg_dmnet_head.py │ │ ├── setr_head.py │ │ ├── simple_cls_head.py │ │ └── yolov3.py │ ├── initializer.py │ ├── layers.py │ ├── losses │ │ ├── __init__.py │ │ ├── cross_entroy_loss.py │ │ ├── detr_loss.py │ │ ├── iou_loss.py │ │ ├── seg_loss.py │ │ ├── triplet_loss.py │ │ └── utils.py │ ├── meta_arch │ │ ├── multitask.py │ │ └── multitask_v2.py │ ├── post_process.py │ └── transformers │ │ ├── position_encoding.py │ │ └── transformer_detr.py ├── requirements.txt ├── scripts │ ├── env.sh │ ├── test.sh │ └── train.sh ├── solver │ └── build.py ├── tools │ ├── eval.py │ ├── moe_group_utils.py │ ├── monitor.py │ ├── ufo_test.py │ └── ufo_train.py └── utils │ ├── __init__.py │ ├── comm.py │ ├── compute_dist.py │ ├── config.py │ ├── events.py │ ├── file_io.py │ ├── logger.py │ └── misc.py ├── README.md └── README_ch.md /OneForAll/README.md: -------------------------------------------------------------------------------- 1 | English | [简体中文](README_ch.md) 2 | 3 | # Track1 Codebase 4 | 5 | ## Instructions 6 | 7 | We provide a three task AllInOne joint training method of classification, detection, and segmentation. 8 | 9 | Demo is based on 8 A100 cards. 10 | 11 | ### Environment 12 | 13 | Please use python3.7 and cuda11.0. 14 | 15 | ```bash 16 | pip install -r requirements.txt 17 | ``` 18 | 19 | ### Data Configuration 20 | 21 | After downloading the training and testing data from [official data download address](https://aistudio.baidu.com/aistudio/datasetdetail/203253), decompress the data into the 'datasets' folder (if it does not exist, please create it first) 22 | 23 | ### Training 24 | 25 | We provide the pre-training weights on the object365 dataset, download the pre-training weights to the 'pretrained' folder (if it does not exist, please create it first), and then use the following script to start training 26 | 27 | ```bash 28 | sh scripts/train.sh 29 | ``` 30 | 31 | ### Inference 32 | 33 | We provide the weights of our three-task AllinOne joint training, which can be downloaded to the 'pretrained' folder (if it does not exist, please create it first), and then use the following script to start inference 34 | 35 | ```bash 36 | sh scripts/test.sh 37 | ``` 38 | -------------------------------------------------------------------------------- /OneForAll/README_ch.md: -------------------------------------------------------------------------------- 1 | 简体中文 | [English](README.md) 2 | 3 | # Track1 Codebase 4 | 5 | ## 使用方案 6 | 7 | 提供了分类、检测、分割AllInOne三任务联合训练方法 8 | Demo为单机(8卡)40G A100的训练方法 9 | 10 | ### 环境配置 11 | 12 | 运行环境为python3.7,cuda11.0测试机器为A100。使用pip的安装依赖包,如下: 13 | ```bash 14 | pip install -r requirements.txt 15 | ``` 16 | 17 | ### 数据配置 18 | 19 | 从[官方数据下载地址](https://aistudio.baidu.com/aistudio/datasetdetail/203253)下载训练和测试数据后,将数据解压到datasets文件夹中(若不存在,请先创建) 20 | 21 | ### 训练 22 | 23 | 我们提供了object365数据集的预训练权重,下载预训练权重至pretrained文件夹中(若不存在,请先创建),后使用以下脚本在训练集上启动训练 24 | 25 | ```bash 26 | sh scripts/train.sh 27 | ``` 28 | 29 | ### 预测 30 | 31 | 我们提供了我们训练的三任务AllinOne联合训练的权重,可下载权重至pretrained文件夹中(若不存在,请先创建),后使用以下脚本在测试集上启动预测 32 | 33 | ```bash 34 | sh scripts/test.sh 35 | ``` 36 | -------------------------------------------------------------------------------- /OneForAll/configs/common.py: -------------------------------------------------------------------------------- 1 | """configs/common.py 2 | """ 3 | from detectron2.config import LazyCall as L 4 | # from ufo.solver.build import get_default_optimizer_params, maybe_add_gradient_clipping 5 | from solver.build import build_lr_optimizer_lazy 6 | from solver.build import build_lr_scheduler_lazy 7 | 8 | 9 | optimizer = L(build_lr_optimizer_lazy)( 10 | base_lr=0.03, 11 | weight_decay=0.0001, 12 | weight_decay_norm=0.0001, 13 | contiguous=True, 14 | bias_lr_factor=2.0, 15 | momentum=0.9, 16 | grad_clip_enabled=True, 17 | grad_clip_norm=5.0, #TODO determine exact value of grad_clip 18 | lr_multiplier=L(build_lr_scheduler_lazy)( 19 | iters_per_epoch=503, 20 | max_iters=50000, 21 | max_epoch=120, 22 | warmup_iters=1000, 23 | warmup_factor=0.1, 24 | warmup_method='linear', 25 | delay_epochs=0, 26 | solver_steps=[40, 90], 27 | solver_gamma=0.1, 28 | eta_min=7e-8, 29 | base_lr=5e-1, 30 | sched='CosineAnnealingLR', 31 | ) 32 | ) 33 | 34 | 35 | train = dict( 36 | output_dir="output", 37 | sacred=dict(enabled=True), 38 | init_checkpoint="", 39 | amp=dict(enabled=True), # options for Automatic Mixed Precision 40 | cudnn_benchmark=True, 41 | ddp=dict( # options for DistributedDataParallel 42 | broadcast_buffers=False, 43 | # find_unused_parameters=False, 44 | find_unused_parameters=True, 45 | fp16_compression=False, 46 | ), 47 | max_iter=90000, 48 | checkpointer=dict(period=2000, max_to_keep=1), # options for PeriodicCheckpointer 49 | eval_period=5000, 50 | log_period=20, 51 | device="gpu", 52 | ) 53 | -------------------------------------------------------------------------------- /OneForAll/data/__init__.py: -------------------------------------------------------------------------------- 1 | """__init__.py 2 | """ -------------------------------------------------------------------------------- /OneForAll/data/build_segmentation.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import os 16 | import random 17 | import paddle 18 | import paddleseg 19 | 20 | from utils import comm 21 | import numpy as np 22 | from fastreid.data import samplers 23 | from fastreid.data.datasets import DATASET_REGISTRY 24 | from data.datasets.cityscapes_datasets import * 25 | from data.datasets.bdd100k_datasets import * 26 | 27 | 28 | def build_segmentation_dataset(dataset_name=None, transforms=[], dataset_root=None, 29 | mode='train', **kwargs): 30 | """ 31 | Build Cityscapes Datasets 32 | """ 33 | data_set = DATASET_REGISTRY.get(dataset_name)(dataset_root=dataset_root, transforms=transforms, mode=mode, **kwargs) 34 | print("data_set:", data_set) 35 | print('{} has {} samples'.format(dataset_name, len(data_set.file_list))) # data_set.roidbs 36 | return data_set 37 | 38 | 39 | def build_segmentation_trainloader(data_set, is_train=True, total_batch_size=0, \ 40 | worker_num=0, drop_last=True, **kwargs): 41 | """ 42 | Build a dataloader for Cityscapse segmentation. 43 | Returns: 44 | paddle.io.DataLoader: a dataloader. 45 | """ 46 | 47 | mini_batch_size = total_batch_size // comm.get_world_size() 48 | 49 | if is_train: 50 | # 无限流 51 | sampler = samplers.TrainingSampler(data_set) 52 | batch_sampler = paddle.io.BatchSampler(sampler=sampler, batch_size=mini_batch_size) 53 | worker_init_fn = np.random.seed(random.randint(0, 100000)) 54 | else: 55 | # 有序分布流 56 | _batch_sampler = samplers.OrderInferenceSampler(data_set, mini_batch_size) 57 | batch_sampler = paddle.io.BatchSampler(sampler=_batch_sampler, batch_size=mini_batch_size) 58 | # batch_sampler = paddle.io.BatchSampler(dataset=data_set, batch_size=mini_batch_size, \ 59 | # shuffle=False, drop_last=drop_last) 60 | worker_init_fn=None 61 | 62 | dataloader = paddle.io.DataLoader( 63 | dataset=data_set, 64 | batch_sampler=batch_sampler, 65 | num_workers=worker_num, 66 | return_list=True, 67 | worker_init_fn=worker_init_fn) 68 | return dataloader 69 | 70 | 71 | 72 | def build_segementation_test_dataset(dataset_name=None, transforms=[], dataset_root=None, 73 | mode='val', is_padding=True, **kwargs): 74 | data_set = DATASET_REGISTRY.get(dataset_name)(dataset_root=dataset_root, transforms=transforms, mode=mode, **kwargs) 75 | 76 | print('{} has {} samples'.format(dataset_name, len(data_set.file_list))) # data_set.roidbs 77 | if is_padding: 78 | # record sample number 79 | data_set.num_valid_samples = len(data_set) 80 | # 在末尾随机填充若干data.gallery数据使得test_items的长度能被world_size整除,以保证每个卡上的数据量均分; 81 | test_items = data_set.file_list 82 | world_size = comm.get_world_size() 83 | if len(test_items)%world_size != 0: 84 | idx_list = list(range(len(test_items))) 85 | random_idx_list = [random.choice(idx_list) for _ in range(world_size - len(test_items)%world_size)] 86 | test_items += [test_items[idx] for idx in random_idx_list] 87 | data_set.file_list = test_items 88 | print('{} has {} samples after padding'.format(dataset_name, len(data_set))) #data_set.roidbs 89 | 90 | return data_set 91 | 92 | -------------------------------------------------------------------------------- /OneForAll/data/build_trafficsign.py: -------------------------------------------------------------------------------- 1 | # !/usr/bin/env python3 2 | 3 | import os 4 | import random 5 | import logging 6 | from collections.abc import Mapping 7 | 8 | import numpy as np 9 | import paddle 10 | 11 | from utils import comm 12 | from fastreid.data import samplers 13 | from fastreid.data.datasets import DATASET_REGISTRY 14 | from tools import moe_group_utils 15 | from data.transforms import detection_ops 16 | from data.transforms.detection_ops import Compose, BatchCompose 17 | 18 | 19 | _root = os.getenv("FASTREID_DATASETS", "datasets") 20 | 21 | 22 | def fast_batch_collator(batched_inputs): 23 | """ 24 | A simple batch collator for most common reid tasks. 25 | There is no need of transforming data to GPU in fast_batch_collator 26 | """ 27 | elem = batched_inputs[0] 28 | if isinstance(elem, np.ndarray): 29 | # return paddle.to_tensor(np.concatenate([ np.expand_dims(elem, axis=0) for elem in batched_inputs], axis=0)) 30 | return np.concatenate([np.expand_dims(elem, axis=0) for elem in batched_inputs], axis=0) 31 | 32 | elif isinstance(elem, Mapping): 33 | return {key: fast_batch_collator([d[key] for d in batched_inputs]) for key in elem} 34 | elif isinstance(elem, float): 35 | # return paddle.to_tensor(batched_inputs, dtype=paddle.float64) 36 | return np.array(batched_inputs, dtype=np.float64) 37 | elif isinstance(elem, int): 38 | #return paddle.to_tensor(batched_inputs) 39 | return np.array(batched_inputs) 40 | elif isinstance(elem, str): 41 | return batched_inputs 42 | 43 | 44 | def build_cocodet_test_loader_lazy(data_set, total_batch_size=0, num_workers=0, is_train=False, 45 | batch_transforms=[], shuffle=True, drop_last=True, collate_batch=True): 46 | """ 47 | Build a dataloader for coco detection with some default features. 48 | 49 | Returns: 50 | paddle.io.DataLoader: a dataloader. 51 | """ 52 | assert is_train == False 53 | num_classes = 80 # hard code 54 | batch_transforms = BatchCompose(batch_transforms, num_classes, collate_batch) 55 | batch_sampler = paddle.io.BatchSampler(dataset=data_set, batch_size=total_batch_size, drop_last=False, shuffle=False) 56 | data_loader = paddle.io.DataLoader( 57 | dataset=data_set, 58 | batch_sampler=batch_sampler, 59 | collate_fn=batch_transforms, 60 | num_workers=num_workers, 61 | return_list=False, 62 | use_shared_memory=False, 63 | ) 64 | return data_loader 65 | 66 | 67 | def build_cocodet_loader_lazy(data_set, total_batch_size=0, num_workers=0, is_train=False, 68 | batch_transforms=[], shuffle=True, drop_last=True, collate_batch=True): 69 | """ 70 | Build a dataloader for coco detection with some default features. 71 | 72 | Returns: 73 | paddle.io.DataLoader: a dataloader. 74 | """ 75 | mini_batch_size = total_batch_size // comm.get_world_size() 76 | num_classes = 80 # hard code 77 | batch_transforms = BatchCompose(batch_transforms, num_classes, collate_batch) 78 | 79 | if is_train: 80 | # 无限流 81 | sampler = samplers.TrainingSampler(data_set, shuffle=shuffle) 82 | else: 83 | # 有序分布流 84 | sampler = samplers.OrderInferenceSampler(data_set, mini_batch_size) 85 | 86 | batch_sampler = paddle.io.BatchSampler(sampler=sampler, batch_size=mini_batch_size) 87 | data_loader = paddle.io.DataLoader( 88 | dataset=data_set, 89 | batch_sampler=batch_sampler, 90 | collate_fn=batch_transforms, 91 | num_workers=num_workers, 92 | return_list=False, 93 | use_shared_memory=False, 94 | ) 95 | 96 | return data_loader 97 | 98 | 99 | def build_cocodet_set(dataset_name=None, transforms=[], dataset_dir=_root, image_dir='train2017', 100 | anno_path='annotations/instances_train2017.json', 101 | is_padding=False, 102 | data_fields=['image', 'gt_bbox', 'gt_class', 'is_crowd'], **kwargs): 103 | """ 104 | build train_set for detection 105 | """ 106 | data_set = DATASET_REGISTRY.get(dataset_name)(dataset_dir=os.path.join(dataset_dir), image_dir=image_dir, 107 | anno_path=anno_path, data_fields=data_fields) 108 | num_classes = 80 # hard code 109 | transforms = Compose(transforms, num_classes=num_classes) 110 | data_set.parse_dataset() 111 | data_set.set_transform(transforms) 112 | data_set.set_kwargs(**kwargs) 113 | print('{} has {} samples'.format(dataset_name, len(data_set))) #data_set.roidbs 114 | if is_padding: 115 | # record sample number 116 | data_set.num_valid_samples = len(data_set) 117 | # 在末尾随机填充若干data.gallery数据使得test_items的长度能被world_size整除,以保证每个卡上的数据量均分; 118 | test_items = data_set.roidbs 119 | world_size = comm.get_world_size() 120 | if len(test_items)%world_size != 0: 121 | idx_list = list(range(len(test_items))) 122 | random_idx_list = [random.choice(idx_list) for _ in range(world_size - len(test_items)%world_size)] 123 | test_items += [test_items[idx] for idx in random_idx_list] 124 | data_set.roidbs = test_items 125 | print('{} has {} samples after padding'.format(dataset_name, len(data_set))) #data_set.roidbs 126 | return data_set -------------------------------------------------------------------------------- /OneForAll/data/datasets/__init_.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | from data.datasets.fgvc_dataset import FGVCDataset 4 | 5 | __all__ = [k for k in globals().keys() if "builtin" not in k and not k.startswith("_")] -------------------------------------------------------------------------------- /OneForAll/data/datasets/bdd100k_datasets.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import os 16 | import glob 17 | 18 | from data.datasets.seg_dataset import Dataset 19 | from paddleseg.cvlibs import manager 20 | from data.transforms.seg_transforms import Compose 21 | from fastreid.data.datasets import DATASET_REGISTRY 22 | 23 | 24 | @DATASET_REGISTRY.register() 25 | class BDD100K(Dataset): 26 | """ 27 | Args: 28 | transforms (list): Transforms for image. 29 | dataset_root (str): Cityscapes dataset directory. 30 | mode (str, optional): Which part of dataset to use. it is one of ('train', 'val', 'test'). Default: 'train'. 31 | edge (bool, optional): Whether to compute edge while training. Default: False 32 | """ 33 | NUM_CLASSES = 19 34 | dataset_name = 'BDD100K' 35 | 36 | def __init__(self, transforms, dataset_root, mode='train', edge=False): 37 | self.dataset_root = dataset_root 38 | self.transforms = Compose(transforms) 39 | self.file_list = list() 40 | mode = mode.lower() 41 | self.mode = mode 42 | # self.num_classes = self.NUM_CLASSES 43 | self.ignore_index = 255 44 | self.edge = edge 45 | 46 | if mode not in ['train', 'val', 'test']: 47 | raise ValueError( 48 | "mode should be 'train', 'val' or 'test', but got {}.".format( 49 | mode)) 50 | 51 | if self.transforms is None: 52 | raise ValueError("`transforms` is necessary, but it is None.") 53 | 54 | img_dir = os.path.join(self.dataset_root, 'images') 55 | label_dir = os.path.join(self.dataset_root, 'label') 56 | if self.dataset_root is None or not os.path.isdir( 57 | self.dataset_root) or not os.path.isdir( 58 | img_dir) or not os.path.isdir(label_dir): 59 | raise ValueError( 60 | "The dataset is not Found or the folder structure is nonconfoumance." 61 | ) 62 | 63 | label_files = sorted( 64 | glob.glob( 65 | os.path.join(label_dir, mode, '*.png'))) 66 | img_files = sorted( 67 | glob.glob(os.path.join(img_dir, mode, '*.jpg'))) 68 | 69 | self.file_list = [ 70 | [img_path, label_path] 71 | for img_path, label_path in zip(img_files, label_files) 72 | ] 73 | 74 | 75 | @DATASET_REGISTRY.register() 76 | class InferDataset(Dataset): 77 | """ 78 | Infer Dataset 79 | """ 80 | NUM_CLASSES = 19 81 | dataset_name = 'InferDataset' 82 | 83 | def __init__(self, 84 | mode, 85 | dataset_root, 86 | transforms, 87 | num_classes=19, 88 | img_channels=3, 89 | ignore_index=255, 90 | edge=False): 91 | self.dataset_root = dataset_root 92 | self.transforms = Compose(transforms, img_channels=img_channels) 93 | self.file_list = list() 94 | self.mode = mode.lower() 95 | self.num_classes = 19 96 | self.img_channels = img_channels 97 | self.ignore_index = ignore_index 98 | self.edge = edge 99 | 100 | if self.mode not in ['train', 'val', 'test']: 101 | raise ValueError( 102 | "mode should be 'train', 'val' or 'test', but got {}.".format( 103 | self.mode)) 104 | 105 | img_dir = os.path.join(self.dataset_root, 'images') 106 | if self.dataset_root is None or not os.path.isdir( 107 | self.dataset_root) or not os.path.isdir(img_dir): 108 | raise ValueError( 109 | "The dataset is not Found or the folder structure is nonconfoumance." 110 | ) 111 | 112 | img_files = sorted( 113 | glob.glob(os.path.join(img_dir, self.mode, '*.jpg'))) 114 | 115 | self.file_list = [(idx, img_path) for idx, img_path in enumerate(img_files)] 116 | self.id2path = {} 117 | for idx, img_path in enumerate(img_files): 118 | self.id2path[idx] = os.path.basename(img_path) 119 | 120 | def __getitem__(self, idx): 121 | data = {} 122 | data['trans_info'] = [] 123 | im_id, image_path = self.file_list[idx] 124 | data['image'] = image_path 125 | data['im_path'] = image_path 126 | data['im_id'] = im_id 127 | data['id2path'] = [self.id2path] 128 | # If key in gt_fields, the data[key] have transforms synchronous. 129 | data['gt_fields'] = [] 130 | if self.mode == 'test': 131 | data = self.transforms(data) 132 | return data 133 | 134 | def __len__(self): 135 | return len(self.file_list) -------------------------------------------------------------------------------- /OneForAll/data/datasets/cityscapes_datasets.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import os 16 | import glob 17 | 18 | from data.datasets.seg_dataset import Dataset 19 | from data.transforms.seg_transforms import Compose 20 | from fastreid.data.datasets import DATASET_REGISTRY 21 | 22 | 23 | @DATASET_REGISTRY.register() 24 | class Cityscapes(Dataset): 25 | """ 26 | Cityscapes dataset `https://www.cityscapes-dataset.com/`. 27 | The folder structure is as follow: 28 | 29 | cityscapes 30 | | 31 | |--leftImg8bit 32 | | |--train 33 | | |--val 34 | | |--test 35 | | 36 | |--gtFine 37 | | |--train 38 | | |--val 39 | | |--test 40 | 41 | Make sure there are **labelTrainIds.png in gtFine directory. If not, please run the conver_cityscapes.py in tools. 42 | 43 | Args: 44 | transforms (list): Transforms for image. 45 | dataset_root (str): Cityscapes dataset directory. 46 | mode (str, optional): Which part of dataset to use. it is one of ('train', 'val', 'test'). Default: 'train'. 47 | edge (bool, optional): Whether to compute edge while training. Default: False 48 | """ 49 | NUM_CLASSES = 19 50 | dataset_name='Cityscapes' 51 | 52 | def __init__(self, transforms, dataset_root, mode='train', edge=False): 53 | self.dataset_root = dataset_root 54 | self.transforms = Compose(transforms) 55 | self.file_list = list() 56 | mode = mode.lower() 57 | self.mode = mode 58 | # self.num_classes = self.NUM_CLASSES 59 | self.ignore_index = 255 60 | self.edge = edge 61 | 62 | if mode not in ['train', 'val', 'test']: 63 | raise ValueError( 64 | "mode should be 'train', 'val' or 'test', but got {}.".format( 65 | mode)) 66 | 67 | if self.transforms is None: 68 | raise ValueError("`transforms` is necessary, but it is None.") 69 | 70 | img_dir = os.path.join(self.dataset_root, 'leftImg8bit') 71 | label_dir = os.path.join(self.dataset_root, 'gtFine') 72 | if self.dataset_root is None or not os.path.isdir( 73 | self.dataset_root) or not os.path.isdir( 74 | img_dir) or not os.path.isdir(label_dir): 75 | raise ValueError( 76 | "The dataset is not Found or the folder structure is nonconfoumance." 77 | ) 78 | 79 | label_files = sorted( 80 | glob.glob( 81 | os.path.join(label_dir, mode, '*', 82 | '*_gtFine_labelTrainIds.png'))) 83 | img_files = sorted( 84 | glob.glob(os.path.join(img_dir, mode, '*', '*_leftImg8bit.png'))) 85 | 86 | self.file_list = [ 87 | [img_path, label_path] 88 | for img_path, label_path in zip(img_files, label_files) 89 | ] 90 | -------------------------------------------------------------------------------- /OneForAll/data/datasets/fgvc_dataset.py: -------------------------------------------------------------------------------- 1 | # !/usr/bin/env python3 2 | """Fine-Grained Visual Classification 3 | """ 4 | from fastreid.data.datasets import DATASET_REGISTRY 5 | from fastreid.data.datasets.bases import ImageDataset 6 | 7 | import os 8 | import numpy as np 9 | 10 | 11 | @DATASET_REGISTRY.register() 12 | class FGVCDataset(ImageDataset): 13 | dataset_name = "FGVCDataset" 14 | 15 | def __init__(self, root='', **kwargs): 16 | self.root = root 17 | self.train_dataset_dir = kwargs['train_dataset_dir'] 18 | self.test_dataset_dir = kwargs['test_dataset_dir'] 19 | self.train_label = kwargs['train_label'] 20 | self.test_label = kwargs['test_label'] 21 | self.dict_label = self.init_dict_label(f'{self.train_label}') 22 | train = self.process_dir(self.train_dataset_dir, self.train_label) 23 | query = self.process_dir(self.test_dataset_dir, self.test_label) 24 | gallery = [] 25 | super().__init__(train, query, gallery, **kwargs) 26 | 27 | def init_dict_label(self, label_dir): 28 | dict_label = {} 29 | count = 0 30 | with open(label_dir, 'r') as f: 31 | list_line = f.readlines() 32 | for line in list_line: 33 | line = line.strip() 34 | path, class_id = line.split() 35 | if class_id not in dict_label.keys(): 36 | dict_label[class_id] = count 37 | count += 1 38 | return dict_label 39 | 40 | def process_dir(self, img_dir, label_dir): 41 | data = [] 42 | with open(label_dir, 'r') as f: 43 | list_line = f.readlines() 44 | im_id = 0 45 | for line in list_line: 46 | line = line.strip() 47 | path, class_id = line.split() 48 | 49 | img_name = os.path.join(img_dir, path) 50 | data.append([img_name, int(class_id), '0', im_id]) 51 | im_id += 1 52 | return data 53 | 54 | # 构建测试Dataset 55 | @DATASET_REGISTRY.register() 56 | class FGVCInferDataset(): 57 | dataset_name = "FGVCInferDataset" 58 | 59 | def __init__(self, root=None, **kwargs): 60 | self.root = root 61 | self.test_dataset_dir = kwargs['test_dataset_dir'] 62 | self.query = self.process_dir(self.test_dataset_dir) 63 | self.gallery = [] 64 | 65 | def process_dir(self, img_dir): 66 | data = [] 67 | files = os.listdir(img_dir) 68 | im_id = 0 69 | for line in files: 70 | img_path = os.path.join(img_dir, line) 71 | data.append([img_path, 0, '0', im_id]) 72 | im_id += 1 73 | return data -------------------------------------------------------------------------------- /OneForAll/data/samplers/clsaware_reader.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import os 16 | import sys 17 | if sys.version_info >= (3, 0): 18 | pass 19 | else: 20 | pass 21 | import numpy as np 22 | from paddle.io import DistributedBatchSampler 23 | 24 | from ppdet.utils.logger import setup_logger 25 | from collections import Counter 26 | 27 | logger = setup_logger('reader') 28 | MAIN_PID = os.getpid() 29 | 30 | 31 | class VehicleMultiTaskClassAwareSampler(DistributedBatchSampler): 32 | def __init__(self, dataset, batch_size, shuffle=True, drop_last=True): 33 | super(VehicleMultiTaskClassAwareSampler, self).__init__(dataset, batch_size, shuffle=shuffle, drop_last=drop_last) 34 | self.batch_size = batch_size 35 | self.category_imgids = self._classaware_sampler(dataset.img_items) 36 | 37 | # counter = [0 for _ in range(len(self.category_imgids))] 38 | # for i in range(len(self.category_imgids)): 39 | # counter += len(self.category_imgids[i]) 40 | # self.class_sampler_prob = np.array(counter) / sum(counter) 41 | self.class_sampler_prob = [1.0/len(self.category_imgids) for _ in range(len(self.category_imgids))] 42 | 43 | def __iter__(self): 44 | 45 | while True: 46 | batch_index = [] 47 | random_categories = list(np.random.choice(list(range(len(self.category_imgids))), 48 | self.batch_size, replace=True, 49 | p=self.class_sampler_prob)) 50 | for cls, count in Counter(random_categories).items(): 51 | cur_ids = list(np.random.choice(self.category_imgids[cls], count, replace=False)) 52 | batch_index.extend(cur_ids) 53 | if self.shuffle: 54 | np.random.RandomState(self.epoch).shuffle(batch_index) 55 | self.epoch += 1 56 | 57 | if not self.drop_last or len(batch_index) == self.batch_size: 58 | yield batch_index 59 | 60 | def _classaware_sampler(self, roidbs): 61 | category_imgids = {} 62 | for i, roidb in enumerate(roidbs): 63 | label = roidb[1] # label 64 | if label not in category_imgids: 65 | category_imgids[label] = [] 66 | category_imgids[label].append(i) # 每个类别对应的图片id 67 | 68 | return category_imgids 69 | 70 | -------------------------------------------------------------------------------- /OneForAll/data/samplers/twosource_sampler.py: -------------------------------------------------------------------------------- 1 | # !/usr/bin/env python3 2 | # encoding: utf-8 3 | 4 | import copy 5 | import itertools 6 | from typing import Optional 7 | import logging 8 | 9 | import numpy as np 10 | from paddle.io import Sampler 11 | 12 | from utils import comm 13 | logger = logging.getLogger(__name__) 14 | 15 | class TrainingSampler(Sampler): 16 | """ 17 | In training, we only care about the "infinite stream" of training data. 18 | So this sampler produces an infinite stream of indices and 19 | all workers cooperate to correctly shuffle the indices and sample different indices. 20 | The samplers in each worker effectively produces `indices[worker_id::num_workers]` 21 | where `indices` is an infinite stream of indices consisting of 22 | `shuffle(range(size)) + shuffle(range(size)) + ...` (if shuffle is True) 23 | or `range(size) + range(size) + ...` (if shuffle is False) 24 | """ 25 | 26 | def __init__(self, dataset, batchsize, shuffle=True, seed=None, dp_group=None, moe_group=None): 27 | """ 28 | Args: 29 | size (int): the total number of data of the underlying dataset to sample from 30 | shuffle (bool): whether to shuffle the indices or not 31 | seed (int): the initial seed of the shuffle. Must be the same 32 | across all workers. If None, will use a random seed shared 33 | among workers (require synchronization among all workers). 34 | """ 35 | self._size = len(dataset) 36 | assert self._size > 0 37 | self._shuffle = shuffle 38 | if seed is None: 39 | seed = comm.shared_random_seed() 40 | self._seed = int(seed) 41 | 42 | # self._rank = comm.get_rank() 43 | # self._world_size = comm.get_world_size() 44 | if dp_group is None: 45 | self._rank = comm.get_rank() 46 | self._world_size = comm.get_world_size() 47 | else: 48 | self._rank = comm.get_rank() // moe_group.nranks 49 | self._world_size = dp_group.nranks 50 | logger.info("dataset {}: rank {} is mapped to _rank {} under the real local world size {}".format(dataset.dataset_name, comm.get_rank(), self._rank, self._world_size)) 51 | self.batchsize = batchsize 52 | 53 | def __iter__(self): 54 | start = self._rank 55 | yield from itertools.islice(self._infinite_indices(), start, None, self._world_size) 56 | 57 | def __len__(self,): 58 | return 0 #len(self.local_indices) 59 | 60 | def _infinite_indices(self): 61 | np.random.seed(self._seed) 62 | while True: 63 | 64 | if self._shuffle: 65 | yield from np.random.permutation(self._size) 66 | else: 67 | yield from np.arange(self._size) 68 | 69 | def _load_batch(self): 70 | batch = [] 71 | if self.two_source: 72 | random_categories = list(np.random.choice([0, 1, 2, 3, 4, 5, 6, 7, 9, 12], self._batch_size, \ 73 | replace=self.is_sample_replace, p=[0.0875, 0.15, 0.15, 0.0875, 0.0875, 0.0875, 0.0875, 0.0875, 0.0875, 0.0875])) 74 | #replace=self.is_sample_replace, p=[0.0825, 0.1450, 0.1450, 0.0825, 0.0825, 0.0925, 0.0925, 0.0925, 0.0925, 0.0925])) 75 | for idx, cls in enumerate(random_categories): 76 | #if idx % 2 == 0: 77 | if idx % 5 <= 1: 78 | if cls not in self.category_imgids: 79 | cls = 1 80 | cur_id = np.random.choice(self.category_imgids[cls], self.num_img_per_cls, replace=False)[0] 81 | sample = copy.deepcopy(self._roidbs[cur_id]) 82 | else: 83 | if cls not in self.category_imgids_2: 84 | cls = 1 85 | if cls == 9 or cls == 12: 86 | cls = list(np.random.choice([0, 1, 2, 3, 4, 5, 6, 7], 1, replace=False))[0] 87 | cur_id = np.random.choice(self.category_imgids_2[cls], self.num_img_per_cls, replace=False)[0] 88 | sample = copy.deepcopy(self._roidbs_2[cur_id]) 89 | 90 | if self._drop_empty and self._fields and 'gt_mask' in self._fields: 91 | if self._has_empty(self._segm(sample)): 92 | continue 93 | if self._drop_empty and self._fields and 'gt_bbox' in self._fields: 94 | while self._has_empty(sample['gt_bbox']): 95 | if idx % 2 == 0: 96 | cur_id = np.random.choice(self.category_imgids[cls], 1, replace=False)[0] 97 | sample = copy.deepcopy(self._roidbs[cur_id]) 98 | else: 99 | cur_id = np.random.choice(self.category_imgids_2[cls], 1, replace=False)[0] 100 | sample = copy.deepcopy(self._roidbs_2[cur_id]) 101 | 102 | if self._load_img: 103 | sample['image'] = self._load_image(sample['im_file']) 104 | batch.append(sample) -------------------------------------------------------------------------------- /OneForAll/data/transforms/__init__.py: -------------------------------------------------------------------------------- 1 | """__init__.py 2 | """ -------------------------------------------------------------------------------- /OneForAll/data/transforms/random_erasing.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | #This code is based on https://github.com/zhunzhong07/Random-Erasing 16 | """RandomErasing 17 | """ 18 | import math 19 | import random 20 | 21 | import numpy as np 22 | 23 | 24 | class RandomErasing(object): 25 | """RandomErasing 26 | """ 27 | def __init__(self, EPSILON=0.5, sl=0.02, sh=0.4, r1=0.3, mean=[0., 0., 0.]): 28 | self.EPSILON = EPSILON 29 | self.mean = mean 30 | self.sl = sl 31 | self.sh = sh 32 | self.r1 = r1 33 | 34 | def __call__(self, img): 35 | if random.uniform(0, 1) > self.EPSILON: 36 | return img 37 | 38 | for _ in range(100): 39 | area = img.shape[0] * img.shape[1] 40 | 41 | target_area = random.uniform(self.sl, self.sh) * area 42 | aspect_ratio = random.uniform(self.r1, 1 / self.r1) 43 | 44 | h = int(round(math.sqrt(target_area * aspect_ratio))) 45 | w = int(round(math.sqrt(target_area / aspect_ratio))) 46 | 47 | if w < img.shape[1] and h < img.shape[0]: 48 | x1 = random.randint(0, img.shape[0] - h) 49 | y1 = random.randint(0, img.shape[1] - w) 50 | if img.shape[0] == 3: 51 | img[x1:x1 + h, y1:y1 + w, 0] = self.mean[0] 52 | img[x1:x1 + h, y1:y1 + w, 1] = self.mean[1] 53 | img[x1:x1 + h, y1:y1 + w, 2] = self.mean[2] 54 | else: 55 | img[0, x1:x1 + h, y1:y1 + w] = self.mean[1] 56 | return img 57 | return img 58 | -------------------------------------------------------------------------------- /OneForAll/detectron2/checkpoint/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (c) Facebook, Inc. and its affiliates. 3 | # File: 4 | 5 | 6 | from . import catalog as _UNUSED # register the handler 7 | from .detection_checkpoint import DetectionCheckpointer 8 | from fvcore.common.checkpoint import Checkpointer, PeriodicCheckpointer 9 | 10 | __all__ = ["Checkpointer", "PeriodicCheckpointer", "DetectionCheckpointer"] 11 | -------------------------------------------------------------------------------- /OneForAll/detectron2/checkpoint/detection_checkpoint.py: -------------------------------------------------------------------------------- 1 | # !/usr/bin/env python3 2 | # Copyright (c) Facebook, Inc. and its affiliates. 3 | import logging 4 | import os 5 | import pickle 6 | import torch 7 | from fvcore.common.checkpoint import Checkpointer 8 | from torch.nn.parallel import DistributedDataParallel 9 | 10 | import detectron2.utils.comm as comm 11 | from detectron2.utils.file_io import PathManager 12 | 13 | from .c2_model_loading import align_and_update_state_dicts 14 | 15 | 16 | class DetectionCheckpointer(Checkpointer): 17 | """ 18 | Same as :class:`Checkpointer`, but is able to: 19 | 1. handle models in detectron & detectron2 model zoo, and apply conversions for legacy models. 20 | 2. correctly load checkpoints that are only available on the master worker 21 | """ 22 | 23 | def __init__(self, model, save_dir="", *, save_to_disk=None, **checkpointables): 24 | is_main_process = comm.is_main_process() 25 | super().__init__( 26 | model, 27 | save_dir, 28 | save_to_disk=is_main_process if save_to_disk is None else save_to_disk, 29 | **checkpointables, 30 | ) 31 | self.path_manager = PathManager 32 | 33 | def load(self, path, *args, **kwargs): 34 | need_sync = False 35 | 36 | if path and isinstance(self.model, DistributedDataParallel): 37 | logger = logging.getLogger(__name__) 38 | path = self.path_manager.get_local_path(path) 39 | has_file = os.path.isfile(path) 40 | all_has_file = comm.all_gather(has_file) 41 | if not all_has_file[0]: 42 | raise OSError(f"File {path} not found on main worker.") 43 | if not all(all_has_file): 44 | logger.warning( 45 | "Not all workers can read checkpoint {path}. " 46 | "Training may fail to fully resume." 47 | ) 48 | # TODO: broadcast the checkpoint file contents from main 49 | # worker, and load from it instead. 50 | need_sync = True 51 | if not has_file: 52 | path = None # don't load if not readable 53 | ret = super().load(path, *args, **kwargs) 54 | 55 | if need_sync: 56 | logger.info("Broadcasting model states from main worker ...") 57 | self.model._sync_params_and_buffers() 58 | return ret 59 | 60 | def _load_file(self, filename): 61 | if filename.endswith(".pkl"): 62 | with PathManager.open(filename, "rb") as f: 63 | data = pickle.load(f, encoding="latin1") 64 | if "model" in data and "__author__" in data: 65 | # file is in Detectron2 model zoo format 66 | self.logger.info("Reading a file from '{}'".format(data["__author__"])) 67 | return data 68 | else: 69 | # assume file is from Caffe2 / Detectron1 model zoo 70 | if "blobs" in data: 71 | # Detection models have "blobs", but ImageNet models don't 72 | data = data["blobs"] 73 | data = {k: v for k, v in data.items() if not k.endswith("_momentum")} 74 | return {"model": data, "__author__": "Caffe2", "matching_heuristics": True} 75 | elif filename.endswith(".pyth"): 76 | # assume file is from pycls; no one else seems to use the ".pyth" extension 77 | with PathManager.open(filename, "rb") as f: 78 | data = torch.load(f) 79 | assert ( 80 | "model_state" in data 81 | ), "Cannot load .pyth file {filename}; pycls checkpoints must contain 'model_state'." 82 | model_state = { 83 | k: v 84 | for k, v in data["model_state"].items() 85 | if not k.endswith("num_batches_tracked") 86 | } 87 | return {"model": model_state, "__author__": "pycls", "matching_heuristics": True} 88 | 89 | loaded = super()._load_file(filename) # load native pth checkpoint 90 | if "model" not in loaded: 91 | loaded = {"model": loaded} 92 | return loaded 93 | 94 | def _load_model(self, checkpoint): 95 | if checkpoint.get("matching_heuristics", False): 96 | self._convert_ndarray_to_tensor(checkpoint["model"]) 97 | # convert weights by name-matching heuristics 98 | checkpoint["model"] = align_and_update_state_dicts( 99 | self.model.state_dict(), 100 | checkpoint["model"], 101 | c2_conversion=checkpoint.get("__author__", None) == "Caffe2", 102 | ) 103 | # for non-caffe2 models, use standard ways to load it 104 | incompatible = super()._load_model(checkpoint) 105 | 106 | model_buffers = dict(self.model.named_buffers(recurse=False)) 107 | for k in ["pixel_mean", "pixel_std"]: 108 | # Ignore missing key message about pixel_mean/std. 109 | # Though they may be missing in old checkpoints, they will be correctly 110 | # initialized from config anyway. 111 | if k in model_buffers: 112 | try: 113 | incompatible.missing_keys.remove(k) 114 | except ValueError: 115 | pass 116 | for k in incompatible.unexpected_keys[:]: 117 | # Ignore unexpected keys about cell anchors. They exist in old checkpoints 118 | # but now they are non-persistent buffers and will not be in new checkpoints. 119 | if "anchor_generator.cell_anchors" in k: 120 | incompatible.unexpected_keys.remove(k) 121 | return incompatible 122 | -------------------------------------------------------------------------------- /OneForAll/detectron2/config/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. 2 | from .compat import downgrade_config, upgrade_config 3 | from .config import CfgNode, get_cfg, global_cfg, set_global_cfg, configurable 4 | from .instantiate import instantiate 5 | from .lazy import LazyCall, LazyConfig 6 | 7 | __all__ = [ 8 | "CfgNode", 9 | "get_cfg", 10 | "global_cfg", 11 | "set_global_cfg", 12 | "downgrade_config", 13 | "upgrade_config", 14 | "configurable", 15 | "instantiate", 16 | "LazyCall", 17 | "LazyConfig", 18 | ] 19 | 20 | 21 | from detectron2.utils.env import fixup_module_metadata 22 | 23 | fixup_module_metadata(__name__, globals(), __all__) 24 | del fixup_module_metadata 25 | -------------------------------------------------------------------------------- /OneForAll/detectron2/config/instantiate.py: -------------------------------------------------------------------------------- 1 | # !/usr/bin/env python3 2 | # Copyright (c) Facebook, Inc. and its affiliates. 3 | import dataclasses 4 | import logging 5 | from collections import abc 6 | from typing import Any 7 | 8 | from detectron2.utils.registry import _convert_target_to_string, locate 9 | 10 | __all__ = ["dump_dataclass", "instantiate"] 11 | 12 | 13 | def dump_dataclass(obj: Any): 14 | """ 15 | Dump a dataclass recursively into a dict that can be later instantiated. 16 | 17 | Args: 18 | obj: a dataclass object 19 | 20 | Returns: 21 | dict 22 | """ 23 | assert dataclasses.is_dataclass(obj) and not isinstance( 24 | obj, type 25 | ), "dump_dataclass() requires an instance of a dataclass." 26 | ret = {"_target_": _convert_target_to_string(type(obj))} 27 | for f in dataclasses.fields(obj): 28 | v = getattr(obj, f.name) 29 | if dataclasses.is_dataclass(v): 30 | v = dump_dataclass(v) 31 | if isinstance(v, (list, tuple)): 32 | v = [dump_dataclass(x) if dataclasses.is_dataclass(x) else x for x in v] 33 | ret[f.name] = v 34 | return ret 35 | 36 | 37 | def instantiate(cfg): 38 | """ 39 | Recursively instantiate objects defined in dictionaries by 40 | "_target_" and arguments. 41 | 42 | Args: 43 | cfg: a dict-like object with "_target_" that defines the caller, and 44 | other keys that define the arguments 45 | 46 | Returns: 47 | object instantiated by cfg 48 | """ 49 | from omegaconf import ListConfig 50 | 51 | if isinstance(cfg, ListConfig): 52 | lst = [instantiate(x) for x in cfg] 53 | return ListConfig(lst, flags={"allow_objects": True}) 54 | if isinstance(cfg, list): 55 | # Specialize for list, because many classes take 56 | # list[objects] as arguments, such as ResNet, DatasetMapper 57 | return [instantiate(x) for x in cfg] 58 | 59 | if isinstance(cfg, abc.Mapping) and "_target_" in cfg: 60 | # conceptually equivalent to hydra.utils.instantiate(cfg) with _convert_=all, 61 | # but faster: https://github.com/facebookresearch/hydra/issues/1200 62 | cfg = {k: instantiate(v) for k, v in cfg.items()} 63 | cls = cfg.pop("_target_") 64 | cls = instantiate(cls) 65 | 66 | if isinstance(cls, str): 67 | cls_name = cls 68 | cls = locate(cls_name) 69 | assert cls is not None, cls_name 70 | else: 71 | try: 72 | cls_name = cls.__module__ + "." + cls.__qualname__ 73 | except Exception: 74 | # target could be anything, so the above could fail 75 | cls_name = str(cls) 76 | assert callable(cls), "_target_ {cls} does not define a callable object" 77 | try: 78 | return cls(**cfg) 79 | except TypeError: 80 | logger = logging.getLogger(__name__) 81 | logger.error(f"Error when instantiating {cls_name}!") 82 | raise 83 | return cfg # return as-is if don't know what to do 84 | -------------------------------------------------------------------------------- /OneForAll/detectron2/data/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. 2 | from . import transforms # isort:skip 3 | 4 | from .build import ( 5 | build_batch_data_loader, 6 | build_detection_test_loader, 7 | build_detection_train_loader, 8 | get_detection_dataset_dicts, 9 | load_proposals_into_dataset, 10 | print_instances_class_histogram, 11 | ) 12 | from .catalog import DatasetCatalog, MetadataCatalog, Metadata 13 | from .common import DatasetFromList, MapDataset, ToIterableDataset 14 | from .dataset_mapper import DatasetMapper 15 | 16 | # ensure the builtin datasets are registered 17 | from . import datasets, samplers # isort:skip 18 | 19 | __all__ = [k for k in globals().keys() if not k.startswith("_")] 20 | -------------------------------------------------------------------------------- /OneForAll/detectron2/data/datasets/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ### Common Datasets 4 | 5 | The dataset implemented here do not need to load the data into the final format. 6 | It should provide the minimal data structure needed to use the dataset, so it can be very efficient. 7 | 8 | For example, for an image dataset, just provide the file names and labels, but don't read the images. 9 | Let the downstream decide how to read. 10 | -------------------------------------------------------------------------------- /OneForAll/detectron2/data/datasets/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. 2 | # from .coco import load_coco_json, load_sem_seg, register_coco_instances, convert_to_coco_json 3 | # from .coco_panoptic import register_coco_panoptic, register_coco_panoptic_separated 4 | # from .lvis import load_lvis_json, register_lvis_instances, get_lvis_instances_meta 5 | # from .pascal_voc import load_voc_instances, register_pascal_voc 6 | # from . import builtin as _builtin # ensure the builtin datasets are registered 7 | 8 | 9 | __all__ = [k for k in globals().keys() if not k.startswith("_")] 10 | -------------------------------------------------------------------------------- /OneForAll/detectron2/data/datasets/pascal_voc.py: -------------------------------------------------------------------------------- 1 | # !/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # Copyright (c) Facebook, Inc. and its affiliates. 4 | 5 | import numpy as np 6 | import os 7 | import xml.etree.ElementTree as ET 8 | from typing import List, Tuple, Union 9 | 10 | from detectron2.data import DatasetCatalog, MetadataCatalog 11 | from detectron2.structures import BoxMode 12 | from detectron2.utils.file_io import PathManager 13 | 14 | __all__ = ["load_voc_instances", "register_pascal_voc"] 15 | 16 | 17 | # fmt: off 18 | CLASS_NAMES = ( 19 | "aeroplane", "bicycle", "bird", "boat", "bottle", "bus", "car", "cat", 20 | "chair", "cow", "diningtable", "dog", "horse", "motorbike", "person", 21 | "pottedplant", "sheep", "sofa", "train", "tvmonitor" 22 | ) 23 | # fmt: on 24 | 25 | 26 | def load_voc_instances(dirname: str, split: str, class_names: Union[List[str], Tuple[str, ...]]): 27 | """ 28 | Load Pascal VOC detection annotations to Detectron2 format. 29 | 30 | Args: 31 | dirname: Contain "Annotations", "ImageSets", "JPEGImages" 32 | split (str): one of "train", "test", "val", "trainval" 33 | class_names: list or tuple of class names 34 | """ 35 | with PathManager.open(os.path.join(dirname, "ImageSets", "Main", split + ".txt")) as f: 36 | fileids = np.loadtxt(f, dtype=np.str) 37 | 38 | # Needs to read many small annotation files. Makes sense at local 39 | annotation_dirname = PathManager.get_local_path(os.path.join(dirname, "Annotations/")) 40 | dicts = [] 41 | for fileid in fileids: 42 | anno_file = os.path.join(annotation_dirname, fileid + ".xml") 43 | jpeg_file = os.path.join(dirname, "JPEGImages", fileid + ".jpg") 44 | 45 | with PathManager.open(anno_file) as f: 46 | tree = ET.parse(f) 47 | 48 | r = { 49 | "file_name": jpeg_file, 50 | "image_id": fileid, 51 | "height": int(tree.findall("./size/height")[0].text), 52 | "width": int(tree.findall("./size/width")[0].text), 53 | } 54 | instances = [] 55 | 56 | for obj in tree.findall("object"): 57 | cls = obj.find("name").text 58 | # We include "difficult" samples in training. 59 | # Based on limited experiments, they don't hurt accuracy. 60 | # difficult = int(obj.find("difficult").text) 61 | # if difficult == 1: 62 | # continue 63 | bbox = obj.find("bndbox") 64 | bbox = [float(bbox.find(x).text) for x in ["xmin", "ymin", "xmax", "ymax"]] 65 | # Original annotations are integers in the range [1, W or H] 66 | # Assuming they mean 1-based pixel indices (inclusive), 67 | # a box with annotation (xmin=1, xmax=W) covers the whole image. 68 | # In coordinate space this is represented by (xmin=0, xmax=W) 69 | bbox[0] -= 1.0 70 | bbox[1] -= 1.0 71 | instances.append( 72 | {"category_id": class_names.index(cls), "bbox": bbox, "bbox_mode": BoxMode.XYXY_ABS} 73 | ) 74 | r["annotations"] = instances 75 | dicts.append(r) 76 | return dicts 77 | 78 | 79 | def register_pascal_voc(name, dirname, split, year, class_names=CLASS_NAMES): 80 | DatasetCatalog.register(name, lambda: load_voc_instances(dirname, split, class_names)) 81 | MetadataCatalog.get(name).set( 82 | thing_classes=list(class_names), dirname=dirname, year=year, split=split 83 | ) 84 | -------------------------------------------------------------------------------- /OneForAll/detectron2/data/datasets/register_coco.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. 2 | from .coco import register_coco_instances # noqa 3 | from .coco_panoptic import register_coco_panoptic_separated # noqa 4 | -------------------------------------------------------------------------------- /OneForAll/detectron2/data/samplers/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. 2 | from .distributed_sampler import ( 3 | InferenceSampler, 4 | RandomSubsetTrainingSampler, 5 | RepeatFactorTrainingSampler, 6 | TrainingSampler, 7 | ) 8 | 9 | from .grouped_batch_sampler import GroupedBatchSampler 10 | 11 | __all__ = [ 12 | "GroupedBatchSampler", 13 | "TrainingSampler", 14 | "RandomSubsetTrainingSampler", 15 | "InferenceSampler", 16 | "RepeatFactorTrainingSampler", 17 | ] 18 | -------------------------------------------------------------------------------- /OneForAll/detectron2/data/samplers/grouped_batch_sampler.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. 2 | import numpy as np 3 | from torch.utils.data.sampler import BatchSampler, Sampler 4 | 5 | 6 | class GroupedBatchSampler(BatchSampler): 7 | """ 8 | Wraps another sampler to yield a mini-batch of indices. 9 | It enforces that the batch only contain elements from the same group. 10 | It also tries to provide mini-batches which follows an ordering which is 11 | as close as possible to the ordering from the original sampler. 12 | """ 13 | 14 | def __init__(self, sampler, group_ids, batch_size): 15 | """ 16 | Args: 17 | sampler (Sampler): Base sampler. 18 | group_ids (list[int]): If the sampler produces indices in range [0, N), 19 | `group_ids` must be a list of `N` ints which contains the group id of each sample. 20 | The group ids must be a set of integers in the range [0, num_groups). 21 | batch_size (int): Size of mini-batch. 22 | """ 23 | if not isinstance(sampler, Sampler): 24 | raise ValueError( 25 | "sampler should be an instance of " 26 | "torch.utils.data.Sampler, but got sampler={}".format(sampler) 27 | ) 28 | self.sampler = sampler 29 | self.group_ids = np.asarray(group_ids) 30 | assert self.group_ids.ndim == 1 31 | self.batch_size = batch_size 32 | groups = np.unique(self.group_ids).tolist() 33 | 34 | # buffer the indices of each group until batch size is reached 35 | self.buffer_per_group = {k: [] for k in groups} 36 | 37 | def __iter__(self): 38 | for idx in self.sampler: 39 | group_id = self.group_ids[idx] 40 | group_buffer = self.buffer_per_group[group_id] 41 | group_buffer.append(idx) 42 | if len(group_buffer) == self.batch_size: 43 | yield group_buffer[:] # yield a copy of the list 44 | del group_buffer[:] 45 | 46 | def __len__(self): 47 | raise NotImplementedError("len() of GroupedBatchSampler is not well-defined.") 48 | -------------------------------------------------------------------------------- /OneForAll/detectron2/data/transforms/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. 2 | from fvcore.transforms.transform import Transform, TransformList # order them first 3 | from fvcore.transforms.transform import * 4 | from .transform import * 5 | from .augmentation import * 6 | from .augmentation_impl import * 7 | 8 | __all__ = [k for k in globals().keys() if not k.startswith("_")] 9 | 10 | 11 | from detectron2.utils.env import fixup_module_metadata 12 | 13 | fixup_module_metadata(__name__, globals(), __all__) 14 | del fixup_module_metadata 15 | -------------------------------------------------------------------------------- /OneForAll/detectron2/engine/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. 2 | 3 | # from .launch import * 4 | from .train_loop_moe import SimpleTrainer as SimpleTrainerMoE 5 | from .train_loop import * 6 | 7 | __all__ = [k for k in globals().keys() if not k.startswith("_")] 8 | 9 | 10 | # prefer to let hooks and defaults live in separate namespaces (therefore not in __all__) 11 | # but still make them available here 12 | from .hooks import * 13 | from .defaults import * 14 | -------------------------------------------------------------------------------- /OneForAll/detectron2/engine/launch.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. 2 | import logging 3 | from datetime import timedelta 4 | import torch 5 | import torch.distributed as dist 6 | import torch.multiprocessing as mp 7 | 8 | from detectron2.utils import comm 9 | 10 | __all__ = ["DEFAULT_TIMEOUT", "launch"] 11 | 12 | DEFAULT_TIMEOUT = timedelta(minutes=30) 13 | 14 | 15 | def _find_free_port(): 16 | import socket 17 | 18 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 19 | # Binding to port 0 will cause the OS to find an available port for us 20 | sock.bind(("", 0)) 21 | port = sock.getsockname()[1] 22 | sock.close() 23 | # NOTE: there is still a chance the port could be taken by other processes. 24 | return port 25 | 26 | 27 | def launch( 28 | main_func, 29 | num_gpus_per_machine, 30 | num_machines=1, 31 | machine_rank=0, 32 | dist_url=None, 33 | args=(), 34 | timeout=DEFAULT_TIMEOUT, 35 | ): 36 | """ 37 | Launch multi-gpu or distributed training. 38 | This function must be called on all machines involved in the training. 39 | It will spawn child processes (defined by ``num_gpus_per_machine``) on each machine. 40 | 41 | Args: 42 | main_func: a function that will be called by `main_func(*args)` 43 | num_gpus_per_machine (int): number of GPUs per machine 44 | num_machines (int): the total number of machines 45 | machine_rank (int): the rank of this machine 46 | dist_url (str): url to connect to for distributed jobs, including protocol 47 | e.g. "tcp://127.0.0.1:8686". 48 | Can be set to "auto" to automatically select a free port on localhost 49 | timeout (timedelta): timeout of the distributed workers 50 | args (tuple): arguments passed to main_func 51 | """ 52 | world_size = num_machines * num_gpus_per_machine 53 | if world_size > 1: 54 | # https://github.com/pytorch/pytorch/pull/14391 55 | # TODO prctl in spawned processes 56 | 57 | if dist_url == "auto": 58 | assert num_machines == 1, "dist_url=auto not supported in multi-machine jobs." 59 | port = _find_free_port() 60 | dist_url = "tcp://127.0.0.1:{port}" 61 | if num_machines > 1 and dist_url.startswith("file://"): 62 | logger = logging.getLogger(__name__) 63 | logger.warning( 64 | "file:// is not a reliable init_method in multi-machine jobs. Prefer tcp://" 65 | ) 66 | 67 | mp.spawn( 68 | _distributed_worker, 69 | nprocs=num_gpus_per_machine, 70 | args=( 71 | main_func, 72 | world_size, 73 | num_gpus_per_machine, 74 | machine_rank, 75 | dist_url, 76 | args, 77 | timeout, 78 | ), 79 | daemon=False, 80 | ) 81 | else: 82 | main_func(*args) 83 | 84 | 85 | def _distributed_worker( 86 | local_rank, 87 | main_func, 88 | world_size, 89 | num_gpus_per_machine, 90 | machine_rank, 91 | dist_url, 92 | args, 93 | timeout=DEFAULT_TIMEOUT, 94 | ): 95 | assert torch.cuda.is_available(), "cuda is not available. Please check your installation." 96 | global_rank = machine_rank * num_gpus_per_machine + local_rank 97 | try: 98 | dist.init_process_group( 99 | backend="NCCL", 100 | init_method=dist_url, 101 | world_size=world_size, 102 | rank=global_rank, 103 | timeout=timeout, 104 | ) 105 | except Exception as e: 106 | logger = logging.getLogger(__name__) 107 | logger.error("Process group URL: {}".format(dist_url)) 108 | raise e 109 | 110 | # Setup the local process group (which contains ranks within the same machine) 111 | assert comm._LOCAL_PROCESS_GROUP is None 112 | num_machines = world_size // num_gpus_per_machine 113 | for i in range(num_machines): 114 | ranks_on_i = list(range(i * num_gpus_per_machine, (i + 1) * num_gpus_per_machine)) 115 | pg = dist.new_group(ranks_on_i) 116 | if i == machine_rank: 117 | comm._LOCAL_PROCESS_GROUP = pg 118 | 119 | assert num_gpus_per_machine <= torch.cuda.device_count() 120 | torch.cuda.set_device(local_rank) 121 | 122 | # synchronize is needed here to prevent a possible timeout after calling init_process_group 123 | # See: https://github.com/facebookresearch/maskrcnn-benchmark/issues/172 124 | comm.synchronize() 125 | 126 | main_func(*args) 127 | -------------------------------------------------------------------------------- /OneForAll/detectron2/evaluation/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. 2 | # from .cityscapes_evaluation import CityscapesInstanceEvaluator, CityscapesSemSegEvaluator 3 | # from .coco_evaluation import COCOEvaluator 4 | # from .rotated_coco_evaluation import RotatedCOCOEvaluator 5 | from .evaluator import DatasetEvaluator, DatasetEvaluators, inference_context, inference_on_dataset 6 | # from .lvis_evaluation import LVISEvaluator 7 | # from .panoptic_evaluation import COCOPanopticEvaluator 8 | # from .pascal_voc_evaluation import PascalVOCDetectionEvaluator 9 | # from .sem_seg_evaluation import SemSegEvaluator 10 | from .testing import print_csv_format, verify_results 11 | 12 | __all__ = [k for k in globals().keys() if not k.startswith("_")] 13 | -------------------------------------------------------------------------------- /OneForAll/detectron2/evaluation/fast_eval_api.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. 2 | import copy 3 | import logging 4 | import numpy as np 5 | import time 6 | from pycocotools.cocoeval import COCOeval 7 | 8 | from detectron2 import _C 9 | 10 | logger = logging.getLogger(__name__) 11 | 12 | 13 | class COCOeval_opt(COCOeval): 14 | """ 15 | This is a slightly modified version of the original COCO API, where the functions evaluateImg() 16 | and accumulate() are implemented in C++ to speedup evaluation 17 | """ 18 | 19 | def evaluate(self): 20 | """ 21 | Run per image evaluation on given images and store results in self.evalImgs_cpp, a 22 | datastructure that isn't readable from Python but is used by a c++ implementation of 23 | accumulate(). Unlike the original COCO PythonAPI, we don't populate the datastructure 24 | self.evalImgs because this datastructure is a computational bottleneck. 25 | :return: None 26 | """ 27 | tic = time.time() 28 | 29 | p = self.params 30 | # add backward compatibility if useSegm is specified in params 31 | if p.useSegm is not None: 32 | p.iouType = "segm" if p.useSegm == 1 else "bbox" 33 | logger.info("Evaluate annotation type *{}*".format(p.iouType)) 34 | p.imgIds = list(np.unique(p.imgIds)) 35 | if p.useCats: 36 | p.catIds = list(np.unique(p.catIds)) 37 | p.maxDets = sorted(p.maxDets) 38 | self.params = p 39 | 40 | self._prepare() # bottleneck 41 | 42 | # loop through images, area range, max detection number 43 | catIds = p.catIds if p.useCats else [-1] 44 | 45 | if p.iouType == "segm" or p.iouType == "bbox": 46 | computeIoU = self.computeIoU 47 | elif p.iouType == "keypoints": 48 | computeIoU = self.computeOks 49 | self.ious = { 50 | (imgId, catId): computeIoU(imgId, catId) for imgId in p.imgIds for catId in catIds 51 | } # bottleneck 52 | 53 | maxDet = p.maxDets[-1] 54 | 55 | # <<<< Beginning of code differences with original COCO API 56 | def convert_instances_to_cpp(instances, is_det=False): 57 | # Convert annotations for a list of instances in an image to a format that's fast 58 | # to access in C++ 59 | instances_cpp = [] 60 | for instance in instances: 61 | instance_cpp = _C.InstanceAnnotation( 62 | int(instance["id"]), 63 | instance["score"] if is_det else instance.get("score", 0.0), 64 | instance["area"], 65 | bool(instance.get("iscrowd", 0)), 66 | bool(instance.get("ignore", 0)), 67 | ) 68 | instances_cpp.append(instance_cpp) 69 | return instances_cpp 70 | 71 | # Convert GT annotations, detections, and IOUs to a format that's fast to access in C++ 72 | ground_truth_instances = [ 73 | [convert_instances_to_cpp(self._gts[imgId, catId]) for catId in p.catIds] 74 | for imgId in p.imgIds 75 | ] 76 | detected_instances = [ 77 | [convert_instances_to_cpp(self._dts[imgId, catId], is_det=True) for catId in p.catIds] 78 | for imgId in p.imgIds 79 | ] 80 | ious = [[self.ious[imgId, catId] for catId in catIds] for imgId in p.imgIds] 81 | 82 | if not p.useCats: 83 | # For each image, flatten per-category lists into a single list 84 | ground_truth_instances = [[[o for c in i for o in c]] for i in ground_truth_instances] 85 | detected_instances = [[[o for c in i for o in c]] for i in detected_instances] 86 | 87 | # Call C++ implementation of self.evaluateImgs() 88 | self._evalImgs_cpp = _C.COCOevalEvaluateImages( 89 | p.areaRng, maxDet, p.iouThrs, ious, ground_truth_instances, detected_instances 90 | ) 91 | self._evalImgs = None 92 | 93 | self._paramsEval = copy.deepcopy(self.params) 94 | toc = time.time() 95 | logger.info("COCOeval_opt.evaluate() finished in {:0.2f} seconds.".format(toc - tic)) 96 | # >>>> End of code differences with original COCO API 97 | 98 | def accumulate(self): 99 | """ 100 | Accumulate per image evaluation results and store the result in self.eval. Does not 101 | support changing parameter settings from those used by self.evaluate() 102 | """ 103 | logger.info("Accumulating evaluation results...") 104 | tic = time.time() 105 | assert hasattr( 106 | self, "_evalImgs_cpp" 107 | ), "evaluate() must be called before accmulate() is called." 108 | 109 | self.eval = _C.COCOevalAccumulate(self._paramsEval, self._evalImgs_cpp) 110 | 111 | # recall is num_iou_thresholds X num_categories X num_area_ranges X num_max_detections 112 | self.eval["recall"] = np.array(self.eval["recall"]).reshape( 113 | self.eval["counts"][:1] + self.eval["counts"][2:] 114 | ) 115 | 116 | # precision and scores are num_iou_thresholds X num_recall_thresholds X num_categories X 117 | # num_area_ranges X num_max_detections 118 | self.eval["precision"] = np.array(self.eval["precision"]).reshape(self.eval["counts"]) 119 | self.eval["scores"] = np.array(self.eval["scores"]).reshape(self.eval["counts"]) 120 | toc = time.time() 121 | logger.info("COCOeval_opt.accumulate() finished in {:0.2f} seconds.".format(toc - tic)) 122 | -------------------------------------------------------------------------------- /OneForAll/detectron2/evaluation/testing.py: -------------------------------------------------------------------------------- 1 | # !/usr/bin/env python3 2 | # Copyright (c) Facebook, Inc. and its affiliates. 3 | import logging 4 | import numpy as np 5 | import pprint 6 | import sys 7 | from collections.abc import Mapping 8 | 9 | 10 | def print_csv_format(results): 11 | """ 12 | Print main metrics in a format similar to Detectron, 13 | so that they are easy to copypaste into a spreadsheet. 14 | 15 | Args: 16 | results (OrderedDict[dict]): task_name -> {metric -> score} 17 | unordered dict can also be printed, but in arbitrary order 18 | """ 19 | assert isinstance(results, Mapping) or not len(results), results 20 | logger = logging.getLogger(__name__) 21 | for task, res in results.items(): 22 | if isinstance(res, Mapping): 23 | # Don't print "AP-category" metrics since they are usually not tracked. 24 | important_res = [(k, v) for k, v in res.items() if "-" not in k] 25 | logger.info("copypaste: Task: {}".format(task)) 26 | logger.info("copypaste: " + ",".join([k[0] for k in important_res])) 27 | logger.info("copypaste: " + ",".join(["{0:.4f}".format(k[1]) for k in important_res])) 28 | else: 29 | logger.info(f"copypaste: {task}={res}") 30 | 31 | 32 | def verify_results(cfg, results): 33 | """ 34 | Args: 35 | results (OrderedDict[dict]): task_name -> {metric -> score} 36 | 37 | Returns: 38 | bool: whether the verification succeeds or not 39 | """ 40 | expected_results = cfg.TEST.EXPECTED_RESULTS 41 | if not len(expected_results): 42 | return True 43 | 44 | ok = True 45 | for task, metric, expected, tolerance in expected_results: 46 | actual = results[task].get(metric, None) 47 | if actual is None: 48 | ok = False 49 | continue 50 | if not np.isfinite(actual): 51 | ok = False 52 | continue 53 | diff = abs(actual - expected) 54 | if diff > tolerance: 55 | ok = False 56 | 57 | logger = logging.getLogger(__name__) 58 | if not ok: 59 | logger.error("Result verification failed!") 60 | logger.error("Expected Results: " + str(expected_results)) 61 | logger.error("Actual Results: " + pprint.pformat(results)) 62 | 63 | sys.exit(1) 64 | else: 65 | logger.info("Results verification passed.") 66 | return ok 67 | 68 | 69 | def flatten_results_dict(results): 70 | """ 71 | Expand a hierarchical dict of scalars into a flat dict of scalars. 72 | If results[k1][k2][k3] = v, the returned dict will have the entry 73 | {"k1/k2/k3": v}. 74 | 75 | Args: 76 | results (dict): 77 | """ 78 | r = {} 79 | for k, v in results.items(): 80 | if isinstance(v, Mapping): 81 | v = flatten_results_dict(v) 82 | for kk, vv in v.items(): 83 | r[k + "/" + kk] = vv 84 | else: 85 | r[k] = v 86 | return r 87 | -------------------------------------------------------------------------------- /OneForAll/detectron2/solver/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. 2 | from .build import build_lr_scheduler, build_optimizer, get_default_optimizer_params 3 | from .lr_scheduler import WarmupCosineLR, WarmupMultiStepLR, LRMultiplier, WarmupParamScheduler 4 | 5 | __all__ = [k for k in globals().keys() if not k.startswith("_")] 6 | -------------------------------------------------------------------------------- /OneForAll/detectron2/structures/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. 2 | from .boxes import Boxes, BoxMode 3 | from .image_list import ImageList 4 | 5 | from .instances import Instances 6 | from .keypoints import Keypoints, heatmaps_to_keypoints 7 | from .masks import BitMasks, PolygonMasks, polygons_to_bitmask, ROIMasks 8 | from .rotated_boxes import RotatedBoxes 9 | 10 | __all__ = [k for k in globals().keys() if not k.startswith("_")] -------------------------------------------------------------------------------- /OneForAll/detectron2/utils/README.md: -------------------------------------------------------------------------------- 1 | # Utility functions 2 | 3 | This folder contain utility functions that are not used in the 4 | core library, but are useful for building models or training 5 | code using the config system. 6 | -------------------------------------------------------------------------------- /OneForAll/detectron2/utils/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. 2 | -------------------------------------------------------------------------------- /OneForAll/detectron2/utils/colormap.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. 2 | 3 | """ 4 | An awesome colormap for really neat visualizations. 5 | Copied from Detectron, and removed gray colors. 6 | """ 7 | 8 | import numpy as np 9 | 10 | __all__ = ["colormap", "random_color"] 11 | 12 | # fmt: off 13 | # RGB: 14 | _COLORS = np.array( 15 | [ 16 | 0.000, 0.447, 0.741, 17 | 0.850, 0.325, 0.098, 18 | 0.929, 0.694, 0.125, 19 | 0.494, 0.184, 0.556, 20 | 0.466, 0.674, 0.188, 21 | 0.301, 0.745, 0.933, 22 | 0.635, 0.078, 0.184, 23 | 0.300, 0.300, 0.300, 24 | 0.600, 0.600, 0.600, 25 | 1.000, 0.000, 0.000, 26 | 1.000, 0.500, 0.000, 27 | 0.749, 0.749, 0.000, 28 | 0.000, 1.000, 0.000, 29 | 0.000, 0.000, 1.000, 30 | 0.667, 0.000, 1.000, 31 | 0.333, 0.333, 0.000, 32 | 0.333, 0.667, 0.000, 33 | 0.333, 1.000, 0.000, 34 | 0.667, 0.333, 0.000, 35 | 0.667, 0.667, 0.000, 36 | 0.667, 1.000, 0.000, 37 | 1.000, 0.333, 0.000, 38 | 1.000, 0.667, 0.000, 39 | 1.000, 1.000, 0.000, 40 | 0.000, 0.333, 0.500, 41 | 0.000, 0.667, 0.500, 42 | 0.000, 1.000, 0.500, 43 | 0.333, 0.000, 0.500, 44 | 0.333, 0.333, 0.500, 45 | 0.333, 0.667, 0.500, 46 | 0.333, 1.000, 0.500, 47 | 0.667, 0.000, 0.500, 48 | 0.667, 0.333, 0.500, 49 | 0.667, 0.667, 0.500, 50 | 0.667, 1.000, 0.500, 51 | 1.000, 0.000, 0.500, 52 | 1.000, 0.333, 0.500, 53 | 1.000, 0.667, 0.500, 54 | 1.000, 1.000, 0.500, 55 | 0.000, 0.333, 1.000, 56 | 0.000, 0.667, 1.000, 57 | 0.000, 1.000, 1.000, 58 | 0.333, 0.000, 1.000, 59 | 0.333, 0.333, 1.000, 60 | 0.333, 0.667, 1.000, 61 | 0.333, 1.000, 1.000, 62 | 0.667, 0.000, 1.000, 63 | 0.667, 0.333, 1.000, 64 | 0.667, 0.667, 1.000, 65 | 0.667, 1.000, 1.000, 66 | 1.000, 0.000, 1.000, 67 | 1.000, 0.333, 1.000, 68 | 1.000, 0.667, 1.000, 69 | 0.333, 0.000, 0.000, 70 | 0.500, 0.000, 0.000, 71 | 0.667, 0.000, 0.000, 72 | 0.833, 0.000, 0.000, 73 | 1.000, 0.000, 0.000, 74 | 0.000, 0.167, 0.000, 75 | 0.000, 0.333, 0.000, 76 | 0.000, 0.500, 0.000, 77 | 0.000, 0.667, 0.000, 78 | 0.000, 0.833, 0.000, 79 | 0.000, 1.000, 0.000, 80 | 0.000, 0.000, 0.167, 81 | 0.000, 0.000, 0.333, 82 | 0.000, 0.000, 0.500, 83 | 0.000, 0.000, 0.667, 84 | 0.000, 0.000, 0.833, 85 | 0.000, 0.000, 1.000, 86 | 0.000, 0.000, 0.000, 87 | 0.143, 0.143, 0.143, 88 | 0.857, 0.857, 0.857, 89 | 1.000, 1.000, 1.000 90 | ] 91 | ).astype(np.float32).reshape(-1, 3) 92 | # fmt: on 93 | 94 | 95 | def colormap(rgb=False, maximum=255): 96 | """ 97 | Args: 98 | rgb (bool): whether to return RGB colors or BGR colors. 99 | maximum (int): either 255 or 1 100 | 101 | Returns: 102 | ndarray: a float32 array of Nx3 colors, in range [0, 255] or [0, 1] 103 | """ 104 | assert maximum in [255, 1], maximum 105 | c = _COLORS * maximum 106 | if not rgb: 107 | c = c[:, ::-1] 108 | return c 109 | 110 | 111 | def random_color(rgb=False, maximum=255): 112 | """ 113 | Args: 114 | rgb (bool): whether to return RGB colors or BGR colors. 115 | maximum (int): either 255 or 1 116 | 117 | Returns: 118 | ndarray: a vector of 3 numbers 119 | """ 120 | idx = np.random.randint(0, len(_COLORS)) 121 | ret = _COLORS[idx] * maximum 122 | if not rgb: 123 | ret = ret[::-1] 124 | return ret 125 | 126 | 127 | if __name__ == "__main__": 128 | import cv2 129 | 130 | size = 100 131 | H, W = 10, 10 132 | canvas = np.random.rand(H * size, W * size, 3).astype("float32") 133 | for h in range(H): 134 | for w in range(W): 135 | idx = h * W + w 136 | if idx >= len(_COLORS): 137 | break 138 | canvas[h * size : (h + 1) * size, w * size : (w + 1) * size] = _COLORS[idx] 139 | cv2.imshow("a", canvas) 140 | cv2.waitKey(0) 141 | -------------------------------------------------------------------------------- /OneForAll/detectron2/utils/file_io.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. 2 | from iopath.common.file_io import HTTPURLHandler, OneDrivePathHandler, PathHandler 3 | from iopath.common.file_io import PathManager as PathManagerBase 4 | 5 | __all__ = ["PathManager", "PathHandler"] 6 | 7 | 8 | PathManager = PathManagerBase() 9 | """ 10 | This is a detectron2 project-specific PathManager. 11 | We try to stay away from global PathManager in fvcore as it 12 | introduces potential conflicts among other libraries. 13 | """ 14 | 15 | 16 | class Detectron2Handler(PathHandler): 17 | """ 18 | Resolve anything that's hosted under detectron2's namespace. 19 | """ 20 | 21 | PREFIX = "detectron2://" 22 | S3_DETECTRON2_PREFIX = "https://dl.fbaipublicfiles.com/detectron2/" 23 | 24 | def _get_supported_prefixes(self): 25 | return [self.PREFIX] 26 | 27 | def _get_local_path(self, path, **kwargs): 28 | name = path[len(self.PREFIX) :] 29 | return PathManager.get_local_path(self.S3_DETECTRON2_PREFIX + name, **kwargs) 30 | 31 | def _open(self, path, mode="r", **kwargs): 32 | return PathManager.open(self._get_local_path(path), mode, **kwargs) 33 | 34 | 35 | PathManager.register_handler(HTTPURLHandler()) 36 | PathManager.register_handler(OneDrivePathHandler()) 37 | PathManager.register_handler(Detectron2Handler()) 38 | -------------------------------------------------------------------------------- /OneForAll/detectron2/utils/memory.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. 2 | 3 | import logging 4 | from contextlib import contextmanager 5 | from functools import wraps 6 | import torch 7 | 8 | __all__ = ["retry_if_cuda_oom"] 9 | 10 | 11 | @contextmanager 12 | def _ignore_torch_cuda_oom(): 13 | """ 14 | A context which ignores CUDA OOM exception from pytorch. 15 | """ 16 | try: 17 | yield 18 | except RuntimeError as e: 19 | # NOTE: the string may change? 20 | if "CUDA out of memory. " in str(e): 21 | pass 22 | else: 23 | raise 24 | 25 | 26 | def retry_if_cuda_oom(func): 27 | """ 28 | Makes a function retry itself after encountering 29 | pytorch's CUDA OOM error. 30 | It will first retry after calling `torch.cuda.empty_cache()`. 31 | 32 | If that still fails, it will then retry by trying to convert inputs to CPUs. 33 | In this case, it expects the function to dispatch to CPU implementation. 34 | The return values may become CPU tensors as well and it's user's 35 | responsibility to convert it back to CUDA tensor if needed. 36 | 37 | Args: 38 | func: a stateless callable that takes tensor-like objects as arguments 39 | 40 | Returns: 41 | a callable which retries `func` if OOM is encountered. 42 | 43 | Examples: 44 | :: 45 | output = retry_if_cuda_oom(some_torch_function)(input1, input2) 46 | # output may be on CPU even if inputs are on GPU 47 | 48 | Note: 49 | 1. When converting inputs to CPU, it will only look at each argument and check 50 | if it has `.device` and `.to` for conversion. Nested structures of tensors 51 | are not supported. 52 | 53 | 2. Since the function might be called more than once, it has to be 54 | stateless. 55 | """ 56 | 57 | def maybe_to_cpu(x): 58 | try: 59 | like_gpu_tensor = x.device.type == "cuda" and hasattr(x, "to") 60 | except AttributeError: 61 | like_gpu_tensor = False 62 | if like_gpu_tensor: 63 | return x.to(device="cpu") 64 | else: 65 | return x 66 | 67 | @wraps(func) 68 | def wrapped(*args, **kwargs): 69 | with _ignore_torch_cuda_oom(): 70 | return func(*args, **kwargs) 71 | 72 | # Clear cache and retry 73 | torch.cuda.empty_cache() 74 | with _ignore_torch_cuda_oom(): 75 | return func(*args, **kwargs) 76 | 77 | # Try on CPU. This slows down the code significantly, therefore print a notice. 78 | logger = logging.getLogger(__name__) 79 | logger.info("Attempting to copy inputs of {} to CPU due to CUDA OOM".format(str(func))) 80 | new_args = (maybe_to_cpu(x) for x in args) 81 | new_kwargs = {k: maybe_to_cpu(v) for k, v in kwargs.items()} 82 | return func(*new_args, **new_kwargs) 83 | 84 | return wrapped 85 | -------------------------------------------------------------------------------- /OneForAll/detectron2/utils/registry.py: -------------------------------------------------------------------------------- 1 | # !/usr/bin/env python3 2 | # Copyright (c) Facebook, Inc. and its affiliates. 3 | 4 | from typing import Any 5 | import pydoc 6 | from fvcore.common.registry import Registry # for backward compatibility. 7 | 8 | """ 9 | ``Registry`` and `locate` provide ways to map a string (typically found 10 | in config files) to callable objects. 11 | """ 12 | 13 | __all__ = ["Registry", "locate"] 14 | 15 | 16 | def _convert_target_to_string(t: Any) -> str: 17 | """ 18 | Inverse of ``locate()``. 19 | 20 | Args: 21 | t: any object with ``__module__`` and ``__qualname__`` 22 | """ 23 | module, qualname = t.__module__, t.__qualname__ 24 | 25 | # Compress the path to this object, e.g. ``module.submodule._impl.class`` 26 | # may become ``module.submodule.class``, if the later also resolves to the same 27 | # object. This simplifies the string, and also is less affected by moving the 28 | # class implementation. 29 | module_parts = module.split(".") 30 | for k in range(1, len(module_parts)): 31 | prefix = ".".join(module_parts[:k]) 32 | candidate = "{prefix}.{qualname}" 33 | try: 34 | if locate(candidate) is t: 35 | return candidate 36 | except ImportError: 37 | pass 38 | return "{module}.{qualname}" 39 | 40 | 41 | def locate(name: str) -> Any: 42 | """ 43 | Locate and return an object ``x`` using an input string ``{x.__module__}.{x.__qualname__}``, 44 | such as "module.submodule.class_name". 45 | 46 | Raise Exception if it cannot be found. 47 | """ 48 | obj = pydoc.locate(name) 49 | 50 | # Some cases (e.g. torch.optim.sgd.SGD) not handled correctly 51 | # by pydoc.locate. Try a private function from hydra. 52 | if obj is None: 53 | try: 54 | # from hydra.utils import get_method - will print many errors 55 | from hydra.utils import _locate 56 | except ImportError as e: 57 | raise ImportError(f"Cannot dynamically locate object {name}!") from e 58 | else: 59 | obj = _locate(name) # it raises if fails 60 | 61 | return obj 62 | -------------------------------------------------------------------------------- /OneForAll/detectron2/utils/serialize.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. 2 | import cloudpickle 3 | 4 | 5 | class PicklableWrapper(object): 6 | """ 7 | Wrap an object to make it more picklable, note that it uses 8 | heavy weight serialization libraries that are slower than pickle. 9 | It's best to use it only on closures (which are usually not picklable). 10 | 11 | This is a simplified version of 12 | https://github.com/joblib/joblib/blob/master/joblib/externals/loky/cloudpickle_wrapper.py 13 | """ 14 | 15 | def __init__(self, obj): 16 | while isinstance(obj, PicklableWrapper): 17 | # Wrapping an object twice is no-op 18 | obj = obj._obj 19 | self._obj = obj 20 | 21 | def __reduce__(self): 22 | s = cloudpickle.dumps(self._obj) 23 | return cloudpickle.loads, (s,) 24 | 25 | def __call__(self, *args, **kwargs): 26 | return self._obj(*args, **kwargs) 27 | 28 | def __getattr__(self, attr): 29 | # Ensure that the wrapped object can be used seamlessly as the previous object. 30 | if attr not in ["_obj"]: 31 | return getattr(self._obj, attr) 32 | return getattr(self, attr) 33 | -------------------------------------------------------------------------------- /OneForAll/detectron2/utils/testing.py: -------------------------------------------------------------------------------- 1 | # !/usr/bin/env python3 2 | # Copyright (c) Facebook, Inc. and its affiliates. 3 | import io 4 | import numpy as np 5 | import torch 6 | 7 | from detectron2 import model_zoo 8 | from detectron2.data import DatasetCatalog 9 | from detectron2.data.detection_utils import read_image 10 | from detectron2.modeling import build_model 11 | from detectron2.structures import Boxes, Instances, ROIMasks 12 | from detectron2.utils.file_io import PathManager 13 | 14 | 15 | """ 16 | Internal utilities for tests. Don't use except for writing tests. 17 | """ 18 | 19 | 20 | def get_model_no_weights(config_path): 21 | """ 22 | Like model_zoo.get, but do not load any weights (even pretrained) 23 | """ 24 | cfg = model_zoo.get_config(config_path) 25 | if not torch.cuda.is_available(): 26 | cfg.MODEL.DEVICE = "cpu" 27 | return build_model(cfg) 28 | 29 | 30 | def random_boxes(num_boxes, max_coord=100, device="cpu"): 31 | """ 32 | Create a random Nx4 boxes tensor, with coordinates < max_coord. 33 | """ 34 | boxes = torch.rand(num_boxes, 4, device=device) * (max_coord * 0.5) 35 | boxes.clamp_(min=1.0) # tiny boxes cause numerical instability in box regression 36 | # Note: the implementation of this function in torchvision is: 37 | # boxes[:, 2:] += torch.rand(N, 2) * 100 38 | # but it does not guarantee non-negative widths/heights constraints: 39 | # boxes[:, 2] >= boxes[:, 0] and boxes[:, 3] >= boxes[:, 1]: 40 | boxes[:, 2:] += boxes[:, :2] 41 | return boxes 42 | 43 | 44 | def get_sample_coco_image(tensor=True): 45 | """ 46 | Args: 47 | tensor (bool): if True, returns 3xHxW tensor. 48 | else, returns a HxWx3 numpy array. 49 | 50 | Returns: 51 | an image, in BGR color. 52 | """ 53 | try: 54 | file_name = DatasetCatalog.get("coco_2017_val_100")[0]["file_name"] 55 | if not PathManager.exists(file_name): 56 | raise FileNotFoundError() 57 | except IOError: 58 | # for public CI to run 59 | file_name = "http://images.cocodataset.org/train2017/000000000009.jpg" 60 | ret = read_image(file_name, format="BGR") 61 | if tensor: 62 | ret = torch.from_numpy(np.ascontiguousarray(ret.transpose(2, 0, 1))) 63 | return ret 64 | 65 | 66 | def convert_scripted_instances(instances): 67 | """ 68 | Convert a scripted Instances object to a regular :class:`Instances` object 69 | """ 70 | ret = Instances(instances.image_size) 71 | for name in instances._field_names: 72 | val = getattr(instances, "_" + name, None) 73 | if val is not None: 74 | ret.set(name, val) 75 | return ret 76 | 77 | 78 | def assert_instances_allclose(input, other, *, rtol=1e-5, msg="", size_as_tensor=False): 79 | """ 80 | Args: 81 | input, other (Instances): 82 | size_as_tensor: compare image_size of the Instances as tensors (instead of tuples). 83 | Useful for comparing outputs of tracing. 84 | """ 85 | if not isinstance(input, Instances): 86 | input = convert_scripted_instances(input) 87 | if not isinstance(other, Instances): 88 | other = convert_scripted_instances(other) 89 | 90 | if not msg: 91 | msg = "Two Instances are different! " 92 | else: 93 | msg = msg.rstrip() + " " 94 | 95 | size_error_msg = msg + "image_size is {input.image_size} vs. {other.image_size}!" 96 | if size_as_tensor: 97 | assert torch.equal( 98 | torch.tensor(input.image_size), torch.tensor(other.image_size) 99 | ), size_error_msg 100 | else: 101 | assert input.image_size == other.image_size, size_error_msg 102 | fields = sorted(input.get_fields().keys()) 103 | fields_other = sorted(other.get_fields().keys()) 104 | assert fields == fields_other, msg + "Fields are {fields} vs {fields_other}!" 105 | 106 | for f in fields: 107 | val1, val2 = input.get(f), other.get(f) 108 | if isinstance(val1, (Boxes, ROIMasks)): 109 | # boxes in the range of O(100) and can have a larger tolerance 110 | assert torch.allclose(val1.tensor, val2.tensor, atol=100 * rtol), ( 111 | msg + "Field {f} differs too much!" 112 | ) 113 | elif isinstance(val1, torch.Tensor): 114 | if val1.dtype.is_floating_point: 115 | mag = torch.abs(val1).max().cpu().item() 116 | assert torch.allclose(val1, val2, atol=mag * rtol), ( 117 | msg + "Field {f} differs too much!" 118 | ) 119 | else: 120 | assert torch.equal(val1, val2), msg + "Field {f} is different!" 121 | else: 122 | raise ValueError(f"Don't know how to compare type {type(val1)}") 123 | 124 | 125 | def reload_script_model(module): 126 | """ 127 | Save a jit module and load it back. 128 | Similar to the `getExportImportCopy` function in torch/testing/ 129 | """ 130 | buffer = io.BytesIO() 131 | torch.jit.save(module, buffer) 132 | buffer.seek(0) 133 | return torch.jit.load(buffer) 134 | -------------------------------------------------------------------------------- /OneForAll/engine/hooks.py: -------------------------------------------------------------------------------- 1 | """paddle authors 2 | """ 3 | import logging 4 | from collections import Counter 5 | 6 | from detectron2.engine.train_loop import HookBase 7 | 8 | 9 | class LRScheduler(HookBase): 10 | """ 11 | A hook which executes a builtin LR scheduler and summarizes the LR. 12 | It is executed after every iteration. 13 | """ 14 | 15 | def __init__(self, optimizer, scheduler): 16 | """ 17 | Args: 18 | optimizer (optim.Optimizer): 19 | scheduler (optim._LRScheduler) 20 | """ 21 | self._optimizer = optimizer 22 | self._scheduler = scheduler 23 | self._scale = 0 24 | 25 | def before_step(self): 26 | """before_step 27 | """ 28 | if self.trainer.grad_scaler is not None: 29 | self._scale = self.trainer.grad_scaler._scale 30 | 31 | def after_step(self): 32 | """after_step 33 | """ 34 | lr = self._optimizer.get_lr() 35 | self.trainer.storage.put_scalar("lr", lr, smoothing_hint=False) 36 | if self.trainer.grad_scaler is None or self._scale == self.trainer.grad_scaler._scale: 37 | self._scheduler.step() 38 | lr = self._optimizer.get_lr() 39 | 40 | next_iter = self.trainer.iter + 1 41 | 42 | def state_dict(self): 43 | """state_dict 44 | """ 45 | return self._scheduler.state_dict() 46 | 47 | def set_state_dict(self, state_dict): 48 | """set_state_dict 49 | """ 50 | self._scheduler.set_state_dict(state_dict) 51 | -------------------------------------------------------------------------------- /OneForAll/evaluation/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | __init__.py 3 | """ 4 | from evaluation.testing import print_csv_format, verify_results -------------------------------------------------------------------------------- /OneForAll/evaluation/clas_evaluator.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | """ 3 | @author: xingyu liao 4 | @contact: sherlockliao01@gmail.com 5 | """ 6 | 7 | import copy 8 | import itertools 9 | import logging 10 | from collections import OrderedDict 11 | import os 12 | 13 | import paddle 14 | 15 | from utils import comm 16 | from evaluation.evaluator import DatasetEvaluator 17 | 18 | logger = logging.getLogger(__name__) 19 | 20 | class ClasEvaluatorSingleTask(DatasetEvaluator): 21 | """ClasEvaluatorSingleTask 22 | """ 23 | def __init__(self, cfg, output_dir=None, num_valid_samples=None, **kwargs): 24 | self.cfg = cfg 25 | self._output_dir = output_dir 26 | 27 | self._predictions = [] 28 | self.topk = (1,) 29 | self._num_valid_samples = num_valid_samples 30 | 31 | def reset(self): 32 | """reset 33 | """ 34 | self._predictions = [] 35 | 36 | def process(self, inputs, outputs): 37 | """process 38 | """ 39 | assert len(inputs) == 1, 'support only single task evaluation' 40 | assert len(outputs) == 1, 'support only single task evaluation' 41 | inputs = list(inputs.values())[0] 42 | outputs = list(outputs.values())[0] 43 | 44 | pred_logits = outputs 45 | labels = inputs["targets"] 46 | 47 | with paddle.no_grad(): 48 | maxk = max(self.topk) 49 | batch_size = labels.shape[0] 50 | _, pred = pred_logits.topk(maxk, 1, True, True) 51 | pred = pred.t() 52 | correct = pred.equal(labels.reshape((1, -1)).expand_as(pred)) 53 | 54 | k = 1 #top1 55 | correct_k = paddle.cast(correct[: k].reshape((-1, )), 'float32') 56 | 57 | # self._predictions.append({"num_correct": num_correct_acc1, "num_samples": labels.size(0)}) 58 | self._predictions.append({"correct_k": correct_k}) 59 | 60 | def evaluate(self): 61 | """evaluate 62 | """ 63 | if comm.get_world_size() > 1: 64 | comm.synchronize() 65 | predictions = comm.gather(self._predictions, dst=0) 66 | predictions = list(itertools.chain(*predictions)) 67 | 68 | if not comm.is_main_process(): return {} 69 | 70 | else: 71 | predictions = self._predictions 72 | 73 | correct_k_list = [] 74 | for prediction in predictions: 75 | correct_k_list.append(prediction["correct_k"]) 76 | all_correct_k = paddle.concat(correct_k_list, axis=0) 77 | all_correct_k = all_correct_k[:self._num_valid_samples] 78 | 79 | 80 | acc1 = all_correct_k.sum() / all_correct_k.shape[0] * 100 81 | 82 | self._results = OrderedDict() 83 | self._results["Acc@1"] = acc1.item() 84 | self._results["metric"] = acc1.item() 85 | 86 | return copy.deepcopy(self._results) 87 | -------------------------------------------------------------------------------- /OneForAll/evaluation/common_cls_evaluator.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | import copy 4 | import itertools 5 | import json 6 | import logging 7 | from collections import OrderedDict 8 | import os 9 | 10 | import paddle 11 | 12 | from utils import comm 13 | from evaluation.evaluator import DatasetEvaluator 14 | 15 | logger = logging.getLogger(__name__) 16 | 17 | # eval mode for training 18 | class CommonClasEvaluatorSingleTask(DatasetEvaluator): 19 | """CommonClasEvaluatorSingleTask 20 | """ 21 | def __init__(self, cfg, output_dir=None, num_valid_samples=None, **kwargs): 22 | self.cfg = cfg 23 | self._output_dir = output_dir 24 | self.task_type = kwargs.get('task_type', 'brand') 25 | 26 | self._predictions = [] 27 | self.topk = (1,) 28 | self._num_valid_samples = num_valid_samples 29 | 30 | self.num_classes = kwargs.get('num_classes', 3) 31 | 32 | def reset(self): 33 | """reset 34 | """ 35 | self._predictions = [] 36 | 37 | def process(self, inputs, outputs): 38 | """process 39 | """ 40 | assert len(inputs) == 1, 'support only single task evaluation' 41 | assert len(outputs) == 1, 'support only single task evaluation' 42 | inputs = list(inputs.values())[0] 43 | outputs = list(outputs.values())[0] 44 | 45 | pred_logits = outputs 46 | labels = inputs["targets"] 47 | with paddle.no_grad(): 48 | maxk = max(self.topk) 49 | batch_size = labels.shape[0] 50 | for i in range(batch_size): 51 | label = labels[i] 52 | result = -paddle.ones((2,)) 53 | _, pred = pred_logits[i].topk(maxk, -1, True, True) 54 | result[0] = int(label) 55 | result[1] = int(pred) 56 | self._predictions.append(result) 57 | 58 | def evaluate(self): 59 | """evaluate 60 | """ 61 | if comm.get_world_size() > 1: 62 | comm.synchronize() 63 | predictions = comm.gather(self._predictions, dst=0) 64 | predictions = list(itertools.chain(*predictions)) 65 | if not comm.is_main_process(): return {} 66 | else: 67 | predictions = self._predictions 68 | 69 | conf_mat = paddle.zeros((self.num_classes, self.num_classes)) 70 | correct = 0 71 | total_num = 0 72 | for prediction in predictions: 73 | label = int(prediction[0]) 74 | if label != -1: 75 | pred = int(prediction[1]) 76 | if label == pred: 77 | correct += 1 78 | total_num += 1 79 | conf_mat[label, pred] += 1 80 | 81 | self._results = OrderedDict() 82 | self._results["Acc@1"] = correct / total_num 83 | 84 | return copy.deepcopy(self._results) 85 | 86 | 87 | # infer mode only for test dataset 88 | class CommonClasEvaluatorSingleTaskInfer(DatasetEvaluator): 89 | """CommonClasEvaluatorSingleTaskInfer 90 | """ 91 | def __init__(self, cfg, output_dir=None, num_valid_samples=None, **kwargs): 92 | self.cfg = cfg 93 | self._output_dir = output_dir 94 | self.task_type = kwargs.get('task_type', 'brand') 95 | 96 | self._predictions = [] 97 | self.topk = (1,) 98 | self._num_valid_samples = num_valid_samples 99 | 100 | self.num_classes = kwargs.get('num_classes', 3) 101 | 102 | def reset(self): 103 | """reset 104 | """ 105 | self._predictions = [] 106 | 107 | def process(self, inputs, outputs): 108 | """process 109 | """ 110 | assert len(inputs) == 1, 'support only single task evaluation' 111 | assert len(outputs) == 1, 'support only single task evaluation' 112 | inputs = list(inputs.values())[0] 113 | outputs = list(outputs.values())[0] 114 | 115 | pred_logits = outputs 116 | im_id = inputs["im_id"] 117 | self.id2imgname = inputs["id2imgname"] 118 | batch_size = im_id.shape[0] 119 | with paddle.no_grad(): 120 | maxk = max(self.topk) 121 | for i in range(batch_size): 122 | result = -paddle.ones((2,)) 123 | _, pred = pred_logits[i].topk(maxk, -1, True, True) 124 | result[0] = int(pred) 125 | result[1] = int(im_id[i]) 126 | self._predictions.append(result) 127 | 128 | def evaluate(self): 129 | """evaluate 130 | """ 131 | if comm.get_world_size() > 1: 132 | comm.synchronize() 133 | predictions = comm.gather(self._predictions, dst=0) 134 | predictions = list(itertools.chain(*predictions)) 135 | if not comm.is_main_process(): return {} 136 | else: 137 | predictions = self._predictions 138 | 139 | pred_res = [] 140 | for prediction in predictions: 141 | img_path = self.id2imgname[int(prediction[1])] 142 | pred = int(prediction[0]) 143 | tmp = dict() 144 | tmp[os.path.basename(img_path[0])] = pred 145 | pred_res.append(tmp) 146 | 147 | return {'cls': pred_res} -------------------------------------------------------------------------------- /OneForAll/evaluation/rank_cylib/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | /root/paddlejob/workspace/env_run/anaconda3/envs/py37_torch17_cu11/bin/python setup.py build_ext --inplace 3 | rm -rf build 4 | clean: 5 | rm -rf build 6 | rm -f rank_cy.c *.so 7 | -------------------------------------------------------------------------------- /OneForAll/evaluation/rank_cylib/__init__.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | """ 3 | @author: liaoxingyu 4 | @contact: sherlockliao01@gmail.com 5 | """ 6 | 7 | 8 | def compile_helper(): 9 | """Compile helper function at runtime. Make sure this 10 | is invoked on a single process.""" 11 | import os 12 | import subprocess 13 | 14 | path = os.path.abspath(os.path.dirname(__file__)) 15 | ret = subprocess.run(["make", "-C", path]) 16 | if ret.returncode != 0: 17 | print("Making cython reid evaluation module failed, exiting.") 18 | import sys 19 | 20 | sys.exit(1) 21 | -------------------------------------------------------------------------------- /OneForAll/evaluation/rank_cylib/roc_cy.pyx: -------------------------------------------------------------------------------- 1 | # cython: boundscheck=False, wraparound=False, nonecheck=False, cdivision=True 2 | # credits: https://github.com/KaiyangZhou/deep-person-reid/blob/master/torchreid/metrics/rank_cylib/rank_cy.pyx 3 | 4 | import cython 5 | import faiss 6 | import numpy as np 7 | cimport numpy as np 8 | 9 | 10 | """ 11 | Compiler directives: 12 | https://github.com/cython/cython/wiki/enhancements-compilerdirectives 13 | Cython tutorial: 14 | https://cython.readthedocs.io/en/latest/src/userguide/numpy_tutorial.html 15 | Credit to https://github.com/luzai 16 | """ 17 | 18 | 19 | # Main interface 20 | cpdef evaluate_roc_cy(float[:,:] distmat, long[:] q_pids, long[:]g_pids, 21 | long[:]q_camids, long[:]g_camids): 22 | 23 | distmat = np.asarray(distmat, dtype=np.float32) 24 | q_pids = np.asarray(q_pids, dtype=np.int64) 25 | g_pids = np.asarray(g_pids, dtype=np.int64) 26 | q_camids = np.asarray(q_camids, dtype=np.int64) 27 | g_camids = np.asarray(g_camids, dtype=np.int64) 28 | 29 | cdef long num_q = distmat.shape[0] 30 | cdef long num_g = distmat.shape[1] 31 | 32 | cdef: 33 | long[:,:] indices = np.argsort(distmat, axis=1) 34 | long[:,:] matches = (np.asarray(g_pids)[np.asarray(indices)] == np.asarray(q_pids)[:, np.newaxis]).astype(np.int64) 35 | 36 | float[:] pos = np.zeros(num_q*num_g, dtype=np.float32) 37 | float[:] neg = np.zeros(num_q*num_g, dtype=np.float32) 38 | 39 | long valid_pos = 0 40 | long valid_neg = 0 41 | long ind 42 | 43 | long q_idx, q_pid, q_camid, g_idx 44 | long[:] order = np.zeros(num_g, dtype=np.int64) 45 | 46 | float[:] raw_cmc = np.zeros(num_g, dtype=np.float32) # binary vector, positions with value 1 are correct matches 47 | long[:] sort_idx = np.zeros(num_g, dtype=np.int64) 48 | 49 | long idx 50 | 51 | for q_idx in range(num_q): 52 | # get query pid and camid 53 | q_pid = q_pids[q_idx] 54 | q_camid = q_camids[q_idx] 55 | 56 | for g_idx in range(num_g): 57 | order[g_idx] = indices[q_idx, g_idx] 58 | num_g_real = 0 59 | 60 | # remove gallery samples that have the same pid and camid with query 61 | for g_idx in range(num_g): 62 | if (g_pids[order[g_idx]] != q_pid) or (g_camids[order[g_idx]] != q_camid): 63 | raw_cmc[num_g_real] = matches[q_idx][g_idx] 64 | sort_idx[num_g_real] = order[g_idx] 65 | num_g_real += 1 66 | 67 | q_dist = distmat[q_idx] 68 | 69 | for valid_idx in range(num_g_real): 70 | if raw_cmc[valid_idx] == 1: 71 | pos[valid_pos] = q_dist[sort_idx[valid_idx]] 72 | valid_pos += 1 73 | elif raw_cmc[valid_idx] == 0: 74 | neg[valid_neg] = q_dist[sort_idx[valid_idx]] 75 | valid_neg += 1 76 | 77 | cdef float[:] scores = np.hstack((pos[:valid_pos], neg[:valid_neg])) 78 | cdef float[:] labels = np.hstack((np.zeros(valid_pos, dtype=np.float32), 79 | np.ones(valid_neg, dtype=np.float32))) 80 | return np.asarray(scores), np.asarray(labels) 81 | 82 | 83 | # Compute the cumulative sum 84 | cdef void function_cumsum(cython.numeric[:] src, cython.numeric[:] dst, long n): 85 | cdef long i 86 | dst[0] = src[0] 87 | for i in range(1, n): 88 | dst[i] = src[i] + dst[i - 1] -------------------------------------------------------------------------------- /OneForAll/evaluation/rank_cylib/setup.py: -------------------------------------------------------------------------------- 1 | from distutils.core import setup 2 | from distutils.extension import Extension 3 | 4 | import numpy as np 5 | from Cython.Build import cythonize 6 | 7 | 8 | def numpy_include(): 9 | try: 10 | numpy_include = np.get_include() 11 | except AttributeError: 12 | numpy_include = np.get_numpy_include() 13 | return numpy_include 14 | 15 | 16 | ext_modules = [ 17 | Extension( 18 | 'rank_cy', 19 | ['rank_cy.pyx'], 20 | include_dirs=[numpy_include()], 21 | ), 22 | Extension( 23 | 'roc_cy', 24 | ['roc_cy.pyx'], 25 | include_dirs=[numpy_include()], 26 | ) 27 | ] 28 | 29 | setup( 30 | name='Cython-based reid evaluation code', 31 | ext_modules=cythonize(ext_modules) 32 | ) 33 | -------------------------------------------------------------------------------- /OneForAll/evaluation/rank_cylib/test_cython.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import timeit 3 | import numpy as np 4 | import os.path as osp 5 | 6 | sys.path.insert(0, osp.dirname(osp.abspath(__file__)) + '/../../..') 7 | 8 | from fastreid.evaluation.rank import evaluate_rank 9 | from fastreid.evaluation.roc import evaluate_roc 10 | 11 | """ 12 | Test the speed of cython-based evaluation code. The speed improvements 13 | can be much bigger when using the real reid data, which contains a larger 14 | amount of query and gallery images. 15 | Note: you might encounter the following error: 16 | 'AssertionError: Error: all query identities do not appear in gallery'. 17 | This is normal because the inputs are random numbers. Just try again. 18 | """ 19 | 20 | print('*** Compare running time ***') 21 | 22 | setup = ''' 23 | import sys 24 | import os.path as osp 25 | import numpy as np 26 | sys.path.insert(0, osp.dirname(osp.abspath(__file__)) + '/../../..') 27 | from fastreid.evaluation.rank import evaluate_rank 28 | from fastreid.evaluation.roc import evaluate_roc 29 | num_q = 30 30 | num_g = 300 31 | dim = 512 32 | max_rank = 5 33 | q_feats = np.random.rand(num_q, dim).astype(np.float32) * 20 34 | q_feats = q_feats / np.linalg.norm(q_feats, ord=2, axis=1, keepdims=True) 35 | g_feats = np.random.rand(num_g, dim).astype(np.float32) * 20 36 | g_feats = g_feats / np.linalg.norm(g_feats, ord=2, axis=1, keepdims=True) 37 | distmat = 1 - np.dot(q_feats, g_feats.transpose()) 38 | q_pids = np.random.randint(0, num_q, size=num_q) 39 | g_pids = np.random.randint(0, num_g, size=num_g) 40 | q_camids = np.random.randint(0, 5, size=num_q) 41 | g_camids = np.random.randint(0, 5, size=num_g) 42 | ''' 43 | 44 | print('=> Using CMC metric') 45 | pytime = timeit.timeit( 46 | 'evaluate_rank(distmat, q_pids, g_pids, q_camids, g_camids, max_rank, use_cython=False)', 47 | setup=setup, 48 | number=20 49 | ) 50 | cytime = timeit.timeit( 51 | 'evaluate_rank(distmat, q_pids, g_pids, q_camids, g_camids, max_rank, use_cython=True)', 52 | setup=setup, 53 | number=20 54 | ) 55 | print('Python time: {} s'.format(pytime)) 56 | print('Cython time: {} s'.format(cytime)) 57 | print('CMC Cython is {} times faster than python\n'.format(pytime / cytime)) 58 | 59 | print('=> Using ROC metric') 60 | pytime = timeit.timeit( 61 | 'evaluate_roc(distmat, q_pids, g_pids, q_camids, g_camids, use_cython=False)', 62 | setup=setup, 63 | number=20 64 | ) 65 | cytime = timeit.timeit( 66 | 'evaluate_roc(distmat, q_pids, g_pids, q_camids, g_camids, use_cython=True)', 67 | setup=setup, 68 | number=20 69 | ) 70 | print('Python time: {} s'.format(pytime)) 71 | print('Cython time: {} s'.format(cytime)) 72 | print('ROC Cython is {} times faster than python\n'.format(pytime / cytime)) 73 | 74 | print("=> Check precision") 75 | num_q = 30 76 | num_g = 300 77 | dim = 512 78 | max_rank = 5 79 | q_feats = np.random.rand(num_q, dim).astype(np.float32) * 20 80 | q_feats = q_feats / np.linalg.norm(q_feats, ord=2, axis=1, keepdims=True) 81 | g_feats = np.random.rand(num_g, dim).astype(np.float32) * 20 82 | g_feats = g_feats / np.linalg.norm(g_feats, ord=2, axis=1, keepdims=True) 83 | distmat = 1 - np.dot(q_feats, g_feats.transpose()) 84 | q_pids = np.random.randint(0, num_q, size=num_q) 85 | g_pids = np.random.randint(0, num_g, size=num_g) 86 | q_camids = np.random.randint(0, 5, size=num_q) 87 | g_camids = np.random.randint(0, 5, size=num_g) 88 | 89 | cmc_py, mAP_py, mINP_py = evaluate_rank(distmat, q_pids, g_pids, q_camids, g_camids, max_rank, use_cython=False) 90 | 91 | cmc_cy, mAP_cy, mINP_cy = evaluate_rank(distmat, q_pids, g_pids, q_camids, g_camids, max_rank, use_cython=True) 92 | 93 | np.testing.assert_allclose(cmc_py, cmc_cy, rtol=1e-3, atol=1e-6) 94 | np.testing.assert_allclose(mAP_py, mAP_cy, rtol=1e-3, atol=1e-6) 95 | np.testing.assert_allclose(mINP_py, mINP_cy, rtol=1e-3, atol=1e-6) 96 | print('Rank results between python and cython are the same!') 97 | 98 | scores_cy, labels_cy = evaluate_roc(distmat, q_pids, g_pids, q_camids, g_camids, use_cython=True) 99 | scores_py, labels_py = evaluate_roc(distmat, q_pids, g_pids, q_camids, g_camids, use_cython=False) 100 | 101 | np.testing.assert_allclose(scores_cy, scores_py, rtol=1e-3, atol=1e-6) 102 | np.testing.assert_allclose(labels_cy, labels_py, rtol=1e-3, atol=1e-6) 103 | print('ROC results between python and cython are the same!\n') 104 | 105 | print("=> Check exact values") 106 | print("mAP = {} \ncmc = {}\nmINP = {}\nScores = {}".format(np.array(mAP_cy), cmc_cy, np.array(mINP_cy), scores_cy)) 107 | -------------------------------------------------------------------------------- /OneForAll/evaluation/segmentation_evaluator.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from __future__ import absolute_import 16 | from __future__ import division 17 | from __future__ import print_function 18 | 19 | import os 20 | import sys 21 | import json 22 | import paddle 23 | import numpy as np 24 | import typing 25 | from pathlib import Path 26 | import logging 27 | import copy 28 | import itertools 29 | 30 | from evaluation.evaluator import DatasetEvaluator 31 | from utils import comm 32 | 33 | 34 | logger = logging.getLogger("ufo.segmentation_evaluator") 35 | 36 | 37 | class SegEvaluator(object): 38 | """ 39 | SegEvaluator 40 | """ 41 | def __init__(self, mode='train'): 42 | """init 43 | """ 44 | self.mode = mode 45 | 46 | def reset(self): 47 | """reset 48 | """ 49 | pass 50 | 51 | def process(self, inputs, outputs): 52 | """process 53 | """ 54 | pass 55 | 56 | def evaluate(self): 57 | """evaluate 58 | """ 59 | pass 60 | 61 | 62 | class SegEvaluatorInfer(object): 63 | """ 64 | SegEvaluatorInfer 65 | """ 66 | def __init__(self, mode='test', save_path='./'): 67 | """init 68 | """ 69 | self.mode = mode 70 | self.save_path = save_path 71 | 72 | def reset(self): 73 | """reset 74 | """ 75 | pass 76 | 77 | def process(self, inputs, outputs): 78 | """process 79 | """ 80 | pass 81 | 82 | def evaluate(self): 83 | """evaluate 84 | """ 85 | pass -------------------------------------------------------------------------------- /OneForAll/evaluation/testing.py: -------------------------------------------------------------------------------- 1 | """evaluation.testing 2 | """ 3 | # Copyright (c) 4 | import logging 5 | import numpy as np 6 | import pprint 7 | import sys 8 | from collections.abc import Mapping 9 | 10 | 11 | def print_csv_format(results): 12 | """ 13 | Print main metrics in a format similar to Detectron, 14 | so that they are easy to copypaste into a spreadsheet. 15 | 16 | Args: 17 | results (OrderedDict[dict]): task_name -> {metric -> score} 18 | unordered dict can also be printed, but in arbitrary order 19 | """ 20 | assert isinstance(results, Mapping) or not len(results), results 21 | logger = logging.getLogger(__name__) 22 | for task, res in results.items(): 23 | if isinstance(res, Mapping): 24 | # Don't print "AP-category" metrics since they are usually not tracked. 25 | important_res = [(k, v) for k, v in res.items() if "-" not in k] 26 | logger.info("copypaste: Task: {}".format(task)) 27 | logger.info("copypaste: " + ",".join([k[0] for k in important_res])) 28 | logger.info("copypaste: " + ",".join(["{0:.4f}".format(k[1]) for k in important_res])) 29 | else: 30 | logger.info("copypaste: {}={}".format(task, res)) 31 | 32 | 33 | def verify_results(cfg, results): 34 | """ 35 | Args: 36 | results (OrderedDict[dict]): task_name -> {metric -> score} 37 | 38 | Returns: 39 | bool: whether the verification succeeds or not 40 | """ 41 | expected_results = cfg.TEST.EXPECTED_RESULTS 42 | if not len(expected_results): 43 | return True 44 | 45 | ok = True 46 | for task, metric, expected, tolerance in expected_results: 47 | actual = results[task].get(metric, None) 48 | if actual is None: 49 | ok = False 50 | continue 51 | if not np.isfinite(actual): 52 | ok = False 53 | continue 54 | diff = abs(actual - expected) 55 | if diff > tolerance: 56 | ok = False 57 | 58 | logger = logging.getLogger(__name__) 59 | if not ok: 60 | logger.error("Result verification failed!") 61 | logger.error("Expected Results: " + str(expected_results)) 62 | logger.error("Actual Results: " + pprint.pformat(results)) 63 | 64 | sys.exit(1) 65 | else: 66 | logger.info("Results verification passed.") 67 | return ok 68 | 69 | 70 | def flatten_results_dict(results): 71 | """ 72 | Expand a hierarchical dict of scalars into a flat dict of scalars. 73 | If results[k1][k2][k3] = v, the returned dict will have the entry 74 | {"k1/k2/k3": v}. 75 | 76 | Args: 77 | results (dict): 78 | """ 79 | r = {} 80 | for k, v in results.items(): 81 | if isinstance(v, Mapping): 82 | v = flatten_results_dict(v) 83 | for kk, vv in v.items(): 84 | r[k + "/" + kk] = vv 85 | else: 86 | r[k] = v 87 | return r 88 | -------------------------------------------------------------------------------- /OneForAll/fastreid/data/__init__.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | """ 3 | @author: sherlock 4 | @contact: sherlockliao01@gmail.com 5 | """ 6 | 7 | # from . import transforms # isort:skip 8 | # from .build import ( 9 | # build_reid_train_loader, 10 | # build_reid_test_loader, 11 | # ) 12 | from .common import CommDataset 13 | 14 | # ensure the builtin datasets are registered 15 | from . import datasets, samplers # isort:skip 16 | 17 | # __all__ = [k for k in globals().keys() if not k.startswith("_")] 18 | -------------------------------------------------------------------------------- /OneForAll/fastreid/data/common.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | """ 3 | @author: liaoxingyu 4 | @contact: sherlockliao01@gmail.com 5 | """ 6 | from paddle.io import Dataset 7 | 8 | from .data_utils import read_image 9 | 10 | class CommDataset(Dataset): 11 | """Image Person ReID Dataset""" 12 | 13 | def __init__(self, img_items, transform=None, relabel=True, dataset_name=None): 14 | self.img_items = img_items 15 | self.transform = transform 16 | self.relabel = relabel 17 | self.dataset_name = dataset_name 18 | self.labels = [] 19 | 20 | pid_set = set() 21 | cam_set = set() 22 | for i in img_items: 23 | pid_set.add(i[1]) 24 | cam_set.add(i[2]) 25 | 26 | self.pids = sorted(list(pid_set)) 27 | self.cams = sorted(list(cam_set)) 28 | if relabel: 29 | self.pid_dict = dict([(p, i) for i, p in enumerate(self.pids)]) 30 | self.cam_dict = dict([(p, i) for i, p in enumerate(self.cams)]) 31 | 32 | def __len__(self): 33 | return len(self.img_items) 34 | 35 | def __getitem__(self, index): 36 | n_retry = 10 37 | for _ in range(n_retry): 38 | try: 39 | img_item = self.img_items[index] 40 | img_path = img_item[0] 41 | pid = img_item[1] 42 | camid = img_item[2] 43 | img = read_image(img_path) 44 | if self.transform is not None: img = self.transform(img) 45 | break 46 | except Exception as e: 47 | index = (index + 1) % len(self.img_items) 48 | print(e) 49 | 50 | if self.relabel: 51 | pid = self.pid_dict[pid] 52 | camid = self.cam_dict[camid] 53 | return { 54 | "images": img, 55 | "targets": pid, 56 | "camids": camid, 57 | # "img_paths": img_path, 58 | } 59 | 60 | @property 61 | def num_classes(self): 62 | """get number of classes 63 | """ 64 | return len(self.pids) 65 | 66 | @property 67 | def num_cameras(self): 68 | """get number of cameras 69 | """ 70 | return len(self.cams) 71 | -------------------------------------------------------------------------------- /OneForAll/fastreid/data/data_utils.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | """ 3 | @author: liaoxingyu 4 | @contact: sherlockliao01@gmail.com 5 | """ 6 | import numpy as np 7 | from PIL import Image, ImageOps 8 | import threading 9 | 10 | import queue 11 | from paddle.io import DataLoader 12 | 13 | from utils.file_io import PathManager 14 | 15 | 16 | def read_image(file_name, format=None): 17 | """ 18 | Read an image into the given format. 19 | Will apply rotation and flipping if the image has such exif information. 20 | 21 | Args: 22 | file_name (str): image file path 23 | format (str): one of the supported image modes in PIL, or "BGR" 24 | Returns: 25 | image (np.ndarray): an HWC image 26 | """ 27 | with PathManager.open(file_name, "rb") as f: 28 | image = Image.open(f) 29 | 30 | # work around this bug: https://github.com/python-pillow/Pillow/issues/3973 31 | try: 32 | image = ImageOps.exif_transpose(image) 33 | except Exception: 34 | pass 35 | 36 | if format is not None: 37 | # PIL only supports RGB, so convert to RGB and flip channels over below 38 | conversion_format = format 39 | if format == "BGR": 40 | conversion_format = "RGB" 41 | image = image.convert(conversion_format) 42 | image = np.asarray(image) 43 | 44 | # PIL squeezes out the channel dimension for "L", so make it HWC 45 | if format == "L": 46 | image = np.expand_dims(image, -1) 47 | 48 | # handle formats not supported by PIL 49 | elif format == "BGR": 50 | # flip channels if needed 51 | image = image[:, :, ::-1] 52 | 53 | # handle grayscale mixed in RGB images 54 | elif len(image.shape) == 2: 55 | image = np.repeat(image[..., np.newaxis], 3, axis=-1) 56 | 57 | image = Image.fromarray(image) 58 | 59 | return image 60 | 61 | 62 | """ 63 | #based on http://stackoverflow.com/questions/7323664/python-generator-pre-fetch 64 | This is a single-function package that transforms arbitrary generator into a background-thead generator that 65 | prefetches several batches of data in a parallel background thead. 66 | 67 | This is useful if you have a computationally heavy process (CPU or GPU) that 68 | iteratively processes minibatches from the generator while the generator 69 | consumes some other resource (disk IO / loading from database / more CPU if you have unused cores). 70 | 71 | By default these two processes will constantly wait for one another to finish. If you make generator work in 72 | prefetch mode (see examples below), they will work in parallel, potentially saving you your GPU time. 73 | We personally use the prefetch generator when iterating minibatches of data for deep learning with PyTorch etc. 74 | 75 | Quick usage example (ipython notebook) - https://github.com/justheuristic/prefetch_generator/blob/master/example.ipynb 76 | This package contains this object 77 | - BackgroundGenerator(any_other_generator[,max_prefetch = something]) 78 | """ 79 | 80 | -------------------------------------------------------------------------------- /OneForAll/fastreid/data/datasets/__init__.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | """ 3 | @author: liaoxingyu 4 | @contact: sherlockliao01@gmail.com 5 | """ 6 | 7 | from ...utils.registry import Registry 8 | 9 | DATASET_REGISTRY = Registry("DATASET") 10 | DATASET_REGISTRY.__doc__ = """ 11 | Registry for datasets 12 | It must returns an instance of :class:`Backbone`. 13 | """ 14 | 15 | # Person re-id datasets 16 | # from .cuhk03 import CUHK03 17 | # from .dukemtmcreid import DukeMTMC 18 | # from .market1501 import Market1501 19 | # from .msmt17 import MSMT17 20 | # from .AirportALERT import AirportALERT 21 | # from .iLIDS import iLIDS 22 | # from .pku import PKU 23 | # from .prai import PRAI 24 | # from .prid import PRID 25 | # from .grid import GRID 26 | # from .saivt import SAIVT 27 | # from .sensereid import SenseReID 28 | # from .sysu_mm import SYSU_mm 29 | # from .thermalworld import Thermalworld 30 | # from .pes3d import PeS3D 31 | # from .caviara import CAVIARa 32 | # from .viper import VIPeR 33 | # from .lpw import LPW 34 | # from .shinpuhkan import Shinpuhkan 35 | # from .wildtracker import WildTrackCrop 36 | # from .cuhk_sysu import cuhkSYSU 37 | 38 | # Vehicle re-id datasets 39 | # from .veri import VeRi 40 | # from .vehicleid import VehicleID, SmallVehicleID, MediumVehicleID, LargeVehicleID 41 | # from .veriwild import VeRiWild, SmallVeRiWild, MediumVeRiWild, LargeVeRiWild 42 | 43 | # from .retri import SOP, InShop, CUB, Cars196 44 | 45 | # from .ms1mv2 import MS1MV2, LFW, CPLFW, CALFW, CFP_FF, CFP_FP, AgeDB_30, VGG2_FP 46 | # from .ms1mv3 import MS1MV3 47 | # from .veriall import VeriAll 48 | # from .personall import PersonAll 49 | # from .decathlon import Aircraft, Cifar100, Daimlerpedcls, Dtd, Gtsrb, Imagenet12, Omniglot, Svhn, Ucf101, VggFlowers 50 | # from .intern_train import DF20, IWildCam2020, TsingHuaDogs, FoodX251, CompCars 51 | # from .imagenet import ImageNet1k, ImageNet1kBD 52 | # from .intern_test import PatchCamelyon, GTSRB, Fer2013, Retinopathy, Resisc45, \ 53 | # EuroSAT, SVHN, FGVCaircraft, Caltech101, DTD, SUN397, \ 54 | # Oxford102Flower, OxfordPet, Food101, CIFAR10, CIFAR100 55 | 56 | # from .luperson import LUPerson 57 | from .cocodet import COCODataSet 58 | 59 | __all__ = [k for k in globals().keys() if "builtin" not in k and not k.startswith("_")] 60 | -------------------------------------------------------------------------------- /OneForAll/fastreid/data/samplers/__init__.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | """ 3 | @author: liaoxingyu 4 | @contact: sherlockliao01@gmail.com 5 | """ 6 | 7 | # from .triplet_sampler import BalancedIdentitySampler 8 | from .triplet_sampler import NaiveIdentitySampler 9 | # from .triplet_sampler import NaiveIdentitySamplerFaster 10 | # from .triplet_sampler import SetReWeightSampler 11 | from .data_sampler import TrainingSampler, InferenceSampler, OrderInferenceSampler 12 | # from .imbalance_sampler import ImbalancedDatasetSampler 13 | 14 | __all__ = [ 15 | # "BalancedIdentitySampler", 16 | # "NaiveIdentitySampler", 17 | # "SetReWeightSampler", 18 | "TrainingSampler", 19 | "InferenceSampler", 20 | # "ImbalancedDatasetSampler", 21 | "NaiveIdentitySamplerFaster" 22 | ] 23 | -------------------------------------------------------------------------------- /OneForAll/fastreid/utils/__init__.py: -------------------------------------------------------------------------------- 1 | """__init__.py 2 | """ 3 | 4 | -------------------------------------------------------------------------------- /OneForAll/fastreid/utils/registry.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved 3 | """registry.py 4 | """ 5 | from typing import Dict, Optional 6 | 7 | 8 | class Registry(object): 9 | """ 10 | The registry that provides name mapping, to support third-party 11 | users' custom modules. 12 | To create a registry (e.g. a backbone registry): 13 | .. code-block:: python 14 | BACKBONE_REGISTRY = Registry('BACKBONE') 15 | To register an object: 16 | .. code-block:: python 17 | @BACKBONE_REGISTRY.register() 18 | class MyBackbone(): 19 | ... 20 | Or: 21 | .. code-block:: python 22 | BACKBONE_REGISTRY.register(MyBackbone) 23 | """ 24 | 25 | def __init__(self, name): 26 | """ 27 | Args: 28 | name (str): the name of this registry 29 | """ 30 | self._name = name 31 | self._obj_map: Dict[str, object] = {} 32 | 33 | def _do_register(self, name, obj): 34 | assert ( 35 | name not in self._obj_map 36 | ), "An object named '{}' was already registered in '{}' registry!".format( 37 | name, self._name 38 | ) 39 | self._obj_map[name] = obj 40 | 41 | def register(self, obj=None): 42 | """ 43 | Register the given object under the the name `obj.__name__`. 44 | Can be used as either a decorator or not. See docstring of this class for usage. 45 | """ 46 | if obj is None: 47 | # used as a decorator 48 | def deco(func_or_class): 49 | name = func_or_class.__name__ # pyre-ignore 50 | self._do_register(name, func_or_class) 51 | return func_or_class 52 | 53 | return deco 54 | 55 | # used as a function call 56 | name = obj.__name__ # pyre-ignore 57 | self._do_register(name, obj) 58 | 59 | def get(self, name): 60 | """get 61 | """ 62 | ret = self._obj_map.get(name) 63 | if ret is None: 64 | raise KeyError( 65 | "No object named '{}' found in '{}' registry!".format( 66 | name, self._name 67 | ) 68 | ) 69 | return ret 70 | -------------------------------------------------------------------------------- /OneForAll/layers/any_softmax.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | """paddle authors 3 | """ 4 | 5 | import paddle 6 | import paddle.nn as nn 7 | 8 | __all__ = [ 9 | "Linear", 10 | "CosSoftmax", 11 | ] 12 | 13 | 14 | class Linear(nn.Layer): 15 | """Linear 16 | """ 17 | def __init__(self, num_classes, scale, margin): 18 | super().__init__() 19 | self.num_classes = num_classes 20 | self.s = scale 21 | self.m = margin 22 | 23 | def forward(self, logits, targets): 24 | """forward 25 | """ 26 | return logits * self.s 27 | 28 | def extra_repr(self): 29 | """extra_repr 30 | """ 31 | return "num_classes={}, scale={}, margin={}".format(self.num_classes, self.s, self.m) 32 | 33 | 34 | class CosSoftmax(Linear): 35 | r"""Implement of large margin cosine distance: 36 | """ 37 | 38 | def forward(self, logits, targets): 39 | """forward 40 | """ 41 | m_zero = paddle.zeros_like(logits, dtype=logits.dtype) 42 | m_valid = paddle.ones_like(logits, dtype=logits.dtype) * self.m 43 | 44 | o = targets.unsqueeze(-1).tile((1, logits.shape[1])) 45 | k = paddle.arange(logits.shape[1]).unsqueeze(0).expand_as(o) 46 | m_hot = paddle.where(o == k, m_valid, m_zero) 47 | logits -= m_hot 48 | 49 | logits = logits * self.s 50 | return logits -------------------------------------------------------------------------------- /OneForAll/modeling/__init__.py: -------------------------------------------------------------------------------- 1 | """Init 2 | """ 3 | # Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License" 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. -------------------------------------------------------------------------------- /OneForAll/modeling/backbones/__init__.py: -------------------------------------------------------------------------------- 1 | """Init 2 | """ 3 | # Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License" 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | from .vision_transformer import build_vit_backbone_lazy 18 | -------------------------------------------------------------------------------- /OneForAll/modeling/backbones/super_module/Linear_super.py: -------------------------------------------------------------------------------- 1 | """super_module/Linear_super.py 2 | """ 3 | import paddle 4 | import paddle.nn as nn 5 | import paddle.nn.functional as F 6 | import numpy as np 7 | 8 | 9 | xavier_uniform_ = paddle.nn.initializer.XavierUniform() 10 | constant_ = paddle.nn.initializer.Constant() 11 | 12 | class LinearSuper(nn.Linear): 13 | """LinearSuper 14 | """ 15 | def __init__(self, super_in_dim, super_out_dim, 16 | bias_attr=None, uniform_=None, non_linear='linear', scale=False, weight_attr=None): 17 | super().__init__(super_in_dim, super_out_dim, weight_attr=weight_attr, bias_attr=bias_attr) 18 | 19 | # super_in_dim and super_out_dim indicate the largest network! 20 | self.super_in_dim = super_in_dim 21 | self.super_out_dim = super_out_dim 22 | 23 | # input_dim and output_dim indicate the current sampled size 24 | self.sample_in_dim = None 25 | self.sample_out_dim = None 26 | 27 | self.samples = {} 28 | 29 | self.scale = scale 30 | # self._reset_parameters(bias, uniform_, non_linear) #TODO add initialization for weights 31 | self.profiling = False 32 | 33 | def _reset_parameters(self, bias, uniform_, non_linear): 34 | xavier_uniform_(self.weight) if uniform_ is None else uniform_(self.weight) #TODO add non_linear 35 | if bias: 36 | constant_(self.bias, 0.) 37 | 38 | def set_sample_config(self, sample_in_dim, sample_out_dim): 39 | """set_sample_config 40 | """ 41 | self.sample_in_dim = sample_in_dim 42 | self.sample_out_dim = sample_out_dim 43 | 44 | self._sample_parameters() 45 | 46 | def _sample_parameters(self): 47 | """_sample_parameters 48 | """ 49 | self.samples['weight'] = sample_weight(self.weight, self.sample_in_dim, self.sample_out_dim) 50 | self.samples['bias'] = self.bias 51 | self.sample_scale = self.super_out_dim / self.sample_out_dim 52 | if self.bias is not None: 53 | self.samples['bias'] = sample_bias(self.bias, self.sample_out_dim) 54 | return self.samples 55 | 56 | def forward(self, x): 57 | """forward 58 | """ 59 | self._sample_parameters() 60 | return F.linear(x, self.samples['weight'], self.samples['bias']) * (self.sample_scale if self.scale else 1) 61 | 62 | def calc_sampled_param_num(self): 63 | """" 64 | """ 65 | 66 | assert 'weight' in self.samples.keys() 67 | weight_numel = self.samples['weight'].numel() 68 | 69 | if self.samples['bias'] is not None: 70 | bias_numel = self.samples['bias'].numel() 71 | else: 72 | bias_numel = 0 73 | 74 | return weight_numel + bias_numel 75 | 76 | def get_complexity(self, sequence_length): 77 | """get_complexity 78 | """ 79 | total_flops = 0 80 | total_flops += sequence_length * np.prod(self.samples['weight'].size()) 81 | return total_flops 82 | 83 | 84 | def sample_weight(weight, sample_in_dim, sample_out_dim): 85 | """sample_weight 86 | """ 87 | sample_weight = weight[:sample_in_dim, :] 88 | sample_weight = sample_weight[:, :sample_out_dim] 89 | 90 | return sample_weight 91 | 92 | 93 | def sample_bias(bias, sample_out_dim): 94 | """sample_bias 95 | """ 96 | sample_bias = bias[:sample_out_dim] 97 | 98 | return sample_bias 99 | -------------------------------------------------------------------------------- /OneForAll/modeling/backbones/super_module/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiteng01/CVPR2023_foundation_model_Track1/5bdc7f8fca439495dc55281de937eaf2a2e77f2f/OneForAll/modeling/backbones/super_module/__init__.py -------------------------------------------------------------------------------- /OneForAll/modeling/backbones/super_module/qkv_super.py: -------------------------------------------------------------------------------- 1 | """super_module/qkv_super.py 2 | """ 3 | import paddle 4 | import paddle.nn as nn 5 | import paddle.nn.functional as F 6 | import numpy as np 7 | 8 | 9 | xavier_uniform_ = paddle.nn.initializer.XavierUniform() 10 | constant_ = paddle.nn.initializer.Constant() 11 | 12 | class QkvSuper(nn.Linear): 13 | """QkvSuper 14 | """ 15 | def __init__(self, super_in_dim, super_out_dim, 16 | bias_attr=None, uniform_=None, non_linear='linear', scale=False, weight_attr=None): 17 | super().__init__(super_in_dim, super_out_dim, bias_attr=bias_attr, weight_attr=weight_attr) 18 | 19 | # super_in_dim and super_out_dim indicate the largest network! 20 | self.super_in_dim = super_in_dim 21 | self.super_out_dim = super_out_dim 22 | 23 | # input_dim and output_dim indicate the current sampled size 24 | self.sample_in_dim = None 25 | self.sample_out_dim = None 26 | 27 | self.samples = {} 28 | 29 | self.scale = scale 30 | # self._reset_parameters(bias, uniform_, non_linear) #TODO add initialization for weights 31 | self.profiling = False 32 | 33 | def _reset_parameters(self, bias, uniform_, non_linear): 34 | xavier_uniform_(self.weight) if uniform_ is None else uniform_(self.weight) #TODO add non_linear 35 | if bias: 36 | constant_(self.bias, 0.) 37 | 38 | def set_sample_config(self, sample_in_dim, sample_out_dim): 39 | """set_sample_config 40 | """ 41 | self.sample_in_dim = sample_in_dim 42 | self.sample_out_dim = sample_out_dim 43 | 44 | self._sample_parameters() 45 | 46 | def _sample_parameters(self): 47 | """_sample_parameters 48 | """ 49 | self.samples['weight'] = sample_weight(self.weight, self.sample_in_dim, self.sample_out_dim) 50 | self.samples['bias'] = self.bias 51 | self.sample_scale = self.super_out_dim / self.sample_out_dim 52 | if self.bias is not None: 53 | self.samples['bias'] = sample_bias(self.bias, self.sample_out_dim) 54 | return self.samples 55 | 56 | def forward(self, x): 57 | """forward 58 | """ 59 | self._sample_parameters() 60 | return F.linear(x, self.samples['weight'], self.samples['bias']) * (self.sample_scale if self.scale else 1) 61 | 62 | def calc_sampled_param_num(self): 63 | """" 64 | """ 65 | 66 | assert 'weight' in self.samples.keys() 67 | weight_numel = self.samples['weight'].numel() 68 | 69 | if self.samples['bias'] is not None: 70 | bias_numel = self.samples['bias'].numel() 71 | else: 72 | bias_numel = 0 73 | 74 | return weight_numel + bias_numel 75 | 76 | def get_complexity(self, sequence_length): 77 | """get_complexity 78 | """ 79 | total_flops = 0 80 | total_flops += sequence_length * np.prod(self.samples['weight'].size()) 81 | return total_flops 82 | 83 | 84 | def sample_weight(weight, sample_in_dim, sample_out_dim): 85 | """sample_weight 86 | """ 87 | _, super_out_dim = weight.shape 88 | sample_weight = weight[:sample_in_dim, :] 89 | sample_weight = paddle.concat( 90 | [sample_weight[:, i * super_out_dim // 3: i * super_out_dim // 3 + sample_out_dim // 3] for i in range(3)], 91 | axis=1) 92 | 93 | return sample_weight 94 | 95 | 96 | def sample_bias(bias, sample_out_dim): 97 | """sample_weight 98 | """ 99 | super_out_dim = len(bias) 100 | sample_bias = paddle.concat( 101 | [bias[i * super_out_dim // 3: i * super_out_dim // 3 + sample_out_dim // 3] for i in range(3)], 102 | axis=0 103 | ) 104 | 105 | return sample_bias 106 | -------------------------------------------------------------------------------- /OneForAll/modeling/heads/cbam.py: -------------------------------------------------------------------------------- 1 | import paddle 2 | from paddle import nn 3 | 4 | 5 | class CBAM_Module(nn.Layer): 6 | def __init__(self, channels, reduction=16): 7 | super(CBAM_Module, self).__init__() 8 | self.avg_pool = nn.AdaptiveAvgPool2D(output_size=1) 9 | self.max_pool = nn.AdaptiveMaxPool2D(output_size=1) 10 | self.fc1 = nn.Conv2D(in_channels=channels, out_channels=channels // reduction, kernel_size=1, padding=0) 11 | self.relu = nn.ReLU() 12 | self.fc2 = nn.Conv2D(in_channels=channels // reduction, out_channels=channels, kernel_size=1, padding=0) 13 | 14 | self.sigmoid_channel = nn.Sigmoid() 15 | self.conv_after_concat = nn.Conv2D(in_channels=2, out_channels=1, kernel_size=7, stride=1, padding=3) 16 | self.sigmoid_spatial = nn.Sigmoid() 17 | 18 | def forward(self, x): 19 | # Channel Attention Module 20 | module_input = x 21 | avg = self.relu(self.fc1(self.avg_pool(x))) 22 | avg = self.fc2(avg) 23 | mx = self.relu(self.fc1(self.max_pool(x))) 24 | mx = self.fc2(mx) 25 | x = avg + mx 26 | x = self.sigmoid_channel(x) 27 | 28 | # Spatial Attention Module 29 | x = module_input * x 30 | module_input = x 31 | avg = paddle.mean(x, axis=1, keepdim=True) 32 | mx = paddle.argmax(x, axis=1, keepdim=True) 33 | mx = paddle.cast(mx, 'float32') 34 | x = paddle.concat([avg, mx], axis=1) 35 | x = self.conv_after_concat(x) 36 | x = self.sigmoid_spatial(x) 37 | x = module_input * x 38 | 39 | return x -------------------------------------------------------------------------------- /OneForAll/modeling/heads/classification.py: -------------------------------------------------------------------------------- 1 | # !/usr/bin/env python3 2 | # Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | 17 | import paddle 18 | import paddle.nn as nn 19 | import paddle.nn.functional as F 20 | from collections import OrderedDict 21 | import pycocotools.mask as mask_util 22 | from modeling.initializer import linear_init_, constant_ 23 | from modeling.losses import triplet_loss, cross_entropy_loss, log_accuracy 24 | from paddle.nn.initializer import TruncatedNormal, Constant, Normal 25 | from paddle import ParamAttr 26 | from layers import any_softmax 27 | import random 28 | 29 | trunc_normal_ = TruncatedNormal(std=.02) 30 | zeros_ = Constant(value=0.) 31 | ones_ = Constant(value=1.) 32 | normal_ = Normal 33 | BIAS_LR_FACTOR=2.0 34 | 35 | class ClassificationNeck(nn.Layer): 36 | """d 37 | """ 38 | def __init__(self): 39 | super().__init__() 40 | pass 41 | 42 | def forward(self, x): 43 | """d 44 | """ 45 | if isinstance(x, (list, tuple)): 46 | return x[-1] 47 | else: 48 | return x 49 | 50 | class GlobalAvgPool(nn.AdaptiveAvgPool2D): 51 | """ 52 | GlobalAvgPool 53 | """ 54 | def __init__(self, output_size=1, *args, **kwargs): 55 | """Init 56 | """ 57 | super().__init__(output_size) 58 | 59 | class ClassificationHead(nn.Layer): 60 | """d 61 | """ 62 | def __init__(self, feat_dim, num_classes, neck, scale=1, 63 | margin=0, load_head=False, pretrain_path='', **loss_kwargs, 64 | ): 65 | super().__init__() 66 | self.neck = neck 67 | self.pool_layer = GlobalAvgPool() 68 | assert num_classes > 0 69 | self.linear = paddle.nn.Linear(feat_dim, num_classes, 70 | bias_attr=ParamAttr(learning_rate=0.1 * BIAS_LR_FACTOR), 71 | weight_attr=ParamAttr(learning_rate=0.1) 72 | ) 73 | self.cls_layer = getattr(any_softmax, "Linear")(num_classes, scale, margin) 74 | if load_head: 75 | # pretrain_path 76 | state_dict = paddle.load(pretrain_path) 77 | print("Loading Head from {}".format(pretrain_path)) 78 | if 'model' in state_dict: 79 | state_dict = state_dict.pop('model') 80 | if 'state_dict' in state_dict: 81 | state_dict = state_dict.pop('state_dict') 82 | state_dict_new = OrderedDict() 83 | for k, v in state_dict.items(): 84 | if 'head' in k: 85 | k_new = k[5:] 86 | state_dict_new[k_new] = state_dict[k] 87 | self.linear.set_state_dict(state_dict_new) 88 | 89 | self.ce_kwargs = loss_kwargs.get('ce', {}) 90 | 91 | def forward(self, body_feats, inputs): 92 | """d 93 | """ 94 | neck_feat = self.neck(body_feats) 95 | feat = self.pool_layer(neck_feat) 96 | feat = feat[:, :, 0, 0] 97 | targets = inputs["targets"] 98 | if self.training: 99 | loss_dict = {} 100 | logits = self.linear(feat) 101 | pred_class_logits = logits * self.cls_layer.s 102 | cls_outputs = self.cls_layer(logits, targets) 103 | # Log prediction accuracy 104 | # acc = log_accuracy(pred_class_logits, gt_labels) 105 | ce_prob = self.ce_kwargs.get('prob', 1.0) 106 | if random.random() < ce_prob: 107 | loss_exist = 1.0 108 | else: 109 | loss_exist = 0.0 110 | loss_dict['loss_cls'] = cross_entropy_loss( 111 | cls_outputs, 112 | targets, 113 | self.ce_kwargs.get('eps', 0.0), 114 | self.ce_kwargs.get('alpha', 0.2) 115 | ) * self.ce_kwargs.get('scale', 1.0) * loss_exist 116 | return loss_dict 117 | else: 118 | return self.linear(feat) 119 | -------------------------------------------------------------------------------- /OneForAll/modeling/heads/cls_head.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | from __future__ import division 3 | from __future__ import print_function 4 | 5 | import paddle.nn as nn 6 | from paddle.nn import AdaptiveAvgPool2D 7 | from modeling.losses import cross_entropy_loss 8 | import paddle 9 | from paddleseg.models import layers 10 | 11 | from .cbam import CBAM_Module 12 | 13 | 14 | class ConvBNLayer(nn.Layer): 15 | def __init__(self, 16 | in_channels, 17 | out_channels, 18 | kernel_size, 19 | stride=1, 20 | dilation=1, 21 | groups=1, 22 | is_vd_mode=False, 23 | act=None, 24 | data_format='NCHW'): 25 | super(ConvBNLayer, self).__init__() 26 | if dilation != 1 and kernel_size != 3: 27 | raise RuntimeError("When the dilation isn't 1," \ 28 | "the kernel_size should be 3.") 29 | 30 | self.is_vd_mode = is_vd_mode 31 | self._pool2d_avg = nn.AvgPool2D( 32 | kernel_size=2, 33 | stride=2, 34 | padding=0, 35 | ceil_mode=True, 36 | data_format=data_format) 37 | self._conv = nn.Conv2D( 38 | in_channels=in_channels, 39 | out_channels=out_channels, 40 | kernel_size=kernel_size, 41 | stride=stride, 42 | padding=(kernel_size - 1) // 2 \ 43 | if dilation == 1 else dilation, 44 | dilation=dilation, 45 | groups=groups, 46 | bias_attr=False, 47 | data_format=data_format) 48 | 49 | self._batch_norm = layers.SyncBatchNorm( 50 | out_channels, data_format=data_format) 51 | self._act_op = layers.Activation(act=act) 52 | 53 | def forward(self, inputs): 54 | if self.is_vd_mode: 55 | inputs = self._pool2d_avg(inputs) 56 | y = self._conv(inputs) 57 | y = self._batch_norm(y) 58 | y = self._act_op(y) 59 | 60 | return y 61 | 62 | 63 | class ClsHead(nn.Layer): 64 | def __init__(self, embedding_size, class_num, **kwargs): 65 | super(ClsHead, self).__init__() 66 | self.embedding_size = embedding_size 67 | self.class_num = class_num 68 | 69 | self.avg_pool = AdaptiveAvgPool2D(1, data_format="NCHW") 70 | 71 | self.conv16_32 = ConvBNLayer(self.embedding_size, self.embedding_size, 3, 2, 1, act="relu") 72 | 73 | self.conv1 = ConvBNLayer(self.embedding_size * 2, self.embedding_size * 2, 3, 1, 1, act="relu") 74 | self.conv2 = ConvBNLayer(self.embedding_size * 2, self.embedding_size * 2, 3, 1, 1, act="relu") 75 | 76 | self.fc1 = nn.Linear(self.embedding_size * 2, self.embedding_size) 77 | self.fc2 = nn.Linear(self.embedding_size, self.class_num) 78 | self.flatten = nn.Flatten() 79 | 80 | self.cbam = CBAM_Module(self.embedding_size * 2) 81 | 82 | def forward(self, inputs, targets=None): 83 | if isinstance(inputs, list): 84 | inputs = inputs[0][2:4] # 0-transformer 1-cnn 85 | else: 86 | inputs = inputs[1] 87 | gt_labels = targets['targets'] 88 | 89 | feature16 = inputs[0] 90 | feature32 = inputs[1] 91 | feature16_32 = self.conv16_32(feature16) 92 | features = paddle.concat([feature16_32, feature32], axis=1) 93 | 94 | input = self.conv1(features) 95 | input = self.conv2(input) 96 | 97 | input = self.cbam(input) 98 | 99 | inputs = self.avg_pool(input) 100 | inputs = self.flatten(inputs) 101 | outputs = self.fc2(self.fc1(inputs)) 102 | if self.training: 103 | return self.get_loss(outputs, gt_labels) 104 | else: 105 | return outputs 106 | 107 | def get_loss(self, outputs, gt_labels): 108 | """ 109 | Compute loss from modeling's outputs, the loss function input arguments 110 | must be the same as the outputs of the model forwarding. 111 | """ 112 | loss_dict = {} 113 | loss_dict['loss_ce_cls'] = cross_entropy_loss( 114 | outputs, 115 | gt_labels, 116 | 0.1 117 | ) 118 | 119 | return loss_dict -------------------------------------------------------------------------------- /OneForAll/modeling/heads/detr.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | import paddle 15 | import paddle.nn as nn 16 | import paddle.nn.functional as F 17 | 18 | 19 | class DETR(nn.Layer): 20 | """d 21 | """ 22 | def __init__(self, transformer, detr_head, post_process, exclude_post_process=False): 23 | super().__init__() 24 | 25 | self.transformer = transformer 26 | self.detr_head = detr_head 27 | self.post_process = post_process 28 | self.exclude_post_process = exclude_post_process 29 | self.start = 0 30 | 31 | def forward(self, body_feats, inputs): 32 | """d""" 33 | # body_feats = self.backbone(inputs) 34 | # if self.start == 0: 35 | # self.transformer.set_state_dict(paddle.load('self.transformer.pddet.pdparams')) 36 | # self.start += 1 37 | if isinstance(body_feats, list): 38 | body_feats = body_feats[0] 39 | else: 40 | body_feats = body_feats 41 | # Transformer 42 | if 'gt_bbox' in inputs: 43 | #hard code 44 | gt_bbox = [paddle.cast(inputs['gt_bbox'][i], 'float32') for i in range(len(inputs['gt_bbox']))] 45 | inputs['gt_bbox'] = gt_bbox 46 | pad_mask = inputs['pad_mask'] if self.training else None 47 | out_transformer = self.transformer(body_feats, pad_mask, inputs) 48 | # 49 | # out_transformer = paddle.load('out_transformer.pddata') 50 | # body_feats = paddle.load('body_feats.pddata') 51 | # inputs = paddle.load('inputs.pddata') 52 | # d = self.detr_head(out_transformer, body_feats, inputs) 53 | # self.transformer.eval() 54 | # with paddle.no_grad(): 55 | # e1 = self.transformer(body_feats, inputs['pad_mask'], inputs) 56 | # e2 = self.transformer(body_feats, inputs['pad_mask'], inputs) 57 | # paddle.save(self.transformer.state_dict(), 'self.transformer.pdparams') 58 | # with paddle.no_grad(): 59 | # e1 = self.transformer._get_encoder_input(body_feats, inputs['pad_mask']) 60 | # e2 = self.transformer._get_encoder_input(body_feats, inputs['pad_mask']) 61 | # with paddle.no_grad(): 62 | # m1 = self.transformer.encoder(*e1) 63 | # m2 = self.transformer.encoder(*e2) 64 | # DETR Head 65 | if self.training: 66 | losses = self.detr_head(out_transformer, body_feats, inputs) 67 | new_losses = {} 68 | new_losses.update({ 69 | 'loss': 70 | paddle.add_n([v for k, v in losses.items() if 'log' not in k]) 71 | }) 72 | return new_losses 73 | else: 74 | preds = self.detr_head(out_transformer, body_feats) 75 | if self.exclude_post_process: 76 | bboxes, logits, masks = preds 77 | bbox_pred, bbox_num = bboxes, logits 78 | else: 79 | bbox, bbox_num = self.post_process( 80 | preds, inputs['im_shape'], inputs['scale_factor']) 81 | bbox_pred, bbox_num = bbox, bbox_num 82 | 83 | output = { 84 | "bbox": bbox_pred, 85 | "bbox_num": bbox_num, 86 | } 87 | return output -------------------------------------------------------------------------------- /OneForAll/modeling/heads/faster_rcnn.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | import paddle 15 | import paddle.nn as nn 16 | import paddle.nn.functional as F 17 | import pycocotools.mask as mask_util 18 | from modeling.initializer import linear_init_, constant_ 19 | 20 | 21 | class FasterRCNNHead(nn.Layer): 22 | """ 23 | """ 24 | def __init__(self, neck, rpn_head, bbox_head, bbox_post_process): 25 | super().__init__() 26 | self.neck=neck 27 | self.rpn_head = rpn_head 28 | self.bbox_head = bbox_head 29 | self.bbox_post_process = bbox_post_process 30 | 31 | def forward(self, body_feats, inputs): 32 | body_feats = self.neck(body_feats) 33 | if 'gt_bbox' in inputs: 34 | #hard code 35 | gt_bbox = [paddle.cast(inputs['gt_bbox'][i], 'float32') for i in range(len(inputs['gt_bbox']))] 36 | inputs['gt_bbox'] = gt_bbox 37 | if self.training: 38 | rois, rois_num, rpn_loss = self.rpn_head(body_feats, inputs) 39 | bbox_loss, _ = self.bbox_head(body_feats, rois, rois_num, 40 | inputs) 41 | loss = {} 42 | loss.update(rpn_loss) 43 | loss.update(bbox_loss) 44 | total_loss = paddle.add_n(list(loss.values())) 45 | loss.update({'loss': total_loss}) 46 | return loss 47 | 48 | else: 49 | rois, rois_num, _ = self.rpn_head(body_feats, inputs) 50 | preds, _ = self.bbox_head(body_feats, rois, rois_num, None) 51 | 52 | im_shape = inputs['im_shape'] 53 | scale_factor = inputs['scale_factor'] 54 | bbox, bbox_num = self.bbox_post_process(preds, (rois, rois_num), 55 | im_shape, scale_factor) 56 | 57 | # rescale the prediction back to origin image 58 | bboxes, bbox_pred, bbox_num = self.bbox_post_process.get_pred( 59 | bbox, bbox_num, im_shape, scale_factor) 60 | output = {'bbox': bbox_pred, 'bbox_num': bbox_num} 61 | return output -------------------------------------------------------------------------------- /OneForAll/modeling/heads/seg_dmnet_head.py: -------------------------------------------------------------------------------- 1 | import paddle 2 | import paddle.nn as nn 3 | import paddle.nn.functional as F 4 | 5 | from paddleseg.cvlibs import manager 6 | from paddleseg.models import layers 7 | from paddleseg.utils import utils 8 | 9 | 10 | class DMNetV2(nn.Layer): 11 | """ 12 | The DMNet implementation based on PaddlePaddle. 13 | 14 | The original article refers to 15 | Junjun He, Zhongying Deng, Yu Qiao. "Dynamic Multi-scale Filters for Semantic Segmentation" 16 | 17 | Args: 18 | num_classes (int): The unique number of target classes. 19 | backbone (paddle.nn.Layer): Backbone network, currently support Resnet50_vd/Resnet101_vd. 20 | mid_channels (int): The middle channels of convolution layer. Default: 512. 21 | filter_sizes (list, tuple): The filter size of generated convolution kernel used in Dynamic Convolutional Module. Default: [1, 3, 5, 7]. 22 | fusion (bool): Add one conv to fuse DCM output feature. Default: False. 23 | pretrained (str, optional): The path or url of pretrained model. Default: None. 24 | """ 25 | 26 | def __init__(self, 27 | num_classes, 28 | backbone_dim=768, 29 | mid_channels=512, 30 | filter_sizes=[1, 3, 5, 7], 31 | backbone_layeer=50, 32 | num_filters = [64, 128, 256, 512], 33 | fusion=False, 34 | loss="SegDMNetLoss",): 35 | super().__init__() 36 | self.backbone_dim = backbone_dim 37 | self.loss = loss 38 | self.dcm_modules = nn.LayerList() 39 | self.feat_channels = [c * 4 for c in num_filters 40 | ] if backbone_layeer >= 50 else num_filters 41 | for filter_size in filter_sizes: 42 | self.dcm_modules.append( 43 | DCM(filter_size, fusion, self.feat_channels[-1], 44 | mid_channels), ) 45 | self.bottleneck = layers.ConvBNReLU( 46 | self.feat_channels[-1] + len(filter_sizes) * mid_channels, 47 | mid_channels, 48 | 3, 49 | padding=1, ) 50 | self.cls = nn.Conv2D(mid_channels, num_classes, 1) 51 | 52 | self.fcn_head = nn.Sequential( 53 | layers.ConvBNReLU( 54 | self.backbone_dim + 256*4, mid_channels, 3, padding=1), 55 | nn.Conv2D(mid_channels, num_classes, 1), ) # self.feat_channels[2] 56 | 57 | def forward(self, x, target=None): 58 | feats = x[1] 59 | trans_feats = x[0] 60 | x = feats[-1] 61 | dcm_outs = [x] 62 | for dcm_module in self.dcm_modules: 63 | dcm_outs.append(dcm_module(x)) 64 | dcm_outs = paddle.concat(dcm_outs, axis=1) 65 | x = self.bottleneck(dcm_outs) 66 | x = self.cls(x) 67 | x = F.interpolate( 68 | x, scale_factor=8, mode='bilinear', align_corners=True) 69 | output = [x] 70 | if self.training: 71 | trans_cnn_feat = paddle.concat([feats[2], trans_feats[1]], axis=1) 72 | # fcn_out = self.fcn_head(feats[2]) 73 | fcn_out = self.fcn_head(trans_cnn_feat) 74 | fcn_out = F.interpolate( 75 | fcn_out, scale_factor=8, mode='bilinear', align_corners=True) 76 | output.append(fcn_out) 77 | 78 | labels = target['label'].astype('int64') 79 | 80 | loss = dict() 81 | seg_loss = self.loss(output, labels) 82 | loss['dmnetloss'] = seg_loss 83 | 84 | return loss 85 | 86 | return output 87 | 88 | 89 | class DCM(nn.Layer): 90 | """ 91 | Dynamic Convolutional Module used in DMNet. 92 | 93 | Args: 94 | filter_size (int): The filter size of generated convolution kernel used in Dynamic Convolutional Module. 95 | fusion (bool): Add one conv to fuse DCM output feature. 96 | in_channels (int): Input channels. 97 | channels (int): Channels after modules, before conv_seg. 98 | """ 99 | 100 | def __init__(self, filter_size, fusion, in_channels, channels): 101 | super().__init__() 102 | self.filter_size = filter_size 103 | self.fusion = fusion 104 | self.channels = channels 105 | 106 | pad = (self.filter_size - 1) // 2 107 | if (self.filter_size - 1) % 2 == 0: 108 | self.pad = (pad, pad, pad, pad) 109 | else: 110 | self.pad = (pad + 1, pad, pad + 1, pad) 111 | 112 | self.avg_pool = nn.AdaptiveAvgPool2D(filter_size) 113 | self.filter_gen_conv = nn.Conv2D(in_channels, channels, 1) 114 | self.input_redu_conv = layers.ConvBNReLU(in_channels, channels, 1) 115 | 116 | self.norm = layers.SyncBatchNorm(channels) 117 | self.act = nn.ReLU() 118 | 119 | if self.fusion: 120 | self.fusion_conv = layers.ConvBNReLU(channels, channels, 1) 121 | 122 | def forward(self, x): 123 | generated_filter = self.filter_gen_conv(self.avg_pool(x)) 124 | x = self.input_redu_conv(x) 125 | b, c, h, w = x.shape 126 | assert b > 0, "The batch size of x need to be bigger than 0, but got {}.".format( 127 | b) 128 | x = paddle.unsqueeze( 129 | paddle.flatten( 130 | x, start_axis=0, stop_axis=1), axis=0) 131 | generated_filter = generated_filter.reshape( 132 | [b * c, 1, self.filter_size, self.filter_size]) 133 | 134 | x = F.pad(x, self.pad, mode='constant', value=0) 135 | output = F.conv2d(x, weight=generated_filter, groups=b * c) 136 | output = output.reshape([b, self.channels, h, w]) 137 | output = self.norm(output) 138 | output = self.act(output) 139 | if self.fusion: 140 | output = self.fusion_conv(output) 141 | return output -------------------------------------------------------------------------------- /OneForAll/modeling/heads/simple_cls_head.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | from __future__ import division 3 | from __future__ import print_function 4 | 5 | import paddle.nn as nn 6 | from paddle.nn import AdaptiveAvgPool2D 7 | from modeling.losses import cross_entropy_loss 8 | 9 | 10 | __all__ = ['ClsHead'] 11 | 12 | class ClsHead(nn.Layer): 13 | def __init__(self, embedding_size, class_num, **kwargs): 14 | super(ClsHead, self).__init__() 15 | self.embedding_size = embedding_size 16 | self.class_num = class_num 17 | 18 | self.avg_pool = AdaptiveAvgPool2D(1, data_format="NCHW") 19 | 20 | self.fc1 = nn.Linear(self.embedding_size, self.embedding_size // 2) 21 | self.fc2 = nn.Linear(self.embedding_size // 2, self.class_num) 22 | self.flatten = nn.Flatten() 23 | 24 | def forward(self, feats, inputs=None): 25 | 26 | if isinstance(feats, list): 27 | feats = feats[0][-2] 28 | 29 | out = self.avg_pool(feats) 30 | out = self.flatten(out) 31 | out = self.fc2(self.fc1(out)) 32 | 33 | if self.training: 34 | return self.get_loss(out, inputs['targets']) 35 | else: 36 | return out 37 | 38 | def get_loss(self, outputs, gt_labels): 39 | """ 40 | Compute loss from modeling's outputs, the loss function input arguments 41 | must be the same as the outputs of the model forwarding. 42 | """ 43 | loss_dict = {} 44 | loss_dict['loss_ce_cls'] = cross_entropy_loss( 45 | outputs, 46 | gt_labels, 47 | 0.1 48 | ) 49 | 50 | return loss_dict -------------------------------------------------------------------------------- /OneForAll/modeling/heads/yolov3.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | import paddle 15 | import paddle.nn as nn 16 | import paddle.nn.functional as F 17 | import pycocotools.mask as mask_util 18 | from ppdet.modeling.post_process import JDEBBoxPostProcess 19 | 20 | class YOLOv3(nn.Layer): 21 | """ 22 | """ 23 | def __init__(self, neck, yolo_head, post_process, for_mot=False): 24 | super().__init__() 25 | self.neck = neck 26 | self.yolo_head = yolo_head 27 | self.post_process = post_process 28 | self.for_mot = for_mot 29 | self.return_idx = isinstance(post_process, JDEBBoxPostProcess) 30 | 31 | def forward(self, body_feats, inputs): 32 | neck_feats = self.neck(body_feats, self.for_mot) 33 | 34 | if isinstance(neck_feats, dict): 35 | assert self.for_mot == True 36 | emb_feats = neck_feats['emb_feats'] 37 | neck_feats = neck_feats['yolo_feats'] 38 | 39 | if self.training: 40 | yolo_losses = self.yolo_head(neck_feats, inputs) 41 | 42 | if self.for_mot: 43 | return {'det_losses': yolo_losses, 'emb_feats': emb_feats} 44 | else: 45 | return yolo_losses 46 | 47 | else: 48 | yolo_head_outs = self.yolo_head(neck_feats) 49 | 50 | if self.for_mot: 51 | boxes_idx, bbox, bbox_num, nms_keep_idx = self.post_process( 52 | yolo_head_outs, self.yolo_head.mask_anchors) 53 | output = { 54 | 'bbox': bbox, 55 | 'bbox_num': bbox_num, 56 | 'boxes_idx': boxes_idx, 57 | 'nms_keep_idx': nms_keep_idx, 58 | 'emb_feats': emb_feats, 59 | } 60 | else: 61 | if self.return_idx: 62 | _, bbox, bbox_num, _ = self.post_process( 63 | yolo_head_outs, self.yolo_head.mask_anchors) 64 | elif self.post_process is not None: 65 | bbox, bbox_num = self.post_process( 66 | yolo_head_outs, self.yolo_head.mask_anchors, 67 | inputs['im_shape'], inputs['scale_factor']) 68 | else: 69 | bbox, bbox_num = self.yolo_head.post_process( 70 | yolo_head_outs, inputs['im_shape'], 71 | inputs['scale_factor']) 72 | output = {'bbox': bbox, 'bbox_num': bbox_num} 73 | 74 | return output -------------------------------------------------------------------------------- /OneForAll/modeling/losses/__init__.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | """ 3 | @author: l1aoxingyu 4 | @contact: sherlockliao01@gmail.com 5 | """ 6 | 7 | # from .circle_loss import * 8 | from .cross_entroy_loss import cross_entropy_loss, log_accuracy 9 | # from .focal_loss import focal_loss 10 | from .triplet_loss import triplet_loss 11 | 12 | __all__ = [k for k in globals().keys() if not k.startswith("_")] -------------------------------------------------------------------------------- /OneForAll/modeling/losses/cross_entroy_loss.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | import paddle 3 | import paddle.nn.functional as F 4 | 5 | from detectron2.utils.events import EventStorage, get_event_storage 6 | from utils import comm 7 | 8 | 9 | def log_accuracy(pred_class_logits, gt_classes, topk=(1,)): 10 | """ 11 | Log the accuracy metrics to EventStorage. 12 | """ 13 | bsz = pred_class_logits.shape[0] 14 | maxk = max(topk) 15 | _, pred_class = pred_class_logits.topk(maxk, 1, True, True) 16 | pred_class = pred_class.t() 17 | correct = pred_class.equal(gt_classes.reshape((1, -1)).expand_as(pred_class)) 18 | 19 | ret = [] 20 | for k in topk: 21 | correct_k = paddle.cast(correct[:k].reshape((-1,)), 'float32').sum(axis=0, keepdim=True) 22 | ret.append(correct_k * (1. / bsz)) 23 | 24 | if comm.is_main_process(): 25 | storage = get_event_storage() 26 | storage.put_scalar("cls_accuracy", ret[0]) 27 | return ret[0] 28 | 29 | 30 | def cross_entropy_loss(pred_class_outputs, gt_classes, eps, alpha=0.2): 31 | """ 32 | pred_class_outputs 33 | gt_classes 34 | eps 35 | """ 36 | num_classes = pred_class_outputs.shape[1] 37 | 38 | if eps >= 0: 39 | smooth_param = eps 40 | else: 41 | # Adaptive label smooth regularization 42 | soft_label = F.softmax(pred_class_outputs, axis=1) 43 | smooth_param = alpha * soft_label[paddle.arange(soft_label.shape[0]), gt_classes].unsqueeze(1) 44 | 45 | log_probs = F.log_softmax(pred_class_outputs, axis=1) 46 | if len(gt_classes.shape) == 1: 47 | with paddle.no_grad(): 48 | origin_value = paddle.ones_like(log_probs, dtype='float32') 49 | origin_value *= smooth_param / (num_classes - 1) 50 | new_value = paddle.ones_like(log_probs, dtype='float32') 51 | new_value *= (1 - smooth_param) 52 | o = gt_classes.unsqueeze(-1).tile((1, pred_class_outputs.shape[1])) 53 | k = paddle.arange(pred_class_outputs.shape[1]).unsqueeze(0).expand_as(o) 54 | targets = paddle.where(o == k, new_value, origin_value) 55 | else: 56 | targets = gt_classes 57 | # targets = 58 | targets = paddle.cast(targets, log_probs.dtype) 59 | loss = (-1 * targets * log_probs).sum(axis=1) 60 | 61 | with paddle.no_grad(): 62 | non_zero_cnt = max(loss.nonzero(as_tuple=False).shape[0], 1) 63 | 64 | loss = loss.sum() / non_zero_cnt 65 | 66 | return loss 67 | -------------------------------------------------------------------------------- /OneForAll/modeling/losses/triplet_loss.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | """ 3 | @author: liaoxingyu 4 | @contact: sherlockliao01@gmail.com 5 | """ 6 | 7 | import paddle 8 | import paddle.nn.functional as F 9 | 10 | from .utils import euclidean_dist, cosine_dist 11 | 12 | 13 | def softmax_weights(dist, mask): 14 | """ 15 | dist 16 | mask 17 | """ 18 | max_v = paddle.max(dist * mask, axis=1, keepdim=True)[0] 19 | diff = dist - max_v 20 | Z = paddle.sum(paddle.exp(diff) * mask, axis=1, keepdim=True) + 1e-6 # avoid division by zero 21 | W = paddle.exp(diff) * mask / Z 22 | return W 23 | 24 | 25 | def hard_example_mining(dist_mat, is_pos, is_neg): 26 | """For each anchor, find the hardest positive and negative sample. 27 | Args: 28 | dist_mat: pair wise distance between samples, shape [N, M] 29 | is_pos: positive index with shape [N, M] 30 | is_neg: negative index with shape [N, M] 31 | Returns: 32 | dist_ap: a tensor, distance(anchor, positive); shape [N] 33 | dist_an: a tensor, distance(anchor, negative); shape [N] 34 | p_inds: a tensor, with shape [N]; 35 | indices of selected hard positive samples; 0 <= p_inds[i] <= N - 1 36 | n_inds: a tensor, with shape [N]; 37 | indices of selected hard negative samples; 0 <= n_inds[i] <= N - 1 38 | NOTE: Only consider the case in which all labels have same num of samples, 39 | thus we can cope with all anchors in parallel. 40 | """ 41 | 42 | assert len(dist_mat.shape) == 2 43 | 44 | # `dist_ap` means distance(anchor, positive) 45 | # both `dist_ap` and `relative_p_inds` with shape [N] 46 | dist_ap = paddle.max(dist_mat * is_pos, axis=1) 47 | # `dist_an` means distance(anchor, negative) 48 | # both `dist_an` and `relative_n_inds` with shape [N] 49 | dist_an = paddle.min(dist_mat * is_neg + is_pos * 1e9, axis=1) 50 | 51 | return dist_ap, dist_an 52 | 53 | 54 | def weighted_example_mining(dist_mat, is_pos, is_neg): 55 | """For each anchor, find the weighted positive and negative sample. 56 | Args: 57 | dist_mat: a tensor, pair wise distance between samples, shape [N, N] 58 | is_pos: 59 | is_neg: 60 | Returns: 61 | dist_ap: a tensor, distance(anchor, positive); shape [N] 62 | dist_an: a tensor, distance(anchor, negative); shape [N] 63 | """ 64 | assert len(dist_mat.size()) == 2 65 | 66 | is_pos = is_pos 67 | is_neg = is_neg 68 | dist_ap = dist_mat * is_pos 69 | dist_an = dist_mat * is_neg 70 | 71 | weights_ap = softmax_weights(dist_ap, is_pos) 72 | weights_an = softmax_weights(-dist_an, is_neg) 73 | 74 | dist_ap = paddle.sum(dist_ap * weights_ap, axis=1) 75 | dist_an = paddle.sum(dist_an * weights_an, axis=1) 76 | 77 | return dist_ap, dist_an 78 | 79 | 80 | def soft_margin_loss(x, y): 81 | """ 82 | Args: 83 | x: shape [N] 84 | y: shape [N] 85 | """ 86 | return paddle.sum(paddle.log(1 + paddle.exp(-1 * x * y))) / x.numel() 87 | 88 | 89 | def triplet_loss(embedding, targets, margin, norm_feat, hard_mining): 90 | r"""Modified from Tong Xiao's open-reid (https://github.com/Cysu/open-reid). 91 | Related Triplet Loss theory can be found in paper 'In Defense of the Triplet 92 | Loss for Person Re-Identification'.""" 93 | 94 | if norm_feat: 95 | dist_mat = cosine_dist(embedding, embedding) 96 | else: 97 | dist_mat = euclidean_dist(embedding, embedding) 98 | 99 | #TODO For distributed training, gather all features from different process. 100 | # if comm.get_world_size() > 1: 101 | # pass 102 | # else: 103 | # pass 104 | 105 | N = dist_mat.shape[0] 106 | is_pos = paddle.cast( 107 | targets.reshape((N, 1)).expand((N, N)).equal(targets.reshape((N, 1)).expand((N, N)).t()), 108 | embedding.dtype) 109 | is_neg = paddle.cast( 110 | targets.reshape((N, 1)).expand((N, N)).not_equal(targets.reshape((N, 1)).expand((N, N)).t()), 111 | embedding.dtype) 112 | 113 | if hard_mining: 114 | dist_ap, dist_an = hard_example_mining(dist_mat, is_pos, is_neg) 115 | else: 116 | dist_ap, dist_an = weighted_example_mining(dist_mat, is_pos, is_neg) 117 | 118 | # y = dist_an.new().resize_as_(dist_an).fill_(1) 119 | y = paddle.ones_like(dist_an) 120 | 121 | if margin > 0: 122 | loss = F.margin_ranking_loss(dist_an, dist_ap, y, margin=margin) 123 | else: 124 | loss = soft_margin_loss(dist_an - dist_ap, y) 125 | # fmt: off 126 | if loss == float('Inf'): loss = F.margin_ranking_loss(dist_an, dist_ap, y, margin=0.3) 127 | # fmt: on 128 | 129 | return loss 130 | -------------------------------------------------------------------------------- /OneForAll/modeling/losses/utils.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | """ 3 | @author: xingyu liao 4 | @contact: sherlockliao01@gmail.com 5 | """ 6 | 7 | import paddle 8 | import paddle.nn.functional as F 9 | 10 | def euclidean_dist(x, y): 11 | """euclidean_dist 12 | """ 13 | m, n = x.shape[0], y.shape[0] 14 | xx = paddle.pow(x, 2).sum(1, keepdim=True).expand((m, n)) 15 | yy = paddle.pow(y, 2).sum(1, keepdim=True).expand((n, m)).t() 16 | dist = xx + yy - 2 * paddle.matmul(x, y.t()) 17 | dist = dist.clip(min=1e-12).sqrt() # for numerical stability 18 | return dist 19 | 20 | def cosine_dist(x, y): 21 | """cosine_dist 22 | """ 23 | x = F.normalize(x, axis=1) 24 | y = F.normalize(y, axis=1) 25 | dist = 2 - 2 * paddle.matmul(x, y.t()) 26 | return dist 27 | -------------------------------------------------------------------------------- /OneForAll/modeling/meta_arch/multitask_v2.py: -------------------------------------------------------------------------------- 1 | # !/usr/bin/env python3 2 | # Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License" 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | import random 17 | 18 | import paddle 19 | from paddle import nn 20 | 21 | from modeling.losses import triplet_loss, cross_entropy_loss, log_accuracy 22 | 23 | class MultiTaskBatchFuse(nn.Layer): 24 | """ 25 | Baseline architecture. Any models that contains the following two components: 26 | 1. Per-image feature extraction (aka backbone) 27 | 2. Per-image feature aggregation and loss computation 28 | """ 29 | 30 | def __init__( 31 | self, 32 | backbone, 33 | heads, 34 | pixel_mean, 35 | pixel_std, 36 | task_loss_kwargs=None, 37 | task2head_mapping=None, 38 | **kwargs, 39 | ): 40 | """ 41 | NOTE: this interface is experimental. 42 | 43 | Args: 44 | backbone: 45 | heads: 46 | pixel_mean: 47 | pixel_std: 48 | """ 49 | super().__init__() 50 | # backbone 51 | self.backbone = backbone 52 | 53 | # head 54 | # use nn.LayerDict to ensure head modules are properly registered 55 | self.heads = nn.LayerDict(heads) 56 | 57 | if task2head_mapping is None: 58 | task2head_mapping = {} 59 | for key in self.heads: 60 | task2head_mapping[key] = key 61 | self.task2head_mapping = task2head_mapping 62 | 63 | self.task_loss_kwargs = task_loss_kwargs 64 | 65 | self.register_buffer('pixel_mean', paddle.to_tensor(list(pixel_mean)).reshape((1, -1, 1, 1)), False) 66 | self.register_buffer('pixel_std', paddle.to_tensor(list(pixel_std)).reshape((1, -1, 1, 1)), False) 67 | 68 | @property 69 | def device(self): 70 | """ 71 | Get device information 72 | """ 73 | return self.pixel_mean.device 74 | 75 | def forward(self, task_batched_inputs): 76 | """ 77 | NOTE: this forward function only supports `self.training is False` 78 | """ 79 | # fuse batch 80 | img_list = [] 81 | task_data_idx = {} 82 | start = 0 83 | # for task_name, batched_inputs in task_batched_inputs.items(): 84 | # images = self.preprocess_image(batched_inputs) 85 | # img_list.append(images) 86 | 87 | # end = start + images.shape[0] 88 | # task_data_idx[task_name] = (start, end) 89 | # start = end 90 | # all_imgs = paddle.concat(img_list, axis=0) 91 | # all_features = self.backbone(all_imgs) 92 | 93 | # assert not self.training 94 | losses = {} 95 | outputs = {} 96 | for task_name, batched_inputs in task_batched_inputs.items(): 97 | # start, end = task_data_idx[task_name] 98 | # features = all_features[start:end, ...] 99 | features = self.backbone(self.preprocess_image(batched_inputs)) 100 | 101 | if self.training: 102 | # assert "targets" in batched_inputs, "Person ID annotation are missing in training!" 103 | # targets = batched_inputs["targets"] 104 | 105 | # PreciseBN flag, When do preciseBN on different dataset, the number of classes in new dataset 106 | # may be larger than that in the original dataset, so the circle/arcface will 107 | # throw an error. We just set all the targets to 0 to avoid this problem. 108 | # if targets.sum() < 0: targets.zero_() 109 | 110 | task_outputs = self.heads[self.task2head_mapping[task_name]](features, batched_inputs) 111 | losses.update(**{task_name + "_" + key: val for key, val in task_outputs.items()}) 112 | else: 113 | task_outputs = self.heads[self.task2head_mapping[task_name]](features, batched_inputs) 114 | outputs[task_name] = task_outputs 115 | 116 | if self.training: 117 | return losses 118 | else: 119 | return outputs 120 | 121 | def preprocess_image(self, batched_inputs): 122 | """ 123 | Normalize and batch the input images. 124 | """ 125 | if isinstance(batched_inputs, dict): 126 | if 'image' in batched_inputs: 127 | images = batched_inputs['image'] 128 | if 'images' in batched_inputs: 129 | images = batched_inputs['images'] 130 | elif isinstance(batched_inputs, paddle.Tensor): 131 | images = batched_inputs 132 | else: 133 | raise TypeError("batched_inputs must be dict or Tensor, but get {}".format(type(batched_inputs))) 134 | 135 | # images.sub_(self.pixel_mean).div_(self.pixel_std) 136 | return {'image': images} 137 | -------------------------------------------------------------------------------- /OneForAll/modeling/post_process.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import numpy as np 16 | import paddle 17 | import paddle.nn as nn 18 | import paddle.nn.functional as F 19 | 20 | from modeling.bbox_utils import bbox_cxcywh_to_xyxy 21 | 22 | 23 | class DETRBBoxPostProcess(object): 24 | def __init__(self, 25 | num_classes=80, 26 | num_top_queries=100, 27 | use_focal_loss=False): 28 | super(DETRBBoxPostProcess, self).__init__() 29 | self.num_classes = num_classes 30 | self.num_top_queries = num_top_queries 31 | self.use_focal_loss = use_focal_loss 32 | 33 | def __call__(self, head_out, im_shape, scale_factor): 34 | """ 35 | Decode the bbox. 36 | 37 | Args: 38 | head_out (tuple): bbox_pred, cls_logit and masks of bbox_head output. 39 | im_shape (Tensor): The shape of the input image. 40 | scale_factor (Tensor): The scale factor of the input image. 41 | Returns: 42 | bbox_pred (Tensor): The output prediction with shape [N, 6], including 43 | labels, scores and bboxes. The size of bboxes are corresponding 44 | to the input image, the bboxes may be used in other branch. 45 | bbox_num (Tensor): The number of prediction boxes of each batch with 46 | shape [bs], and is N. 47 | """ 48 | bboxes, logits, masks = head_out 49 | 50 | bbox_pred = bbox_cxcywh_to_xyxy(bboxes) 51 | origin_shape = paddle.floor(im_shape / scale_factor + 0.5) 52 | img_h, img_w = origin_shape.unbind(1) 53 | origin_shape = paddle.stack( 54 | [img_w, img_h, img_w, img_h], axis=-1).unsqueeze(0) 55 | bbox_pred *= origin_shape 56 | 57 | scores = F.sigmoid(logits) if self.use_focal_loss else F.softmax( 58 | logits)[:, :, :-1] 59 | 60 | if not self.use_focal_loss: 61 | scores, labels = scores.max(-1), scores.argmax(-1) 62 | if scores.shape[1] > self.num_top_queries: 63 | scores, index = paddle.topk( 64 | scores, self.num_top_queries, axis=-1) 65 | labels = paddle.stack( 66 | [paddle.gather(l, i) for l, i in zip(labels, index)]) 67 | bbox_pred = paddle.stack( 68 | [paddle.gather(b, i) for b, i in zip(bbox_pred, index)]) 69 | else: 70 | scores, index = paddle.topk( 71 | scores.reshape([logits.shape[0], -1]), 72 | self.num_top_queries, 73 | axis=-1) 74 | labels = index % logits.shape[2] 75 | index = index // logits.shape[2] 76 | bbox_pred = paddle.stack( 77 | [paddle.gather(b, i) for b, i in zip(bbox_pred, index)]) 78 | 79 | bbox_pred = paddle.concat( 80 | [ 81 | labels.unsqueeze(-1).astype('float32'), scores.unsqueeze(-1), 82 | bbox_pred 83 | ], 84 | axis=-1) 85 | bbox_num = paddle.to_tensor( 86 | bbox_pred.shape[1], dtype='int32').tile([bbox_pred.shape[0]]) 87 | bbox_pred = bbox_pred.reshape([-1, 6]) 88 | return bbox_pred, bbox_num 89 | 90 | 91 | def nms(dets, thresh): 92 | """Apply classic DPM-style greedy NMS.""" 93 | if dets.shape[0] == 0: 94 | return dets[[], :] 95 | scores = dets[:, 0] 96 | x1 = dets[:, 1] 97 | y1 = dets[:, 2] 98 | x2 = dets[:, 3] 99 | y2 = dets[:, 4] 100 | 101 | areas = (x2 - x1 + 1) * (y2 - y1 + 1) 102 | order = scores.argsort()[::-1] 103 | 104 | ndets = dets.shape[0] 105 | suppressed = np.zeros((ndets), dtype=np.int) 106 | 107 | # nominal indices 108 | # _i, _j 109 | # sorted indices 110 | # i, j 111 | # temp variables for box i's (the box currently under consideration) 112 | # ix1, iy1, ix2, iy2, iarea 113 | 114 | # variables for computing overlap with box j (lower scoring box) 115 | # xx1, yy1, xx2, yy2 116 | # w, h 117 | # inter, ovr 118 | 119 | for _i in range(ndets): 120 | i = order[_i] 121 | if suppressed[i] == 1: 122 | continue 123 | ix1 = x1[i] 124 | iy1 = y1[i] 125 | ix2 = x2[i] 126 | iy2 = y2[i] 127 | iarea = areas[i] 128 | for _j in range(_i + 1, ndets): 129 | j = order[_j] 130 | if suppressed[j] == 1: 131 | continue 132 | xx1 = max(ix1, x1[j]) 133 | yy1 = max(iy1, y1[j]) 134 | xx2 = min(ix2, x2[j]) 135 | yy2 = min(iy2, y2[j]) 136 | w = max(0.0, xx2 - xx1 + 1) 137 | h = max(0.0, yy2 - yy1 + 1) 138 | inter = w * h 139 | ovr = inter / (iarea + areas[j] - inter) 140 | if ovr >= thresh: 141 | suppressed[j] = 1 142 | keep = np.where(suppressed == 0)[0] 143 | dets = dets[keep, :] 144 | return dets -------------------------------------------------------------------------------- /OneForAll/modeling/transformers/position_encoding.py: -------------------------------------------------------------------------------- 1 | # !/usr/bin/env python3 2 | # Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | # Modified from DETR (https://github.com/facebookresearch/detr) 17 | # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved 18 | 19 | from __future__ import absolute_import 20 | from __future__ import division 21 | from __future__ import print_function 22 | 23 | import math 24 | import paddle 25 | import paddle.nn as nn 26 | 27 | 28 | class PositionEmbedding(nn.Layer): 29 | def __init__(self, 30 | num_pos_feats=128, 31 | temperature=10000, 32 | normalize=True, 33 | scale=None, 34 | embed_type='sine', 35 | num_embeddings=50, 36 | offset=0.): 37 | super(PositionEmbedding, self).__init__() 38 | assert embed_type in ['sine', 'learned'] 39 | 40 | self.embed_type = embed_type 41 | self.offset = offset 42 | self.eps = 1e-6 43 | if self.embed_type == 'sine': 44 | self.num_pos_feats = num_pos_feats 45 | self.temperature = temperature 46 | self.normalize = normalize 47 | if scale is not None and normalize is False: 48 | raise ValueError("normalize should be True if scale is passed") 49 | if scale is None: 50 | scale = 2 * math.pi 51 | self.scale = scale 52 | elif self.embed_type == 'learned': 53 | self.row_embed = nn.Embedding(num_embeddings, num_pos_feats) 54 | self.col_embed = nn.Embedding(num_embeddings, num_pos_feats) 55 | else: 56 | raise ValueError(f"not supported {self.embed_type}") 57 | 58 | def forward(self, mask): 59 | """ 60 | Args: 61 | mask (Tensor): [B, H, W] 62 | Returns: 63 | pos (Tensor): [B, C, H, W] 64 | """ 65 | assert mask.dtype == paddle.bool 66 | if self.embed_type == 'sine': 67 | mask = mask.astype('float32') 68 | y_embed = mask.cumsum(1, dtype='float32') 69 | x_embed = mask.cumsum(2, dtype='float32') 70 | if self.normalize: 71 | y_embed = (y_embed + self.offset) / ( 72 | y_embed[:, -1:, :] + self.eps) * self.scale 73 | x_embed = (x_embed + self.offset) / ( 74 | x_embed[:, :, -1:] + self.eps) * self.scale 75 | 76 | dim_t = 2 * (paddle.arange(self.num_pos_feats) // 77 | 2).astype('float32') 78 | dim_t = self.temperature**(dim_t / self.num_pos_feats) 79 | 80 | pos_x = x_embed.unsqueeze(-1) / dim_t 81 | pos_y = y_embed.unsqueeze(-1) / dim_t 82 | pos_x = paddle.stack( 83 | (pos_x[:, :, :, 0::2].sin(), pos_x[:, :, :, 1::2].cos()), 84 | axis=4).flatten(3) 85 | pos_y = paddle.stack( 86 | (pos_y[:, :, :, 0::2].sin(), pos_y[:, :, :, 1::2].cos()), 87 | axis=4).flatten(3) 88 | pos = paddle.concat((pos_y, pos_x), axis=3).transpose([0, 3, 1, 2]) 89 | return pos 90 | elif self.embed_type == 'learned': 91 | h, w = mask.shape[-2:] 92 | i = paddle.arange(w) 93 | j = paddle.arange(h) 94 | x_emb = self.col_embed(i) 95 | y_emb = self.row_embed(j) 96 | pos = paddle.concat( 97 | [ 98 | x_emb.unsqueeze(0).repeat(h, 1, 1), 99 | y_emb.unsqueeze(1).repeat(1, w, 1), 100 | ], 101 | axis=-1).transpose([2, 0, 1]).unsqueeze(0).tile(mask.shape[0], 102 | 1, 1, 1) 103 | return pos 104 | else: 105 | raise ValueError(f"not supported {self.embed_type}") -------------------------------------------------------------------------------- /OneForAll/requirements.txt: -------------------------------------------------------------------------------- 1 | paddlepaddle-gpu==2.3.2 2 | fvcore==0.1.5.post20220119 3 | torchvision==0.8.2 4 | cloudpickle==2.0.0 5 | omegaconf==2.1.1 6 | pycocotools==2.0.4 7 | timm==0.4.12 8 | typing_extensions==4.5.0 9 | paddleseg==2.7.0 10 | paddledet==2.6.0 11 | opencv-python==4.4.0.46 12 | hydra-core==1.1.1 13 | sacred==0.8.2 14 | tensorboard==2.5.0 15 | -------------------------------------------------------------------------------- /OneForAll/scripts/env.sh: -------------------------------------------------------------------------------- 1 | pip3 install -r requirements.txt -------------------------------------------------------------------------------- /OneForAll/scripts/test.sh: -------------------------------------------------------------------------------- 1 | export CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 2 | 3 | # kill -9 $(lsof -t /dev/nvidia*) 4 | # sleep 1s 5 | # kill -9 $(lsof -t /dev/nvidia*) 6 | # sleep 1s 7 | 8 | config=configs/test_vitbase_jointtraining_config.py 9 | 10 | python3 -m paddle.distributed.launch --log_dir=./logs/vitbase_jointraining --gpus="0,1,2,3,4,5,6,7" tools/ufo_test.py --config-file ${config} --eval-only 11 | 12 | 13 | -------------------------------------------------------------------------------- /OneForAll/scripts/train.sh: -------------------------------------------------------------------------------- 1 | export CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 2 | 3 | # kill -9 $(lsof -t /dev/nvidia*) 4 | # sleep 1s 5 | # kill -9 $(lsof -t /dev/nvidia*) 6 | # sleep 1s 7 | 8 | config=configs/vitbase_jointtraining_config.py 9 | 10 | python3 -m paddle.distributed.launch --log_dir=./logs/vitbase_jointraining --gpus="0,1,2,3,4,5,6,7" tools/ufo_train.py --config-file ${config} #--resume 11 | 12 | 13 | -------------------------------------------------------------------------------- /OneForAll/solver/build.py: -------------------------------------------------------------------------------- 1 | """solve/build.py 2 | """ 3 | from typing import Optional, Dict, List, Any, Set, Type 4 | import re 5 | import copy 6 | import math 7 | 8 | import paddle 9 | 10 | 11 | def build_lr_optimizer_lazy(**kwargs): 12 | """build_lr_optimizer_lazy 13 | """ 14 | model = kwargs['model'] 15 | lr_multiplier = kwargs['lr_multiplier'] 16 | optimizer_type = kwargs.get('optimizer_type', 'SGD') 17 | momentum = kwargs.get('momentum', 0.9) 18 | weight_decay = kwargs.get('weight_decay', 1e-4) 19 | grad_clip_enabled = kwargs.get('grad_clip_enabled', True) 20 | grad_clip_norm = kwargs.get('grad_clip_norm', 5.0) 21 | apply_decay_param_fun = kwargs.get('apply_decay_param_fun', None) 22 | # grad_clip = paddle.nn.ClipGradByNorm(grad_clip_norm) if grad_clip_enabled else None 23 | grad_clip = paddle.nn.ClipGradByGlobalNorm(grad_clip_norm) if grad_clip_enabled else None 24 | 25 | if optimizer_type == 'SGD': 26 | return paddle.optimizer.Momentum( 27 | learning_rate=lr_multiplier, 28 | momentum=momentum, 29 | parameters=model.parameters(), 30 | weight_decay=weight_decay, 31 | grad_clip=grad_clip, 32 | ) 33 | elif optimizer_type == 'Adam': 34 | return paddle.optimizer.Adam( 35 | learning_rate=lr_multiplier, 36 | beta1=0.9, 37 | beta2=0.999, 38 | epsilon=1e-08, 39 | parameters=model.parameters(), 40 | weight_decay=weight_decay, 41 | grad_clip=grad_clip, 42 | name=None, 43 | lazy_mode=False, 44 | ) 45 | elif optimizer_type == 'AdamW': 46 | return paddle.optimizer.AdamW( 47 | learning_rate=lr_multiplier, 48 | beta1=0.9, beta2=0.999, 49 | epsilon=1e-08, 50 | parameters=model.parameters(), 51 | weight_decay=weight_decay, 52 | lr_ratio=None, 53 | apply_decay_param_fun=apply_decay_param_fun, 54 | grad_clip=grad_clip, 55 | lazy_mode=False, 56 | multi_precision=False, 57 | name=None, 58 | ) 59 | else: 60 | raise ValueError() 61 | 62 | 63 | def build_lr_scheduler_lazy(**kwargs): 64 | """build_lr_scheduler_lazy 65 | """ 66 | max_iters = kwargs['max_iters'] 67 | sched = kwargs['sched'] 68 | base_lr = kwargs['base_lr'] 69 | warmup_iters = kwargs.get('warmup_iters', 0) 70 | warmup_method = kwargs.get('warmup_method', 'linear') 71 | eta_min = kwargs.get('eta_min', 1e-8) 72 | solver_steps = kwargs.get('solver_steps', [20000]) 73 | solver_gamma = kwargs.get('solver_gamma', 0.1) 74 | 75 | power = kwargs.get('power', 0.9) 76 | warmup_start_lr = kwargs.get('warmup_start_lr', 1.0e-5) 77 | end_lr = kwargs.get('end_lr', 0.0) 78 | 79 | if warmup_method == 'linear' and sched == 'CosineAnnealingLR': 80 | lr_scheduler = paddle.optimizer.lr.LinearWarmup( 81 | paddle.optimizer.lr.CosineAnnealingDecay(base_lr, max_iters, eta_min), 82 | warmup_iters, 83 | 0., 84 | base_lr) 85 | elif warmup_iters == 0 and sched == 'PiecewiseDecay': 86 | lr_steps = [pow(solver_gamma, i) * base_lr for i in range(len(solver_steps) + 1)] 87 | lr_scheduler = paddle.optimizer.lr.PiecewiseDecay(boundaries=solver_steps, values=lr_steps) 88 | elif warmup_iters > 0 and sched == 'PiecewiseDecay': 89 | lr_steps = [pow(solver_gamma, i) * base_lr for i in range(len(solver_steps) + 1)] 90 | lr_scheduler = paddle.optimizer.lr.LinearWarmup( 91 | paddle.optimizer.lr.PiecewiseDecay(boundaries=solver_steps, values=lr_steps), 92 | warmup_iters, 93 | eta_min, 94 | base_lr 95 | ) 96 | elif warmup_iters > 0 and sched == 'PolynomialDecay': # add for segmentation 97 | decay_steps = max_iters - warmup_iters 98 | lr_sche = paddle.optimizer.lr.PolynomialDecay(base_lr, power=power, decay_steps=decay_steps, end_lr=0) 99 | lr_scheduler = paddle.optimizer.lr.LinearWarmup( 100 | learning_rate=lr_sche, 101 | warmup_steps=warmup_iters, 102 | start_lr=warmup_start_lr, 103 | end_lr=base_lr) 104 | else: 105 | raise ValueError("Unknown warmup and sched method : {} and {}".format(warmup_method, sched)) 106 | return lr_scheduler 107 | -------------------------------------------------------------------------------- /OneForAll/tools/eval.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import cv2 4 | import numpy as np 5 | import json 6 | import paddle 7 | from PIL import Image 8 | from evaluation.coco_utils import cocoapi_eval 9 | from paddleseg.utils import metrics, logger 10 | 11 | 12 | # classification 13 | def eval_cls(gt_path, classification): 14 | """evalueate classification 15 | """ 16 | with open(gt_path, 'r') as f: 17 | gts = f.readlines() 18 | 19 | gt_dict = dict() 20 | for gt in gts: 21 | line = gt.strip().split() 22 | img_path, cls_id = line[0], line[1] 23 | gt_dict[img_path] = cls_id 24 | 25 | correct = 0 26 | total_cls = 0 27 | for cls in classification: 28 | for key in cls.keys(): 29 | pred_labe = str(cls[key]) 30 | gt_label = gt_dict[key] 31 | if gt_label == pred_labe: 32 | correct += 1 33 | total_cls += 1 34 | acc = correct * 1.0 / total_cls 35 | print("cls Acc@1: %.4f" % (correct / total_cls)) 36 | return acc 37 | 38 | # detection 39 | def eval_dec(gt_det, pred_det): 40 | """evalueate detection 41 | """ 42 | bbox_stats = cocoapi_eval(pred_det, 'bbox', anno_file=gt_det) 43 | eval_results = {} 44 | eval_results['bbox'] = bbox_stats 45 | mAP = eval_results['bbox'][1] 46 | return mAP 47 | 48 | 49 | # segmentation 50 | def polygon2mask(polygons): 51 | """polygon2mask for eval 52 | """ 53 | save_path = 'polygon2mask/' 54 | if not os.path.exists(save_path): 55 | os.mkdir(save_path) 56 | 57 | for img_info in polygons: 58 | img_name = None 59 | for img_name in img_info.keys(): 60 | cls_polygons = img_info[img_name] 61 | img_name = img_name 62 | 63 | mask = np.zeros((720, 1280), dtype=np.uint8) 64 | for category in cls_polygons.keys(): 65 | polys = [] 66 | if category == 0: 67 | continue 68 | 69 | cls_polys = cls_polygons[category] 70 | 71 | for poly in cls_polys: 72 | if len(poly)<=2: 73 | continue 74 | polys.append(np.array(poly, dtype=np.int32)) 75 | cv2.fillPoly(mask, polys, int(category)) 76 | cv2.imwrite(os.path.join(save_path, img_name), mask) 77 | 78 | 79 | def eval_seg(gt_file, pred_file): 80 | """evaluate segemntation 81 | """ 82 | intersect_area_all = paddle.zeros([1], dtype='int64') 83 | pred_area_all = paddle.zeros([1], dtype='int64') 84 | label_area_all = paddle.zeros([1], dtype='int64') 85 | 86 | pred_files = os.listdir(pred_file) 87 | gt_files = os.listdir(gt_file) 88 | 89 | pred_files.sort() 90 | gt_files.sort() 91 | for i, name in enumerate(gt_files): 92 | img_path = os.path.join(gt_file, name) 93 | label = paddle.to_tensor(np.asarray(Image.open(img_path)).astype('int64')) 94 | label = paddle.unsqueeze(label, axis=[0]) 95 | 96 | data_path = os.path.join(pred_file, pred_files[i]) 97 | 98 | pred = paddle.to_tensor(np.asarray(Image.open(data_path)).astype('int32')) 99 | pred = paddle.unsqueeze(pred, axis=[0, 1]) 100 | intersect_area, pred_area, label_area = metrics.calculate_area( 101 | pred, 102 | label, 103 | 19, 104 | ignore_index=255) 105 | 106 | intersect_area_all = intersect_area_all + intersect_area 107 | pred_area_all = pred_area_all + pred_area 108 | label_area_all = label_area_all + label_area 109 | 110 | metrics_input = (intersect_area_all, pred_area_all, label_area_all) 111 | class_iou, miou = metrics.mean_iou(*metrics_input) 112 | acc, class_precision, class_recall = metrics.class_measurement( 113 | *metrics_input) 114 | 115 | print_detail = True 116 | if print_detail: 117 | logger.info("[EVAL] mIoU: \n" + str(np.round(miou, 4))) 118 | logger.info("[EVAL] Class IoU: \n" + str(np.round(class_iou, 3))) 119 | logger.info("[EVAL] Class Precision: \n" + str( 120 | np.round(class_precision, 3))) 121 | logger.info("[EVAL] Class Recall: \n" + str(np.round(class_recall, 3))) 122 | return miou 123 | 124 | 125 | def main(): 126 | 127 | pred_file = sys.argv[1] # pred_cls.txt' 128 | cls_gt_file = sys.argv[2] 129 | dec_gt_file = sys.argv[3] 130 | seg_gt_file = sys.argv[4] 131 | with open(pred_file, 'r') as f: 132 | obj_json = json.load(f) 133 | 134 | classification = obj_json['cls'] 135 | detection = obj_json['dec'] 136 | segmentation = obj_json['seg'] 137 | 138 | acc = eval_cls(cls_gt_file, classification) 139 | mAP = eval_dec(dec_gt_file, detection) 140 | 141 | polygon2mask(segmentation) 142 | mIoU = eval_seg(seg_gt_file, 'polygon2mask/') 143 | 144 | average_score = round(sum([acc, mAP, mIoU]) / 3.0, 4) 145 | 146 | return [acc, mAP, mIoU, average_score] 147 | 148 | 149 | if __name__ == "__main__" : 150 | acc, mAP, mIoU, average_score = main() 151 | print(acc, mAP, mIoU, average_score) 152 | -------------------------------------------------------------------------------- /OneForAll/tools/moe_group_utils.py: -------------------------------------------------------------------------------- 1 | import paddle 2 | import numpy as np 3 | 4 | def get_moe_group(dp_degree): 5 | #构建 moe group 6 | world_size = paddle.distributed.get_world_size() 7 | # dp_degree = cfg.train.dp_degree 8 | assert world_size % dp_degree == 0, "Error! be sure that world_size '%' dp_degree == 0" 9 | print("==================trainer info===================") 10 | ranks = list(range(world_size)) 11 | group_len = len(ranks) // dp_degree 12 | global_group = paddle.distributed.new_group(ranks) 13 | cur_rank = paddle.distributed.get_rank() 14 | print("==>cur_rank: ", cur_rank) 15 | print("==>global_group: ", global_group) 16 | dp_groups = [ranks[i::group_len] for i in range(group_len)] 17 | moe_groups = np.split(np.array(ranks), dp_degree) 18 | cur_dp_group = None 19 | for dp in dp_groups: 20 | print("==>", dp) 21 | tmp = paddle.distributed.new_group(dp) 22 | if cur_rank in dp: 23 | cur_dp_group = tmp 24 | 25 | cur_moe_group = None 26 | for mp in moe_groups: 27 | print("==>", mp) 28 | tmp = paddle.distributed.new_group(mp.tolist()) 29 | if cur_rank in mp.tolist(): 30 | cur_moe_group = tmp 31 | print("==>cur_dp_group: ", cur_dp_group) 32 | print("==>cur_moe_group: ", cur_moe_group) 33 | print("======================================") 34 | return cur_moe_group 35 | 36 | 37 | def get_dp_group(dp_degree): 38 | #构建 moe group 39 | world_size = paddle.distributed.get_world_size() 40 | # dp_degree = cfg.train.dp_degree 41 | assert world_size % dp_degree == 0, "Error! be sure that world_size '%' dp_degree == 0" 42 | print("==================trainer info===================") 43 | ranks = list(range(world_size)) 44 | group_len = len(ranks) // dp_degree 45 | global_group = paddle.distributed.new_group(ranks) 46 | cur_rank = paddle.distributed.get_rank() 47 | print("==>cur_rank: ", cur_rank) 48 | print("==>global_group: ", global_group) 49 | dp_groups = [ranks[i::group_len] for i in range(group_len)] 50 | moe_groups = np.split(np.array(ranks), dp_degree) 51 | cur_dp_group = None 52 | for dp in dp_groups: 53 | print("==>", dp) 54 | tmp = paddle.distributed.new_group(dp) 55 | if cur_rank in dp: 56 | cur_dp_group = tmp 57 | 58 | cur_moe_group = None 59 | for mp in moe_groups: 60 | print("==>", mp) 61 | tmp = paddle.distributed.new_group(mp.tolist()) 62 | if cur_rank in mp.tolist(): 63 | cur_moe_group = tmp 64 | print("==>cur_dp_group: ", cur_dp_group) 65 | print("==>cur_moe_group: ", cur_moe_group) 66 | print("======================================") 67 | return cur_dp_group 68 | -------------------------------------------------------------------------------- /OneForAll/tools/ufo_test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Copyright (c) Baidu, Inc. and its affiliates. 3 | """ 4 | This training script is mainly constructed on train_net.py. 5 | Additionally, this script is specialized for the training of supernet. 6 | Moreover, this script adds a function of self-distillation. 7 | If specifing `teacher_model_path` in the given config file, teacher model will 8 | be built, otherwise teacher model is None. 9 | """ 10 | import logging 11 | import os.path 12 | import sys 13 | import os 14 | 15 | import paddle 16 | import numpy as np 17 | import json 18 | sys.path.append('.') 19 | 20 | SEED = os.getenv("SEED", "0") 21 | paddle.seed(42) 22 | # np.random.seed(int(SEED)) 23 | 24 | from utils.events import CommonMetricSacredWriter 25 | from engine.hooks import LRScheduler 26 | from utils.config import auto_adjust_cfg 27 | from fastreid.utils.checkpoint import Checkpointer 28 | from detectron2.config import LazyConfig, instantiate 29 | from detectron2.engine import ( 30 | AMPTrainer, 31 | SimpleTrainer, 32 | default_argument_parser, 33 | default_setup, 34 | default_writers, 35 | hooks, 36 | ) 37 | from evaluation import print_csv_format 38 | from evaluation.evaluator import inference_on_dataset 39 | from evaluation.seg_evaluator import seg_inference_on_dataset, seg_inference_on_test_dataset 40 | from utils import comm 41 | 42 | logger = logging.getLogger("ufo") 43 | 44 | 45 | def do_test(cfg, model, _run=None, subnet_mode="largest"): 46 | if "evaluator" in cfg.dataloader: 47 | dataloaders = instantiate(cfg.dataloader.test) 48 | pred_rets = {} 49 | for idx, (dataloader, evaluator_cfg) in enumerate(zip(dataloaders, cfg.dataloader.evaluator)): 50 | task_name = '.'.join(list(dataloader.task_loaders.keys())) 51 | dataset_name = dataloader.task_loaders[task_name].dataset.dataset_name 52 | if (hasattr(cfg.train, 'selected_task_names')) and (task_name not in cfg.train.selected_task_names): 53 | continue 54 | print('=' * 10, dataset_name, '=' * 10) 55 | # recognition 56 | if hasattr(list(dataloader.task_loaders.values())[0].dataset, 'num_query'): 57 | evaluator_cfg.num_query = list(dataloader.task_loaders.values())[0].dataset.num_query 58 | evaluator_cfg.num_valid_samples = list(dataloader.task_loaders.values())[0].dataset.num_valid_samples 59 | evaluator_cfg.labels = list(dataloader.task_loaders.values())[0].dataset.labels 60 | evaluator = instantiate(evaluator_cfg) 61 | ret = inference_on_dataset(model, dataloader, evaluator) 62 | # segmentation 63 | elif dataset_name in['Cityscapes', 'BDD100K', 'InferDataset']: 64 | evaluator = instantiate(evaluator_cfg) 65 | print("seg_inference_on_test_dataset") 66 | ret = seg_inference_on_test_dataset(model, dataloader, evaluator) 67 | # detection 68 | else: 69 | evaluator_cfg.anno_file = list(dataloader.task_loaders.values())[0].dataset.get_anno() 70 | evaluator_cfg.clsid2catid = {v: k for k, v in list(dataloader.task_loaders.values())[0].dataset.catid2clsid.items()} 71 | evaluator = instantiate(evaluator_cfg) 72 | ret = inference_on_dataset(model, dataloader, evaluator) 73 | if comm.is_main_process(): 74 | pred_rets.update(**ret) 75 | 76 | if comm.is_main_process(): 77 | save_path = cfg.train.output_dir 78 | if not os.path.exists(save_path): 79 | os.makedirs(save_path) 80 | save_path = os.path.join(save_path, 'pred_results.json') 81 | with open(save_path, 'w') as f: 82 | json.dump(pred_rets, f) 83 | logger.info(f'Pred results are saved to {save_path}') 84 | def main(args): 85 | if 'RANK' in os.environ and 'WORLD_SIZE' in os.environ: 86 | args.rank = int(os.environ["RANK"]) 87 | args.world_size = int(os.environ['WORLD_SIZE']) 88 | args.gpu = int(os.environ['LOCAL_RANK']) 89 | print('rank is {} , world_size is {}, gpu is {} '.format(args.rank, args.world_size, args.gpu)) 90 | 91 | paddle.set_device('gpu') 92 | rank = paddle.distributed.get_rank() 93 | print('rank is {}, world size is {}'.format(rank, paddle.distributed.get_world_size())) 94 | if paddle.distributed.get_world_size() > 1: 95 | paddle.distributed.init_parallel_env() 96 | 97 | cfg = LazyConfig.load(args.config_file) 98 | cfg = LazyConfig.apply_overrides(cfg, args.opts) 99 | default_setup(cfg, args) 100 | 101 | model = instantiate(cfg.model) 102 | model.to(cfg.train.device) 103 | if paddle.distributed.get_world_size() > 1: 104 | model = paddle.DataParallel(model) 105 | Checkpointer(model).load(cfg.train.init_checkpoint) 106 | do_test(cfg, model) 107 | 108 | if __name__ == "__main__": 109 | args = default_argument_parser().parse_args() 110 | 111 | main(args) 112 | -------------------------------------------------------------------------------- /OneForAll/utils/__init__.py: -------------------------------------------------------------------------------- 1 | """__init__.py 2 | """ -------------------------------------------------------------------------------- /OneForAll/utils/comm.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2 | """ 3 | This file contains primitives for multi-gpu communication. 4 | This is useful when doing distributed training. 5 | """ 6 | 7 | import functools 8 | import logging 9 | import numpy as np 10 | import pickle 11 | 12 | import paddle 13 | import paddle.distributed as dist 14 | 15 | _LOCAL_PROCESS_GROUP = None 16 | 17 | 18 | def get_world_size(dp_group=None): 19 | """get_world_size 20 | """ 21 | if dp_group is None: 22 | return dist.get_world_size() 23 | else: 24 | return dp_group.nranks 25 | 26 | 27 | def get_rank(): 28 | """get_rank 29 | """ 30 | return dist.get_rank() 31 | 32 | 33 | def get_local_rank(): 34 | """ 35 | Returns: 36 | The rank of the current process within the local (per-machine) process group. 37 | """ 38 | return dist.ParallelEnv().local_rank 39 | 40 | 41 | def get_local_size(): 42 | """ 43 | Returns: 44 | The size of the per-machine process group, 45 | i.e. the number of processes per machine. 46 | """ 47 | return dist.ParallelEnv().local_rank 48 | 49 | 50 | def is_main_process(): 51 | """judge whether the current process is the main process 52 | """ 53 | return get_rank() == 0 54 | 55 | 56 | def synchronize(): 57 | """ 58 | Helper function to synchronize (barrier) among all processes when 59 | using distributed training 60 | """ 61 | if dist.get_world_size() > 1: 62 | dist.barrier() 63 | 64 | 65 | def gather_v(data, dst=0, group=None): 66 | """ 67 | Run gather on arbitrary picklable data (not necessarily tensors). 68 | 69 | Args: 70 | data: tensor 71 | dst (int): destination rank 72 | group: 73 | 74 | Returns: 75 | list[data]: on dst, a list of data gathered from each rank. Otherwise, 76 | an empty list. 77 | """ 78 | if get_world_size(group) > 1: 79 | data_list = [] 80 | paddle.distributed.all_gather(data_list, data, group) 81 | else: 82 | data_list = [data] 83 | return data_list 84 | 85 | 86 | def gather(datas, dst=0, group=None): 87 | """ 88 | Run gather on arbitrary picklable data (not necessarily tensors). 89 | 90 | Args: 91 | datas: 列表数据有2种类型, 92 | 类型1:list=[paddle.Tensor, paddle.Tensor, ..., paddle.Tensor] 93 | 类型2:list=[ 94 | {'key1':paddle.Tensor, 'key2':paddle.Tensor, ..., 'keyn':paddle.Tensor}, 95 | {'key1':paddle.Tensor, 'key2':paddle.Tensor, ..., 'keyn':paddle.Tensor}, 96 | ... 97 | {'key1':paddle.Tensor, 'key2':paddle.Tensor, ..., 'keyn':paddle.Tensor} 98 | ] 99 | Returns: 100 | 经过gathered后的数据data_list, 101 | 对于类型1,data_list=[[paddle.Tensor,...], [paddle.Tensor,...], ..., ] 102 | 对于类型2,data_list=[ 103 | [{'key1':paddle.Tensor, 'key2':paddle.Tensor, ..., 'keyn':paddle.Tensor}, {'key1':paddle.Tensor, 'key2':paddle.Tensor, ..., 'keyn':paddle.Tensor}, ... ], #长度为world-size 104 | [{'key1':paddle.Tensor, 'key2':paddle.Tensor, ..., 'keyn':paddle.Tensor}, {'key1':paddle.Tensor, 'key2':paddle.Tensor, ..., 'keyn':paddle.Tensor}, ... ], 105 | ... 106 | [{'key1':paddle.Tensor, 'key2':paddle.Tensor, ..., 'keyn':paddle.Tensor}, {'key1':paddle.Tensor, 'key2':paddle.Tensor, ..., 'keyn':paddle.Tensor}, ... ], 107 | ] 108 | list[data]: 109 | """ 110 | if get_world_size(group) > 1: 111 | data_list = [] 112 | for data in datas: 113 | if isinstance(data, paddle.Tensor): 114 | gathered_data = [] 115 | paddle.distributed.all_gather(gathered_data, data, group) 116 | data_list.append(gathered_data) 117 | elif isinstance(data, dict): 118 | global_dict = {} 119 | for key, value in data.items(): 120 | gathered_value = [] 121 | paddle.distributed.all_gather(gathered_value, value, group) 122 | global_dict[key] = gathered_value 123 | 124 | gathered_data = [] 125 | for i in range(len(gathered_value)): 126 | local_dict = {} 127 | for key in global_dict.keys(): 128 | local_dict[key] = global_dict[key][i] 129 | gathered_data.append(local_dict) 130 | data_list.append(gathered_data) 131 | else: 132 | data_list = [datas] 133 | return data_list 134 | 135 | def shared_random_seed(): 136 | """ 137 | Returns: 138 | int: a random number that is the same across all workers. 139 | If workers need a shared RNG, they can use this shared seed to 140 | create one. 141 | 142 | All workers must call this function, otherwise it will deadlock. 143 | """ 144 | return 0 #TODO add shared_random_seed 145 | 146 | 147 | def reduce_dict(input_dict, average=True): 148 | """ 149 | Reduce the values in the dictionary from all processes so that process with rank 150 | 0 has the reduced results. 151 | 152 | Args: 153 | input_dict (dict): inputs to be reduced. All the values must be scalar CUDA Tensor. 154 | average (bool): whether to do average or sum 155 | 156 | Returns: 157 | a dict with the same keys as input_dict, after reduction. 158 | """ 159 | pass 160 | -------------------------------------------------------------------------------- /OneForAll/utils/compute_dist.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | """ 3 | @author: xingyu liao 4 | @contact: sherlockliao01@gmail.com 5 | """ 6 | 7 | # Modified from: https://github.com/open-mmlab/OpenUnReID/blob/66bb2ae0b00575b80fbe8915f4d4f4739cc21206/openunreid/core/utils/compute_dist.py 8 | 9 | 10 | import faiss 11 | import numpy as np 12 | import paddle 13 | import paddle.nn.functional as F 14 | 15 | __all__ = [ 16 | "build_dist", 17 | "compute_jaccard_distance", 18 | "compute_euclidean_distance", 19 | "compute_cosine_distance", 20 | ] 21 | 22 | 23 | @paddle.no_grad() 24 | def build_dist(feat_1, feat_2, metric="euclidean", **kwargs): 25 | r"""Compute distance between two feature embeddings. 26 | 27 | Args: 28 | feat_1 (paddle.Tensor): 2-D feature with batch dimension. 29 | feat_2 (paddle.Tensor): 2-D feature with batch dimension. 30 | metric: 31 | 32 | Returns: 33 | numpy.ndarray: distance matrix. 34 | """ 35 | assert metric in ["cosine", "euclidean", "jaccard"], "Expected metrics are cosine, euclidean and jaccard, " \ 36 | "but got {}".format(metric) 37 | 38 | if metric == "euclidean": 39 | return compute_euclidean_distance(feat_1, feat_2) 40 | 41 | elif metric == "cosine": 42 | return compute_cosine_distance(feat_1, feat_2) 43 | 44 | # elif metric == "jaccard": 45 | # feat = paddle.concat((feat_1, feat_2), axis=0) 46 | # dist = compute_jaccard_distance(feat, k1=kwargs["k1"], k2=kwargs["k2"], search_option=0) 47 | # return dist[:feat_1.size(0), feat_1.size(0):] 48 | 49 | 50 | def k_reciprocal_neigh(initial_rank, i, k1): 51 | """k_reciprocal_neigh 52 | """ 53 | forward_k_neigh_index = initial_rank[i, : k1 + 1] 54 | backward_k_neigh_index = initial_rank[forward_k_neigh_index, : k1 + 1] 55 | fi = np.where(backward_k_neigh_index == i)[0] 56 | return forward_k_neigh_index[fi] 57 | 58 | 59 | @paddle.no_grad() 60 | def compute_jaccard_distance(features, k1=20, k2=6, search_option=0, fp16=False): 61 | """compute_jaccard_distance 62 | """ 63 | pass 64 | 65 | 66 | @paddle.no_grad() 67 | def compute_euclidean_distance(features, others): 68 | """compute_euclidean_distance 69 | """ 70 | m, n = features.size(0), others.size(0) 71 | dist_m = ( 72 | paddle.pow(features, 2).sum(dim=1, keepdim=True).expand(m, n) 73 | + paddle.pow(others, 2).sum(dim=1, keepdim=True).expand(n, m).t() 74 | ) 75 | dist_m.addmm_(1, -2, features, others.t()).numpy() 76 | 77 | return dist_m 78 | 79 | 80 | @paddle.no_grad() 81 | def compute_cosine_distance(features, others): 82 | """Computes cosine distance. 83 | Args: 84 | features (paddle.Tensor): 2-D feature matrix. 85 | others (paddle.Tensor): 2-D feature matrix. 86 | Returns: 87 | paddle.Tensor: distance matrix. 88 | """ 89 | features = F.normalize(features, p=2, axis=1) 90 | others = F.normalize(others, p=2, axis=1) 91 | dist_m = 1 - paddle.mm(features, others.t()).numpy() 92 | return dist_m 93 | -------------------------------------------------------------------------------- /OneForAll/utils/config.py: -------------------------------------------------------------------------------- 1 | """utils/config.py 2 | """ 3 | import logging 4 | 5 | 6 | def auto_adjust_cfg(cfg, train_loader): 7 | """auto_adjust_cfg 8 | """ 9 | logger = logging.getLogger("ufo") 10 | 11 | # single task 12 | if "num_classes" in cfg.model.heads and cfg.model.heads.num_classes == 0: 13 | # auto scale num classes 14 | num_classes = train_loader.dataset.num_classes 15 | cfg.model.heads.num_classes = num_classes 16 | logger.info('Autoscale number of classes: {}'.format(num_classes)) 17 | 18 | # multitask 19 | if "task_loaders" in cfg.dataloader.train: 20 | for task_name, task_loader in train_loader.task_loaders.items(): 21 | if hasattr(task_loader.dataset, 'num_classes'): 22 | num_classes = task_loader.dataset.num_classes 23 | cfg.model.heads[task_name].num_classes = num_classes 24 | logger.info('Autoscale {} number of classes: {}'.format(task_name, num_classes)) 25 | 26 | return cfg 27 | -------------------------------------------------------------------------------- /OneForAll/utils/events.py: -------------------------------------------------------------------------------- 1 | """utils/events.py 2 | """ 3 | import datetime 4 | import json 5 | import logging 6 | import os 7 | import time 8 | from collections import defaultdict 9 | from contextlib import contextmanager 10 | from typing import Optional 11 | from fvcore.common.history_buffer import HistoryBuffer 12 | 13 | from detectron2.utils.events import EventWriter, get_event_storage 14 | from detectron2.utils.file_io import PathManager 15 | 16 | 17 | class CommonMetricSacredWriter(EventWriter): 18 | """CommonMetricSacredWriter 19 | """ 20 | def __init__(self, _run, max_iter=None, window_size=20): 21 | """ 22 | Args: 23 | max_iter: the maximum number of iterations to train. 24 | Used to compute ETA. If not given, ETA will not be printed. 25 | window_size (int): the losses will be median-smoothed by this window size 26 | """ 27 | self.logger = logging.getLogger(__name__) 28 | self._run = _run 29 | self._max_iter = max_iter 30 | self._window_size = window_size 31 | self._last_write = None # (step, time) of last call to write(). Used to compute ETA 32 | 33 | def _get_eta(self, storage): 34 | if self._max_iter is None: 35 | return None 36 | iteration = storage.iter 37 | try: 38 | eta_seconds = storage.history("time").median(1000) * (self._max_iter - iteration - 1) 39 | storage.put_scalar("eta_seconds", eta_seconds, smoothing_hint=False) 40 | return eta_seconds / 60. / 60. # hours 41 | except KeyError: 42 | # estimate eta on our own - more noisy 43 | eta = None 44 | if self._last_write is not None: 45 | estimate_iter_time = (time.perf_counter() - self._last_write[1]) / ( 46 | iteration - self._last_write[0] 47 | ) 48 | eta_seconds = estimate_iter_time * (self._max_iter - iteration - 1) 49 | eta = eta_seconds / 60. / 60. # hours 50 | self._last_write = (iteration, time.perf_counter()) 51 | return eta 52 | 53 | def write(self): 54 | """write 55 | """ 56 | storage = get_event_storage() 57 | iteration = storage.iter 58 | 59 | try: 60 | data_time = storage.history("data_time").avg(20) 61 | except KeyError: 62 | # they may not exist in the first few iterations (due to warmup) 63 | # or when SimpleTrainer is not used 64 | data_time = None 65 | if data_time is not None: 66 | self._run.log_scalar('data_time', data_time, iteration) 67 | 68 | try: 69 | iter_time = storage.history("time").global_avg() 70 | except KeyError: 71 | iter_time = None 72 | if iter_time is not None: 73 | self._run.log_scalar('iter_time', iter_time, iteration) 74 | 75 | try: 76 | lr = storage.history("lr").latest() 77 | except KeyError: 78 | lr = None 79 | if lr is not None: 80 | self._run.log_scalar('lr', lr, iteration) 81 | 82 | eta = self._get_eta(storage) 83 | if eta is not None: 84 | self._run.log_scalar('eta', eta, iteration) 85 | 86 | max_mem_mb = None 87 | if eta is not None: 88 | self._run.log_scalar('max_mem_mb', max_mem_mb, iteration) 89 | 90 | for k, v in storage.histories().items(): 91 | if "loss" in k: 92 | self._run.log_scalar(k, v.median(self._window_size), iteration) 93 | -------------------------------------------------------------------------------- /OneForAll/utils/file_io.py: -------------------------------------------------------------------------------- 1 | """utils.file_io 2 | """ 3 | # Copyright 4 | from iopath.common.file_io import HTTPURLHandler, OneDrivePathHandler, PathHandler 5 | from iopath.common.file_io import PathManager as PathManagerBase 6 | 7 | __all__ = ["PathManager", "PathHandler"] 8 | 9 | 10 | PathManager = PathManagerBase() 11 | """ 12 | This is a detectron2 project-specific PathManager. 13 | We try to stay away from global PathManager in fvcore as it 14 | introduces potential conflicts among other libraries. 15 | """ 16 | 17 | 18 | class Detectron2Handler(PathHandler): 19 | """ 20 | Resolve anything that's hosted under detectron2's namespace. 21 | """ 22 | 23 | PREFIX = "detectron2://" 24 | S3_DETECTRON2_PREFIX = "https://dl.fbaipublicfiles.com/detectron2/" 25 | 26 | def _get_supported_prefixes(self): 27 | return [self.PREFIX] 28 | 29 | def _get_local_path(self, path, **kwargs): 30 | name = path[len(self.PREFIX):] 31 | return PathManager.get_local_path(self.S3_DETECTRON2_PREFIX + name, **kwargs) 32 | 33 | def _open(self, path, mode="r", **kwargs): 34 | return PathManager.open(self._get_local_path(path), mode, **kwargs) 35 | 36 | 37 | PathManager.register_handler(HTTPURLHandler()) 38 | PathManager.register_handler(OneDrivePathHandler()) 39 | PathManager.register_handler(Detectron2Handler()) 40 | -------------------------------------------------------------------------------- /OneForAll/utils/misc.py: -------------------------------------------------------------------------------- 1 | # !/usr/bin/env python3 2 | 3 | import os 4 | import sys 5 | import datetime 6 | 7 | original_print = print 8 | 9 | 10 | def _stdout_write(s, flush=False): 11 | sys.stdout.write(s) 12 | if flush: 13 | sys.stdout.flush() 14 | 15 | 16 | def _stderr_write(s, flush=False): 17 | sys.stderr.write(s) 18 | if flush: 19 | sys.stderr.flush() 20 | 21 | 22 | def _debug_print(*args, sep=' ', end='\n', file=None, flush=True): 23 | args = (str(arg) for arg in args) # convert to string as numbers cannot be joined 24 | if file == sys.stderr: 25 | _stderr_write(sep.join(args), flush) 26 | elif file in [sys.stdout, None]: 27 | lineno = sys._getframe().f_back.f_lineno 28 | filename = sys._getframe(1).f_code.co_filename 29 | 30 | stdout = f'\033[31m{datetime.datetime.now().strftime("%H:%M:%S.%f")}\x1b[0m \033[32m{filename}:{lineno}\x1b[0m {sep.join(args)} {end}' 31 | _stdout_write(stdout, flush) 32 | else: 33 | # catch exceptions 34 | original_print(*args, sep=sep, end=end, file=file) 35 | 36 | 37 | # monkey patch print 38 | def patch_print(): 39 | try: 40 | __builtins__.print = _debug_print 41 | except AttributeError: 42 | __builtins__['print'] = _debug_print 43 | 44 | 45 | def remove_patch_print(): 46 | try: 47 | __builtins__.print = original_print 48 | except AttributeError: 49 | __builtins__['print'] = original_print -------------------------------------------------------------------------------- /README_ch.md: -------------------------------------------------------------------------------- 1 | 简体中文 | [English](README.md) 2 | 3 | ## **赛题背景** 4 | 5 | ### **整体概述** 6 | 7 | 对于设计精良的网络结构和损失函数,多个任务共同训练能大幅提升模型的泛化性。由于特定任务的数据存在noise,仅使用单一任务的数据进行训练,存在过拟合的风险。统一多任务大模型通过将多个任务的数据整合进行统一训练,能够对不同任务的noise做一个平均,进而使模型学到更好的特征。为了进一步探索统一多任务大模型的能力上限,本赛道以交通场景典型任务为题,联合分类、检测、分割三项CV任务三大数据集至单一大模型中,使得单一大模型具备能力的同时获得领先于特定单任务模型的性能。 8 | 9 | ### **原理介绍** 10 | 11 | 之前主流的视觉模型生产流程,通常采用单任务 “train from scratch” 方案。每个任务都从零开始训练,各个任务之间也无法相互借鉴。由于单任务数据不足带来偏置问题,实际效果过分依赖任务数据分布,场景泛化效果往往不佳。近两年蓬勃发展的大数据预训练技术,通过使用大量数据学到更多的通用知识,然后迁移到下游任务当中,本质上是不同任务之间相互借鉴了各自学到的知识。基于海量数据获得的预训练模型具有较好的知识完备性,在下游任务中基于少量数据 fine-tuning 依然可以获得较好的效果。不过基于预训练+下游任务 fine-tuning 的模型生产流程,需要针对各个任务分别训练模型,存在较大的研发资源消耗。 12 | 13 | 百度提出的 VIMER-UFO([*UFO:Unified Feature Optimization*](https://arxiv.org/pdf/2207.10341v1.pdf)) All in One 多任务训练方案,通过使用多个任务的数据训练一个功能强大的通用模型,可被直接应用于处理多个任务。不仅通过跨任务的信息提升了单个任务的效果,并且免去了下游任务 fine-tuning 过程。VIMER-UFO All in One 研发模式可被广泛应用于各类多任务 AI 系统,以智慧城市场景为例,VIMER-UFO 可以用单模型实现人脸识别、人体和车辆ReID等多个任务的 SOTA 效果,同时多任务模型可获得显著优于单任务模型的效果,证明了多任务之间信息借鉴机制的有效性。 14 | 15 | ### **赛题任务** 16 | 17 | 本赛道旨在通过多任务联合训练来提升模型的泛化能力,同时解决多任务、多数据之间冲突的问题。本赛题基于交通场景,选择了分类、检测、分割三大代表性任务进行AllInOne联合训练。 18 | 19 | 任务定义:根据给出的分类、检测、分割三任务的数据集,使用统一大模型进行AllInOne联合训练,使得单一模型能够具备分类、检测、分割的能力。 20 | 21 | #### **数据集介绍** 22 | 23 | 我们使用了分类、检测、分割的公开数据集具体如下: 24 | 25 | ##### **训练集** 26 | 27 | | 任务 | 任务类别 | 数据集 | 图片数 | 28 | | -------------------------------------------------- | -------- | --------------------- | ------ | 29 | | Fine-Grained Image Classification on Stanford Cars | 分类 | Stanford Cars | 8,144 | 30 | | Traffic Sign Recognition on Tsinghua-Tencent 100K | 检测 | Tsinghua-Tencent 100K | 6,103 | 31 | | Semantic Segmentation on BDD100K | 分割 | BDD100K | 7,000 | 32 | 33 | ##### **测试集** 34 | 35 | | 任务 | 任务类别 | 数据集 | 图片数 | 36 | |----------------------------------------------------|----------|-----------------------|--------| 37 | | Fine-Grained Image Classification on Stanford Cars | 分类 | Stanford Cars | 8,041 | 38 | | Traffic Sign Recognition on Tsinghua-Tencent 100K | 检测 | Tsinghua-Tencent 100K | 3,067 | 39 | | Semantic Segmentation on BDD100K | 分割 | BDD100K | 1,000 | 40 | 41 | #### **数据说明** 42 | 43 | ##### **Stanford Cars** 44 | 45 | **标注格式**:每行由图片名称和对应类别id组成 46 | 47 | 参考标注实例如下方所示: 48 | 49 | 00001.jpg 0 50 | 51 | 00002.jpg 2 52 | 53 | 00003.jpg 1 54 | 55 | ... 56 | 57 | ##### **Tsinghua-Tencent 100K** 58 | 59 | **标注格式**:参考[*COCO标注格式*](https://cocodataset.org/#format-data) 60 | 61 | ##### **BDD100K** 62 | 63 | **标注格式**:参考[*BDD100K标注格式*](https://doc.bdd100k.com/download.html#semantic-segmentation) 64 | 65 | ### **评价指标** 66 | 67 | 分类任务:Top-1 accuracy 68 | 69 | 检测任务:mAP50 70 | 71 | 分割任务:mIoU 72 | 73 | A榜最终得分:三任务指标平均值 74 | 75 | ### **比赛说明** 76 | 77 | 比赛分A/B榜单,A榜基于选手提交的分类、检测、分割三任务预测结果文件进行打分;B榜需要选手提交代码和一键启动finetune脚本,在未公开数据集上进行finetune后测试的结果进行打分。 78 | 79 | 比赛提交截止日期前仅A榜对选手可见,比赛结束后B榜会对选手公布,比赛最终排名按照选手成绩在A榜和B榜联和的排名。 80 | 81 | 注意:请确保提交至B榜上的代码finetune脚本能够顺利运行 82 | 83 | ### **提交格式** 84 | 85 | 文件格式:JSON 86 | 87 | 内容格式: 88 | 89 | { 90 | 91 | ​ 'cls': { 92 | 93 | ​ 'image_name': pred_cls_id, 94 | 95 | ​ ... ... 96 | 97 | ​ }, 98 | 99 | ​ 'dec': [ 100 | 101 | ​ {'image_id': 1, 'category_id': 37, "bbox": [x, y, w, h], "score": pred_score}, 102 | 103 | ​ ... ... 104 | 105 | ​ ], 106 | 107 | ​ 'seg': { 108 | 109 | ​ 'image_name': {'pred_cls_id': pred_polygons, ... ...}, 110 | 111 | ​ ... ... 112 | 113 | ​ } 114 | 115 | } 116 | 117 | 参考示例: 118 | 119 | https://aistudio.baidu.com/aistudio/datasetdetail/203253 (track1_submit_example.json) 120 | --------------------------------------------------------------------------------