huantran2004 commited on
Commit
68efce6
·
verified ·
1 Parent(s): 1375457

Upload 127 files

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. CAGE_expression_inference-apvit/affectnet_annotations/train_set_annotation_without_lnd.csv +0 -0
  2. CAGE_expression_inference-apvit/affectnet_annotations/val_set_annotation_without_lnd.csv +0 -0
  3. CAGE_expression_inference-apvit/apvit_mmcls/__init__.py +3 -0
  4. CAGE_expression_inference-apvit/apvit_mmcls/apis/__init__.py +8 -0
  5. CAGE_expression_inference-apvit/apvit_mmcls/apis/inference.py +108 -0
  6. CAGE_expression_inference-apvit/apvit_mmcls/apis/test.py +158 -0
  7. CAGE_expression_inference-apvit/apvit_mmcls/apis/train.py +140 -0
  8. CAGE_expression_inference-apvit/apvit_mmcls/core/__init__.py +3 -0
  9. CAGE_expression_inference-apvit/apvit_mmcls/core/evaluation/__init__.py +8 -0
  10. CAGE_expression_inference-apvit/apvit_mmcls/core/evaluation/eval_hooks.py +158 -0
  11. CAGE_expression_inference-apvit/apvit_mmcls/core/evaluation/mean_ap.py +73 -0
  12. CAGE_expression_inference-apvit/apvit_mmcls/core/evaluation/multilabel_eval_metrics.py +71 -0
  13. CAGE_expression_inference-apvit/apvit_mmcls/core/fp16/__init__.py +4 -0
  14. CAGE_expression_inference-apvit/apvit_mmcls/core/fp16/decorators.py +160 -0
  15. CAGE_expression_inference-apvit/apvit_mmcls/core/fp16/hooks.py +132 -0
  16. CAGE_expression_inference-apvit/apvit_mmcls/core/fp16/utils.py +23 -0
  17. CAGE_expression_inference-apvit/apvit_mmcls/core/utils/__init__.py +4 -0
  18. CAGE_expression_inference-apvit/apvit_mmcls/core/utils/dist_utils.py +56 -0
  19. CAGE_expression_inference-apvit/apvit_mmcls/core/utils/misc.py +7 -0
  20. CAGE_expression_inference-apvit/apvit_mmcls/datasets/__init__.py +16 -0
  21. CAGE_expression_inference-apvit/apvit_mmcls/datasets/base_dataset.py +185 -0
  22. CAGE_expression_inference-apvit/apvit_mmcls/datasets/builder.py +110 -0
  23. CAGE_expression_inference-apvit/apvit_mmcls/datasets/cifar.py +123 -0
  24. CAGE_expression_inference-apvit/apvit_mmcls/datasets/dataset_wrappers.py +173 -0
  25. CAGE_expression_inference-apvit/apvit_mmcls/datasets/imagenet.py +1105 -0
  26. CAGE_expression_inference-apvit/apvit_mmcls/datasets/mnist.py +171 -0
  27. CAGE_expression_inference-apvit/apvit_mmcls/datasets/pipelines/__init__.py +15 -0
  28. CAGE_expression_inference-apvit/apvit_mmcls/datasets/pipelines/compose.py +42 -0
  29. CAGE_expression_inference-apvit/apvit_mmcls/datasets/pipelines/formating.py +156 -0
  30. CAGE_expression_inference-apvit/apvit_mmcls/datasets/pipelines/loading.py +67 -0
  31. CAGE_expression_inference-apvit/apvit_mmcls/datasets/pipelines/test_time_aug.py +126 -0
  32. CAGE_expression_inference-apvit/apvit_mmcls/datasets/pipelines/transforms.py +918 -0
  33. CAGE_expression_inference-apvit/apvit_mmcls/datasets/raf.py +144 -0
  34. CAGE_expression_inference-apvit/apvit_mmcls/datasets/samplers/__init__.py +3 -0
  35. CAGE_expression_inference-apvit/apvit_mmcls/datasets/samplers/distributed_sampler.py +42 -0
  36. CAGE_expression_inference-apvit/apvit_mmcls/datasets/utils.py +152 -0
  37. CAGE_expression_inference-apvit/apvit_mmcls/models/__init__.py +13 -0
  38. CAGE_expression_inference-apvit/apvit_mmcls/models/backbones/__init__.py +32 -0
  39. CAGE_expression_inference-apvit/apvit_mmcls/models/backbones/alexnet.py +55 -0
  40. CAGE_expression_inference-apvit/apvit_mmcls/models/backbones/base_backbone.py +57 -0
  41. CAGE_expression_inference-apvit/apvit_mmcls/models/backbones/iresnet.py +220 -0
  42. CAGE_expression_inference-apvit/apvit_mmcls/models/backbones/irse.py +387 -0
  43. CAGE_expression_inference-apvit/apvit_mmcls/models/backbones/irse_nopadding.py +366 -0
  44. CAGE_expression_inference-apvit/apvit_mmcls/models/backbones/lenet.py +41 -0
  45. CAGE_expression_inference-apvit/apvit_mmcls/models/backbones/mobilefacenet.py +133 -0
  46. CAGE_expression_inference-apvit/apvit_mmcls/models/backbones/mobilenet_v2.py +273 -0
  47. CAGE_expression_inference-apvit/apvit_mmcls/models/backbones/mobilenet_v3.py +186 -0
  48. CAGE_expression_inference-apvit/apvit_mmcls/models/backbones/modules/t2t.py +57 -0
  49. CAGE_expression_inference-apvit/apvit_mmcls/models/backbones/modules/vit.py +197 -0
  50. CAGE_expression_inference-apvit/apvit_mmcls/models/backbones/modules/vit_pooling.py +89 -0
CAGE_expression_inference-apvit/affectnet_annotations/train_set_annotation_without_lnd.csv ADDED
The diff for this file is too large to render. See raw diff
 
CAGE_expression_inference-apvit/affectnet_annotations/val_set_annotation_without_lnd.csv ADDED
The diff for this file is too large to render. See raw diff
 
CAGE_expression_inference-apvit/apvit_mmcls/__init__.py ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ from .version import __version__
2
+
3
+ __all__ = ['__version__']
CAGE_expression_inference-apvit/apvit_mmcls/apis/__init__.py ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ from .inference import inference_model, init_model, show_result_pyplot
2
+ from .test import multi_gpu_test, single_gpu_test
3
+ from .train import set_random_seed, train_model
4
+
5
+ __all__ = [
6
+ 'set_random_seed', 'train_model', 'init_model', 'inference_model',
7
+ 'multi_gpu_test', 'single_gpu_test', 'show_result_pyplot'
8
+ ]
CAGE_expression_inference-apvit/apvit_mmcls/apis/inference.py ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import warnings
2
+
3
+ import matplotlib.pyplot as plt
4
+ import mmcv
5
+ import numpy as np
6
+ import torch
7
+ from mmcv.parallel import collate, scatter
8
+ from mmcv.runner import load_checkpoint
9
+
10
+ from mmcls.datasets.pipelines import Compose
11
+ from mmcls.models import build_classifier
12
+
13
+
14
+ def init_model(config, checkpoint=None, device='cuda:0', options=None):
15
+ """Initialize a classifier from config file.
16
+
17
+ Args:
18
+ config (str or :obj:`mmcv.Config`): Config file path or the config
19
+ object.
20
+ checkpoint (str, optional): Checkpoint path. If left as None, the model
21
+ will not load any weights.
22
+ options (dict): Options to override some settings in the used config.
23
+
24
+ Returns:
25
+ nn.Module: The constructed classifier.
26
+ """
27
+ if isinstance(config, str):
28
+ config = mmcv.Config.fromfile(config)
29
+ elif not isinstance(config, mmcv.Config):
30
+ raise TypeError('config must be a filename or Config object, '
31
+ f'but got {type(config)}')
32
+ if options is not None:
33
+ config.merge_from_dict(options)
34
+ config.model.pretrained = None
35
+ config.model.extractor.pretrained = None
36
+ config.model.vit.pretrained = None
37
+ model = build_classifier(config.model)
38
+ if checkpoint is not None:
39
+ map_loc = 'cpu' if device == 'cpu' else None
40
+ checkpoint = load_checkpoint(model, checkpoint, map_location=map_loc)
41
+ class_loaded = False
42
+ if 'meta' in checkpoint:
43
+ if 'CLASSES' in checkpoint['meta']:
44
+ model.CLASSES = checkpoint['meta']['CLASSES']
45
+ class_loaded = True
46
+ if not class_loaded:
47
+ from mmcls.datasets.raf import FER_CLASSES
48
+ model.CLASSES = FER_CLASSES
49
+ model.cfg = config # save the config in the model for convenience
50
+ model.to(device)
51
+ model.eval()
52
+ return model
53
+
54
+
55
+ def inference_model(model, img):
56
+ """Inference image(s) with the classifier.
57
+
58
+ Args:
59
+ model (nn.Module): The loaded classifier.
60
+ img (str/ndarray): The image filename or loaded image.
61
+
62
+ Returns:
63
+ result (dict): The classification results that contains
64
+ `class_name`, `pred_label` and `pred_score`.
65
+ """
66
+ cfg = model.cfg
67
+ device = next(model.parameters()).device # model device
68
+ # build the data pipeline
69
+ if isinstance(img, str):
70
+ if cfg.data.test.pipeline[0]['type'] != 'LoadImageFromFile':
71
+ cfg.data.test.pipeline.insert(0, dict(type='LoadImageFromFile'))
72
+ data = dict(img_info=dict(filename=img), img_prefix=None)
73
+ else:
74
+ if cfg.data.test.pipeline[0]['type'] == 'LoadImageFromFile':
75
+ cfg.data.test.pipeline.pop(0)
76
+ data = dict(img=img)
77
+ test_pipeline = Compose(cfg.data.test.pipeline)
78
+ data = test_pipeline(data)
79
+ data = collate([data], samples_per_gpu=1)
80
+ if next(model.parameters()).is_cuda:
81
+ # scatter to specified GPU
82
+ data = scatter(data, [device])[0]
83
+
84
+ # forward the model
85
+ with torch.no_grad():
86
+ scores = model(return_loss=False, **data)
87
+ pred_score = np.max(scores, axis=1)[0]
88
+ pred_label = np.argmax(scores, axis=1)[0]
89
+ result = {'pred_label': pred_label, 'pred_score': float(pred_score)}
90
+ result['pred_class'] = model.CLASSES[result['pred_label']]
91
+ return result
92
+
93
+
94
+ def show_result_pyplot(model, img, result, fig_size=(15, 10)):
95
+ """Visualize the classification results on the image.
96
+
97
+ Args:
98
+ model (nn.Module): The loaded classifier.
99
+ img (str or np.ndarray): Image filename or loaded image.
100
+ result (list): The classification result.
101
+ fig_size (tuple): Figure size of the pyplot figure.
102
+ """
103
+ if hasattr(model, 'module'):
104
+ model = model.module
105
+ img = model.show_result(img, result, show=False)
106
+ plt.figure(figsize=fig_size)
107
+ plt.imshow(mmcv.bgr2rgb(img))
108
+ plt.show()
CAGE_expression_inference-apvit/apvit_mmcls/apis/test.py ADDED
@@ -0,0 +1,158 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os.path as osp
2
+ import pickle
3
+ import shutil
4
+ import tempfile
5
+ import time
6
+
7
+ import mmcv
8
+ import torch
9
+ import torch.distributed as dist
10
+ from mmcv.runner import get_dist_info
11
+
12
+
13
+ def single_gpu_test(model, data_loader, show=False, out_dir=None):
14
+ model.eval()
15
+ results = []
16
+ dataset = data_loader.dataset
17
+ prog_bar = mmcv.ProgressBar(len(dataset))
18
+ for i, data in enumerate(data_loader):
19
+ with torch.no_grad():
20
+ result = model(return_loss=False, **data)
21
+ results.append(result)
22
+
23
+ if show or out_dir:
24
+ pass # TODO
25
+
26
+ batch_size = data['img'].size(0)
27
+ for _ in range(batch_size):
28
+ prog_bar.update()
29
+ return results
30
+
31
+
32
+ def multi_gpu_test(model, data_loader, tmpdir=None, gpu_collect=False):
33
+ """Test model with multiple gpus.
34
+
35
+ This method tests model with multiple gpus and collects the results
36
+ under two different modes: gpu and cpu modes. By setting 'gpu_collect=True'
37
+ it encodes results to gpu tensors and use gpu communication for results
38
+ collection. On cpu mode it saves the results on different gpus to 'tmpdir'
39
+ and collects them by the rank 0 worker.
40
+
41
+ Args:
42
+ model (nn.Module): Model to be tested.
43
+ data_loader (nn.Dataloader): Pytorch data loader.
44
+ tmpdir (str): Path of directory to save the temporary results from
45
+ different gpus under cpu mode.
46
+ gpu_collect (bool): Option to use either gpu or cpu to collect results.
47
+
48
+ Returns:
49
+ list: The prediction results.
50
+ """
51
+ model.eval()
52
+ results = []
53
+ dataset = data_loader.dataset
54
+ rank, world_size = get_dist_info()
55
+ if rank == 0:
56
+ prog_bar = mmcv.ProgressBar(len(dataset))
57
+ time.sleep(2) # This line can prevent deadlock problem in some cases.
58
+ for i, data in enumerate(data_loader):
59
+ with torch.no_grad():
60
+ result = model(return_loss=False, **data)
61
+ if isinstance(result, list):
62
+ results.extend(result)
63
+ else:
64
+ results.append(result)
65
+
66
+ # if rank == 0:
67
+ # batch_size = data['img'].size(0)
68
+ # for _ in range(batch_size * world_size):
69
+ # prog_bar.update()
70
+
71
+ # collect results from all ranks
72
+ if gpu_collect:
73
+ results = collect_results_gpu(results, len(dataset))
74
+ else:
75
+ results = collect_results_cpu(results, len(dataset), tmpdir)
76
+ return results
77
+
78
+
79
+ def collect_results_cpu(result_part, size, tmpdir=None):
80
+ rank, world_size = get_dist_info()
81
+ # create a tmp dir if it is not specified
82
+ if tmpdir is None:
83
+ MAX_LEN = 512
84
+ # 32 is whitespace
85
+ dir_tensor = torch.full((MAX_LEN, ),
86
+ 32,
87
+ dtype=torch.uint8,
88
+ device='cuda')
89
+ if rank == 0:
90
+ tmpdir = tempfile.mkdtemp()
91
+ tmpdir = torch.tensor(
92
+ bytearray(tmpdir.encode()), dtype=torch.uint8, device='cuda')
93
+ dir_tensor[:len(tmpdir)] = tmpdir
94
+ dist.broadcast(dir_tensor, 0)
95
+ tmpdir = dir_tensor.cpu().numpy().tobytes().decode().rstrip()
96
+ else:
97
+ mmcv.mkdir_or_exist(tmpdir)
98
+ # dump the part result to the dir
99
+ mmcv.dump(result_part, osp.join(tmpdir, f'part_{rank}.pkl'))
100
+ dist.barrier()
101
+ # collect all parts
102
+ if rank != 0:
103
+ return None
104
+ else:
105
+ # load results of all parts from tmp dir
106
+ part_list = []
107
+ for i in range(world_size):
108
+ part_file = osp.join(tmpdir, f'part_{i}.pkl')
109
+ part_result = mmcv.load(part_file)
110
+ # When data is severely insufficient, an empty part_result
111
+ # on a certain gpu could makes the overall outputs empty.
112
+ if part_result:
113
+ part_list.append(part_result)
114
+ # sort the results
115
+ ordered_results = []
116
+ for res in zip(*part_list):
117
+ ordered_results.extend(list(res))
118
+ # the dataloader may pad some samples
119
+ ordered_results = ordered_results[:size]
120
+ # remove tmp dir
121
+ shutil.rmtree(tmpdir)
122
+ return ordered_results
123
+
124
+
125
+ def collect_results_gpu(result_part, size):
126
+ rank, world_size = get_dist_info()
127
+ # dump result part to tensor with pickle
128
+ part_tensor = torch.tensor(
129
+ bytearray(pickle.dumps(result_part)), dtype=torch.uint8, device='cuda')
130
+ # gather all result part tensor shape
131
+ shape_tensor = torch.tensor(part_tensor.shape, device='cuda')
132
+ shape_list = [shape_tensor.clone() for _ in range(world_size)]
133
+ dist.all_gather(shape_list, shape_tensor)
134
+ # padding result part tensor to max length
135
+ shape_max = torch.tensor(shape_list).max()
136
+ part_send = torch.zeros(shape_max, dtype=torch.uint8, device='cuda')
137
+ part_send[:shape_tensor[0]] = part_tensor
138
+ part_recv_list = [
139
+ part_tensor.new_zeros(shape_max) for _ in range(world_size)
140
+ ]
141
+ # gather all result part
142
+ dist.all_gather(part_recv_list, part_send)
143
+
144
+ if rank == 0:
145
+ part_list = []
146
+ for recv, shape in zip(part_recv_list, shape_list):
147
+ part_result = pickle.loads(recv[:shape[0]].cpu().numpy().tobytes())
148
+ # When data is severely insufficient, an empty part_result
149
+ # on a certain gpu could makes the overall outputs empty.
150
+ if part_result:
151
+ part_list.append(part_result)
152
+ # sort the results
153
+ ordered_results = []
154
+ for res in zip(*part_list):
155
+ ordered_results.extend(list(res))
156
+ # the dataloader may pad some samples
157
+ ordered_results = ordered_results[:size]
158
+ return ordered_results
CAGE_expression_inference-apvit/apvit_mmcls/apis/train.py ADDED
@@ -0,0 +1,140 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import random
2
+ import warnings
3
+
4
+ import numpy as np
5
+ import torch
6
+ from mmcv.parallel import MMDataParallel, MMDistributedDataParallel
7
+ from mmcv.runner import DistSamplerSeedHook, build_optimizer, build_runner, Fp16OptimizerHook, OptimizerHook
8
+
9
+ from mmcls.core import (DistEvalHook, EvalHook)
10
+ from mmcls.datasets import build_dataloader, build_dataset
11
+ from mmcls.utils import get_root_logger
12
+
13
+
14
+ def set_random_seed(seed, deterministic=False):
15
+ """Set random seed.
16
+
17
+ Args:
18
+ seed (int): Seed to be used.
19
+ deterministic (bool): Whether to set the deterministic option for
20
+ CUDNN backend, i.e., set `torch.backends.cudnn.deterministic`
21
+ to True and `torch.backends.cudnn.benchmark` to False.
22
+ Default: False.
23
+ """
24
+ random.seed(seed)
25
+ np.random.seed(seed)
26
+ torch.manual_seed(seed)
27
+ torch.cuda.manual_seed_all(seed)
28
+ if deterministic:
29
+ torch.backends.cudnn.deterministic = True
30
+ torch.backends.cudnn.benchmark = False
31
+
32
+
33
+ def train_model(model,
34
+ dataset,
35
+ cfg,
36
+ distributed=False,
37
+ validate=False,
38
+ timestamp=None,
39
+ meta=None):
40
+ logger = get_root_logger(cfg.log_level)
41
+
42
+ # prepare data loaders
43
+ dataset = dataset if isinstance(dataset, (list, tuple)) else [dataset]
44
+
45
+ data_loaders = [
46
+ build_dataloader(
47
+ ds,
48
+ cfg.data.samples_per_gpu,
49
+ cfg.data.workers_per_gpu,
50
+ # cfg.gpus will be ignored if distributed
51
+ num_gpus=len(cfg.gpu_ids),
52
+ dist=distributed,
53
+ round_up=True,
54
+ seed=cfg.seed,
55
+ # persistent_workers=True
56
+ ) for ds in dataset
57
+ ]
58
+
59
+ # build runner
60
+ optimizer = build_optimizer(model, cfg.optimizer)
61
+
62
+ # if 'use_fp16' in cfg and cfg.use_fp16:
63
+ # import apex
64
+ # model, optimizer = apex.amp.initialize(model.cuda(), optimizer, opt_level="O1")
65
+ # warnings.warn('**** Initializing mixed precision done. ****')
66
+
67
+ # put model on gpus
68
+ if distributed:
69
+ find_unused_parameters = cfg.get('find_unused_parameters', False)
70
+ # Sets the `find_unused_parameters` parameter in
71
+ # torch.nn.parallel.DistributedDataParallel
72
+ model = MMDistributedDataParallel(
73
+ model.cuda(),
74
+ device_ids=[torch.cuda.current_device()],
75
+ broadcast_buffers=False,
76
+ find_unused_parameters=find_unused_parameters)
77
+ else:
78
+ model = MMDataParallel(
79
+ model.cuda(cfg.gpu_ids[0]), device_ids=cfg.gpu_ids)
80
+
81
+ if cfg.get('runner') is None:
82
+ cfg.runner = {
83
+ 'type': 'EpochBasedRunner',
84
+ 'max_epochs': cfg.total_epochs
85
+ }
86
+ warnings.warn(
87
+ 'config is now expected to have a `runner` section, '
88
+ 'please set `runner` in your config.', UserWarning)
89
+
90
+ runner = build_runner(
91
+ cfg.runner,
92
+ default_args=dict(
93
+ model=model,
94
+ batch_processor=None,
95
+ optimizer=optimizer,
96
+ work_dir=cfg.work_dir,
97
+ logger=logger,
98
+ meta=meta))
99
+
100
+ # an ugly walkaround to make the .log and .log.json filenames the same
101
+ runner.timestamp = timestamp
102
+
103
+ # fp16 setting
104
+ fp16_cfg = cfg.get('fp16', None)
105
+ if fp16_cfg is not None:
106
+ optimizer_config = Fp16OptimizerHook(
107
+ **cfg.optimizer_config, **fp16_cfg, distributed=distributed)
108
+ elif distributed and 'type' not in cfg.optimizer_config:
109
+ # optimizer_config = DistOptimizerHook(**cfg.optimizer_config)
110
+ optimizer_config = OptimizerHook(**cfg.optimizer_config)
111
+ else:
112
+ optimizer_config = cfg.optimizer_config
113
+
114
+ # register hooks
115
+ runner.register_training_hooks(cfg.lr_config, optimizer_config,
116
+ cfg.checkpoint_config, cfg.log_config,
117
+ cfg.get('momentum_config', None))
118
+ if distributed and cfg.runner.type=='EpochBasedRunner':
119
+ runner.register_hook(DistSamplerSeedHook())
120
+
121
+ # register eval hooks
122
+ if validate:
123
+ val_dataset = build_dataset(cfg.data.val, dict(test_mode=True))
124
+ val_dataloader = build_dataloader(
125
+ val_dataset,
126
+ samples_per_gpu=cfg.data.samples_per_gpu,
127
+ workers_per_gpu=cfg.data.workers_per_gpu,
128
+ dist=distributed,
129
+ shuffle=False,
130
+ round_up=True)
131
+ eval_cfg = cfg.get('evaluation', {})
132
+ eval_cfg['by_epoch'] = cfg.runner['type'] != 'IterBasedRunner'
133
+ eval_hook = DistEvalHook if distributed else EvalHook
134
+ runner.register_hook(eval_hook(val_dataloader, **eval_cfg), priority='LOW')
135
+
136
+ if cfg.resume_from:
137
+ runner.resume(cfg.resume_from)
138
+ elif cfg.load_from:
139
+ runner.load_checkpoint(cfg.load_from)
140
+ runner.run(data_loaders, cfg.workflow)
CAGE_expression_inference-apvit/apvit_mmcls/core/__init__.py ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ from .evaluation import * # noqa: F401, F403
2
+ from .fp16 import * # noqa: F401, F403
3
+ from .utils import * # noqa: F401, F403
CAGE_expression_inference-apvit/apvit_mmcls/core/evaluation/__init__.py ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ from .eval_hooks import DistEvalHook, EvalHook
2
+ from .mean_ap import average_precision, mAP
3
+ from .multilabel_eval_metrics import average_performance
4
+
5
+ __all__ = [
6
+ 'DistEvalHook', 'EvalHook', 'average_precision', 'mAP',
7
+ 'average_performance'
8
+ ]
CAGE_expression_inference-apvit/apvit_mmcls/core/evaluation/eval_hooks.py ADDED
@@ -0,0 +1,158 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os.path as osp
2
+ from math import inf
3
+
4
+ from mmcv.runner import Hook
5
+ from torch.utils.data import DataLoader
6
+ from mmcls.utils import get_root_logger
7
+
8
+
9
+ class EvalHook(Hook):
10
+ """Evaluation hook.
11
+
12
+ Args:
13
+ dataloader (DataLoader): A PyTorch dataloader.
14
+ interval (int): Evaluation interval (by epochs). Default: 1.
15
+ """
16
+
17
+ def __init__(self, dataloader, interval=1, by_epoch=True, **eval_kwargs):
18
+ if not isinstance(dataloader, DataLoader):
19
+ raise TypeError('dataloader must be a pytorch DataLoader, but got'
20
+ f' {type(dataloader)}')
21
+ self.dataloader = dataloader
22
+ self.interval = interval
23
+ self.eval_kwargs = eval_kwargs
24
+ self.by_epoch = by_epoch
25
+ self.logger = get_root_logger()
26
+
27
+ def after_train_epoch(self, runner):
28
+ if not self.by_epoch or not self.every_n_epochs(runner, self.interval):
29
+ return
30
+ from mmcls.apis import single_gpu_test
31
+ results = single_gpu_test(runner.model, self.dataloader, show=False)
32
+ self.evaluate(runner, results)
33
+
34
+ def after_train_iter(self, runner):
35
+ if self.by_epoch or not self.every_n_iters(runner, self.interval):
36
+ return
37
+ from mmcls.apis import single_gpu_test
38
+ runner.log_buffer.clear()
39
+ results = single_gpu_test(runner.model, self.dataloader, show=False)
40
+ self.evaluate(runner, results)
41
+
42
+ def evaluate(self, runner, results):
43
+ eval_res = self.dataloader.dataset.evaluate(
44
+ results, logger=runner.logger, **self.eval_kwargs)
45
+ for name, val in eval_res.items():
46
+ runner.log_buffer.output[name] = val
47
+ runner.log_buffer.ready = True
48
+ return eval_res
49
+
50
+
51
+ class DistEvalHook(EvalHook):
52
+ """Distributed evaluation hook.
53
+
54
+ Args:
55
+ dataloader (DataLoader): A PyTorch dataloader.
56
+ interval (int): Evaluation interval (by epochs). Default: 1.
57
+ tmpdir (str | None): Temporary directory to save the results of all
58
+ processes. Default: None.
59
+ gpu_collect (bool): Whether to use gpu or cpu to collect results.
60
+ Default: False.
61
+ """
62
+
63
+ def __init__(self,
64
+ dataloader,
65
+ interval=1,
66
+ gpu_collect=True,
67
+ by_epoch=True,
68
+ print_best=True,
69
+ **eval_kwargs):
70
+ if not isinstance(dataloader, DataLoader):
71
+ raise TypeError('dataloader must be a pytorch DataLoader, but got '
72
+ f'{type(dataloader)}')
73
+ super().__init__(dataloader, interval, by_epoch, **eval_kwargs)
74
+ self.dataloader = dataloader
75
+ self.interval = interval
76
+ self.gpu_collect = gpu_collect
77
+ self.by_epoch = by_epoch
78
+ self.eval_kwargs = eval_kwargs
79
+ self.print_best = print_best
80
+
81
+ def before_run(self, runner):
82
+ if self.print_best is not None:
83
+ if runner.meta is None:
84
+ warnings.warn('runner.meta is None. Creating a empty one.')
85
+ runner.meta = dict()
86
+ runner.meta.setdefault('hook_msgs', dict())
87
+
88
+ def before_train_epoch(self, runner):
89
+ return
90
+ # freeze IRNet
91
+ # frozen_blocks = 7
92
+ model = runner.model.module.convert
93
+ model.eval()
94
+ for param in model.parameters():
95
+ param.requires_grad = False
96
+ return
97
+
98
+ if frozen_blocks > 0:
99
+ print(f'IRSE freeze the first {frozen_blocks} blocks, it has {len(model.body)} blocks ')
100
+ model.input_layer.eval()
101
+ print('in freeze', model.input_layer[1].training)
102
+ for param in model.input_layer.parameters():
103
+ param.requires_grad = False
104
+
105
+ for i in range(frozen_blocks):
106
+ m = model.body[i]
107
+ m.eval()
108
+ for param in m.parameters():
109
+ param.requires_grad = False
110
+
111
+ def after_train_epoch(self, runner):
112
+ if not self.by_epoch or not self.every_n_epochs(runner, self.interval):
113
+ return
114
+ from mmcls.apis import multi_gpu_test
115
+ results = multi_gpu_test(
116
+ runner.model,
117
+ self.dataloader,
118
+ tmpdir=osp.join(runner.work_dir, '.eval_hook'),
119
+ gpu_collect=self.gpu_collect)
120
+ if runner.rank == 0:
121
+ print('\n')
122
+ eval_res = self.evaluate(runner, results)
123
+ if self.print_best:
124
+ best_score = runner.meta['hook_msgs'].get('best_score', -inf)
125
+ if 'top-1' not in eval_res:
126
+ return
127
+ acc = eval_res['top-1']
128
+ if acc > best_score:
129
+ self.logger.info(f'top-1 accuracy improved from {best_score} to {acc}')
130
+ runner.meta['hook_msgs']['best_score'] = acc
131
+ runner.save_checkpoint(runner.work_dir, save_optimizer=False, filename_tmpl='best.pth', create_symlink=False)
132
+ else:
133
+ self.logger.info(f'top-1 accuracy did not improve from {best_score}')
134
+
135
+ def after_train_iter(self, runner):
136
+ if self.by_epoch or not self.every_n_iters(runner, self.interval):
137
+ return
138
+ from mmcls.apis import multi_gpu_test
139
+ runner.log_buffer.clear()
140
+ results = multi_gpu_test(
141
+ runner.model,
142
+ self.dataloader,
143
+ tmpdir=osp.join(runner.work_dir, '.eval_hook'),
144
+ gpu_collect=self.gpu_collect)
145
+ if runner.rank == 0:
146
+ print('\n')
147
+ eval_res = self.evaluate(runner, results)
148
+ if self.print_best:
149
+ best_score = runner.meta['hook_msgs'].get('best_score', -inf)
150
+ if 'top-1' not in eval_res:
151
+ return
152
+ acc = eval_res['top-1']
153
+ if acc > best_score:
154
+ self.logger.info(f'top-1 accuracy improved from {best_score} to {acc}')
155
+ runner.meta['hook_msgs']['best_score'] = acc
156
+ runner.save_checkpoint(runner.work_dir, save_optimizer=False, filename_tmpl='best.pth', create_symlink=False)
157
+ else:
158
+ self.logger.info(f'top-1 accuracy did not improve from {best_score}')
CAGE_expression_inference-apvit/apvit_mmcls/core/evaluation/mean_ap.py ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ import torch
3
+
4
+
5
+ def average_precision(pred, target):
6
+ """ Calculate the average precision for a single class
7
+
8
+ AP summarizes a precision-recall curve as the weighted mean of maximum
9
+ precisions obtained for any r'>r, where r is the recall:
10
+
11
+ ..math::
12
+ \\text{AP} = \\sum_n (R_n - R_{n-1}) P_n
13
+
14
+ Note that no approximation is involved since the curve is piecewise
15
+ constant.
16
+
17
+ Args:
18
+ pred (np.ndarray): The model prediction with shape (N, ).
19
+ target (np.ndarray): The target of each prediction with shape (N, ).
20
+
21
+ Returns:
22
+ float: a single float as average precision value.
23
+ """
24
+ eps = np.finfo(np.float32).eps
25
+
26
+ # sort examples
27
+ sort_inds = np.argsort(-pred)
28
+ sort_target = target[sort_inds]
29
+
30
+ # count true positive examples
31
+ pos_inds = sort_target == 1
32
+ tp = np.cumsum(pos_inds)
33
+ total_pos = tp[-1]
34
+
35
+ # count not difficult examples
36
+ pn_inds = sort_target != -1
37
+ pn = np.cumsum(pn_inds)
38
+
39
+ tp[np.logical_not(pos_inds)] = 0
40
+ precision = tp / np.maximum(pn, eps)
41
+ ap = np.sum(precision) / np.maximum(total_pos, eps)
42
+ return ap
43
+
44
+
45
+ def mAP(pred, target):
46
+ """ Calculate the mean average precision with respect of classes
47
+
48
+ Args:
49
+ pred (torch.Tensor | np.ndarray): The model prediction with shape
50
+ (N, C), where C is the number of classes.
51
+ target (torch.Tensor | np.ndarray): The target of each prediction with
52
+ shape (N, C), where C is the number of classes. 1 stands for
53
+ positive examples, 0 stands for negative examples and -1 stands for
54
+ difficult examples.
55
+
56
+ Returns:
57
+ float: A single float as mAP value.
58
+ """
59
+ if isinstance(pred, torch.Tensor) and isinstance(target, torch.Tensor):
60
+ pred = pred.numpy()
61
+ target = target.numpy()
62
+ elif not (isinstance(pred, np.ndarray) and isinstance(target, np.ndarray)):
63
+ raise TypeError('pred and target should both be torch.Tensor or'
64
+ 'np.ndarray')
65
+
66
+ assert pred.shape == \
67
+ target.shape, 'pred and target should be in the same shape.'
68
+ num_classes = pred.shape[1]
69
+ ap = np.zeros(num_classes)
70
+ for k in range(num_classes):
71
+ ap[k] = average_precision(pred[:, k], target[:, k])
72
+ mean_ap = ap.mean() * 100.0
73
+ return mean_ap
CAGE_expression_inference-apvit/apvit_mmcls/core/evaluation/multilabel_eval_metrics.py ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import warnings
2
+
3
+ import numpy as np
4
+ import torch
5
+
6
+
7
+ def average_performance(pred, target, thr=None, k=None):
8
+ """Calculate CP, CR, CF1, OP, OR, OF1, where C stands for per-class
9
+ average, O stands for overall average, P stands for precision, R
10
+ stands for recall and F1 stands for F1-score
11
+
12
+ Args:
13
+ pred (torch.Tensor | np.ndarray): The model prediction with shape
14
+ (N, C), where C is the number of classes.
15
+ target (torch.Tensor | np.ndarray): The target of each prediction with
16
+ shape (N, C), where C is the number of classes. 1 stands for
17
+ positive examples, 0 stands for negative examples and -1 stands for
18
+ difficult examples.
19
+ thr (float): The confidence threshold. Defaults to None.
20
+ k (int): Top-k performance. Note that if thr and k are both given, k
21
+ will be ignored. Defaults to None.
22
+
23
+ Returns:
24
+ tuple: (CP, CR, CF1, OP, OR, OF1)
25
+ """
26
+ if isinstance(pred, torch.Tensor) and isinstance(target, torch.Tensor):
27
+ pred = pred.numpy()
28
+ target = target.numpy()
29
+ elif not (isinstance(pred, np.ndarray) and isinstance(target, np.ndarray)):
30
+ raise TypeError('pred and target should both be torch.Tensor or'
31
+ 'np.ndarray')
32
+ if thr is None and k is None:
33
+ thr = 0.5
34
+ warnings.warn('Neither thr nor k is given, set thr as 0.5 by '
35
+ 'default.')
36
+ elif thr is not None and k is not None:
37
+ warnings.warn('Both thr and k are given, use threshold in favor of '
38
+ 'top-k.')
39
+
40
+ assert pred.shape == \
41
+ target.shape, 'pred and target should be in the same shape.'
42
+
43
+ eps = np.finfo(np.float32).eps
44
+ target[target == -1] = 0
45
+ if thr is not None:
46
+ # a label is predicted positive if the confidence is no lower than thr
47
+ pos_inds = pred >= thr
48
+
49
+ else:
50
+ # top-k labels will be predicted positive for any example
51
+ sort_inds = np.argsort(-pred, axis=1)
52
+ sort_inds_ = sort_inds[:, :k]
53
+ inds = np.indices(sort_inds_.shape)
54
+ pos_inds = np.zeros_like(pred)
55
+ pos_inds[inds[0], sort_inds_] = 1
56
+
57
+ tp = (pos_inds * target) == 1
58
+ fp = (pos_inds * (1 - target)) == 1
59
+ fn = ((1 - pos_inds) * target) == 1
60
+
61
+ precision_class = tp.sum(axis=0) / np.maximum(
62
+ tp.sum(axis=0) + fp.sum(axis=0), eps)
63
+ recall_class = tp.sum(axis=0) / np.maximum(
64
+ tp.sum(axis=0) + fn.sum(axis=0), eps)
65
+ CP = precision_class.mean() * 100.0
66
+ CR = recall_class.mean() * 100.0
67
+ CF1 = 2 * CP * CR / np.maximum(CP + CR, eps)
68
+ OP = tp.sum() / np.maximum(tp.sum() + fp.sum(), eps) * 100.0
69
+ OR = tp.sum() / np.maximum(tp.sum() + fn.sum(), eps) * 100.0
70
+ OF1 = 2 * OP * OR / np.maximum(OP + OR, eps)
71
+ return CP, CR, CF1, OP, OR, OF1
CAGE_expression_inference-apvit/apvit_mmcls/core/fp16/__init__.py ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ from .decorators import auto_fp16, force_fp32
2
+ from .hooks import Fp16OptimizerHook, wrap_fp16_model
3
+
4
+ __all__ = ['auto_fp16', 'force_fp32', 'Fp16OptimizerHook', 'wrap_fp16_model']
CAGE_expression_inference-apvit/apvit_mmcls/core/fp16/decorators.py ADDED
@@ -0,0 +1,160 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import functools
2
+ from inspect import getfullargspec
3
+
4
+ import torch
5
+
6
+ from .utils import cast_tensor_type
7
+
8
+
9
+ def auto_fp16(apply_to=None, out_fp32=False):
10
+ """Decorator to enable fp16 training automatically.
11
+
12
+ This decorator is useful when you write custom modules and want to support
13
+ mixed precision training. If inputs arguments are fp32 tensors, they will
14
+ be converted to fp16 automatically. Arguments other than fp32 tensors are
15
+ ignored.
16
+
17
+ Args:
18
+ apply_to (Iterable, optional): The argument names to be converted.
19
+ `None` indicates all arguments.
20
+ out_fp32 (bool): Whether to convert the output back to fp32.
21
+
22
+ :Example:
23
+
24
+ class MyModule1(nn.Module)
25
+
26
+ # Convert x and y to fp16
27
+ @auto_fp16()
28
+ def forward(self, x, y):
29
+ pass
30
+
31
+ class MyModule2(nn.Module):
32
+
33
+ # convert pred to fp16
34
+ @auto_fp16(apply_to=('pred', ))
35
+ def do_something(self, pred, others):
36
+ pass
37
+ """
38
+
39
+ def auto_fp16_wrapper(old_func):
40
+
41
+ @functools.wraps(old_func)
42
+ def new_func(*args, **kwargs):
43
+ # check if the module has set the attribute `fp16_enabled`, if not,
44
+ # just fallback to the original method.
45
+ if not isinstance(args[0], torch.nn.Module):
46
+ raise TypeError('@auto_fp16 can only be used to decorate the '
47
+ 'method of nn.Module')
48
+ if not (hasattr(args[0], 'fp16_enabled') and args[0].fp16_enabled):
49
+ return old_func(*args, **kwargs)
50
+ # get the arg spec of the decorated method
51
+ args_info = getfullargspec(old_func)
52
+ # get the argument names to be casted
53
+ args_to_cast = args_info.args if apply_to is None else apply_to
54
+ # convert the args that need to be processed
55
+ new_args = []
56
+ # NOTE: default args are not taken into consideration
57
+ if args:
58
+ arg_names = args_info.args[:len(args)]
59
+ for i, arg_name in enumerate(arg_names):
60
+ if arg_name in args_to_cast:
61
+ new_args.append(
62
+ cast_tensor_type(args[i], torch.float, torch.half))
63
+ else:
64
+ new_args.append(args[i])
65
+ # convert the kwargs that need to be processed
66
+ new_kwargs = {}
67
+ if kwargs:
68
+ for arg_name, arg_value in kwargs.items():
69
+ if arg_name in args_to_cast:
70
+ new_kwargs[arg_name] = cast_tensor_type(
71
+ arg_value, torch.float, torch.half)
72
+ else:
73
+ new_kwargs[arg_name] = arg_value
74
+ # apply converted arguments to the decorated method
75
+ output = old_func(*new_args, **new_kwargs)
76
+ # cast the results back to fp32 if necessary
77
+ if out_fp32:
78
+ output = cast_tensor_type(output, torch.half, torch.float)
79
+ return output
80
+
81
+ return new_func
82
+
83
+ return auto_fp16_wrapper
84
+
85
+
86
+ def force_fp32(apply_to=None, out_fp16=False):
87
+ """Decorator to convert input arguments to fp32 in force.
88
+
89
+ This decorator is useful when you write custom modules and want to support
90
+ mixed precision training. If there are some inputs that must be processed
91
+ in fp32 mode, then this decorator can handle it. If inputs arguments are
92
+ fp16 tensors, they will be converted to fp32 automatically. Arguments other
93
+ than fp16 tensors are ignored.
94
+
95
+ Args:
96
+ apply_to (Iterable, optional): The argument names to be converted.
97
+ `None` indicates all arguments.
98
+ out_fp16 (bool): Whether to convert the output back to fp16.
99
+
100
+ :Example:
101
+
102
+ class MyModule1(nn.Module)
103
+
104
+ # Convert x and y to fp32
105
+ @force_fp32()
106
+ def loss(self, x, y):
107
+ pass
108
+
109
+ class MyModule2(nn.Module):
110
+
111
+ # convert pred to fp32
112
+ @force_fp32(apply_to=('pred', ))
113
+ def post_process(self, pred, others):
114
+ pass
115
+ """
116
+
117
+ def force_fp32_wrapper(old_func):
118
+
119
+ @functools.wraps(old_func)
120
+ def new_func(*args, **kwargs):
121
+ # check if the module has set the attribute `fp16_enabled`, if not,
122
+ # just fallback to the original method.
123
+ if not isinstance(args[0], torch.nn.Module):
124
+ raise TypeError('@force_fp32 can only be used to decorate the '
125
+ 'method of nn.Module')
126
+ if not (hasattr(args[0], 'fp16_enabled') and args[0].fp16_enabled):
127
+ return old_func(*args, **kwargs)
128
+ # get the arg spec of the decorated method
129
+ args_info = getfullargspec(old_func)
130
+ # get the argument names to be casted
131
+ args_to_cast = args_info.args if apply_to is None else apply_to
132
+ # convert the args that need to be processed
133
+ new_args = []
134
+ if args:
135
+ arg_names = args_info.args[:len(args)]
136
+ for i, arg_name in enumerate(arg_names):
137
+ if arg_name in args_to_cast:
138
+ new_args.append(
139
+ cast_tensor_type(args[i], torch.half, torch.float))
140
+ else:
141
+ new_args.append(args[i])
142
+ # convert the kwargs that need to be processed
143
+ new_kwargs = dict()
144
+ if kwargs:
145
+ for arg_name, arg_value in kwargs.items():
146
+ if arg_name in args_to_cast:
147
+ new_kwargs[arg_name] = cast_tensor_type(
148
+ arg_value, torch.half, torch.float)
149
+ else:
150
+ new_kwargs[arg_name] = arg_value
151
+ # apply converted arguments to the decorated method
152
+ output = old_func(*new_args, **new_kwargs)
153
+ # cast the results back to fp32 if necessary
154
+ if out_fp16:
155
+ output = cast_tensor_type(output, torch.float, torch.half)
156
+ return output
157
+
158
+ return new_func
159
+
160
+ return force_fp32_wrapper
CAGE_expression_inference-apvit/apvit_mmcls/core/fp16/hooks.py ADDED
@@ -0,0 +1,132 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import copy
2
+
3
+ import torch
4
+ import torch.nn as nn
5
+ from mmcv.runner import OptimizerHook
6
+ from mmcv.utils.parrots_wrapper import _BatchNorm
7
+
8
+ from ..utils import allreduce_grads
9
+ from .utils import cast_tensor_type
10
+
11
+
12
+ class Fp16OptimizerHook(OptimizerHook):
13
+ """FP16 optimizer hook.
14
+
15
+ The steps of fp16 optimizer is as follows.
16
+ 1. Scale the loss value.
17
+ 2. BP in the fp16 model.
18
+ 2. Copy gradients from fp16 model to fp32 weights.
19
+ 3. Update fp32 weights.
20
+ 4. Copy updated parameters from fp32 weights to fp16 model.
21
+
22
+ Refer to https://arxiv.org/abs/1710.03740 for more details.
23
+
24
+ Args:
25
+ loss_scale (float): Scale factor multiplied with loss.
26
+ """
27
+
28
+ def __init__(self,
29
+ grad_clip=None,
30
+ coalesce=True,
31
+ bucket_size_mb=-1,
32
+ loss_scale=512.,
33
+ distributed=True):
34
+ self.grad_clip = grad_clip
35
+ self.coalesce = coalesce
36
+ self.bucket_size_mb = bucket_size_mb
37
+ self.loss_scale = loss_scale
38
+ self.distributed = distributed
39
+
40
+ def before_run(self, runner):
41
+ # keep a copy of fp32 weights
42
+ runner.optimizer.param_groups = copy.deepcopy(
43
+ runner.optimizer.param_groups)
44
+ # convert model to fp16
45
+ wrap_fp16_model(runner.model)
46
+
47
+ def copy_grads_to_fp32(self, fp16_net, fp32_weights):
48
+ """Copy gradients from fp16 model to fp32 weight copy."""
49
+ for fp32_param, fp16_param in zip(fp32_weights, fp16_net.parameters()):
50
+ if fp16_param.grad is not None:
51
+ if fp32_param.grad is None:
52
+ fp32_param.grad = fp32_param.data.new(fp32_param.size())
53
+ fp32_param.grad.copy_(fp16_param.grad)
54
+
55
+ def copy_params_to_fp16(self, fp16_net, fp32_weights):
56
+ """Copy updated params from fp32 weight copy to fp16 model."""
57
+ for fp16_param, fp32_param in zip(fp16_net.parameters(), fp32_weights):
58
+ fp16_param.data.copy_(fp32_param.data)
59
+
60
+ def after_train_iter(self, runner):
61
+ # clear grads of last iteration
62
+ runner.model.zero_grad()
63
+ runner.optimizer.zero_grad()
64
+ # scale the loss value
65
+ scaled_loss = runner.outputs['loss'] * self.loss_scale
66
+ scaled_loss.backward()
67
+ # copy fp16 grads in the model to fp32 params in the optimizer
68
+ fp32_weights = []
69
+ for param_group in runner.optimizer.param_groups:
70
+ fp32_weights += param_group['params']
71
+ self.copy_grads_to_fp32(runner.model, fp32_weights)
72
+ # allreduce grads
73
+ if self.distributed:
74
+ allreduce_grads(fp32_weights, self.coalesce, self.bucket_size_mb)
75
+ # scale the gradients back
76
+ for param in fp32_weights:
77
+ if param.grad is not None:
78
+ param.grad.div_(self.loss_scale)
79
+ if self.grad_clip is not None:
80
+ grad_norm = self.clip_grads(fp32_weights)
81
+ if grad_norm is not None:
82
+ # Add grad norm to the logger
83
+ runner.log_buffer.update({'grad_norm': float(grad_norm)},
84
+ runner.outputs['num_samples'])
85
+ # update fp32 params
86
+ runner.optimizer.step()
87
+ # copy fp32 params to the fp16 model
88
+ self.copy_params_to_fp16(runner.model, fp32_weights)
89
+
90
+
91
+ def wrap_fp16_model(model):
92
+ # convert model to fp16
93
+ model.half()
94
+ # patch the normalization layers to make it work in fp32 mode
95
+ patch_norm_fp32(model)
96
+ # set `fp16_enabled` flag
97
+ for m in model.modules():
98
+ if hasattr(m, 'fp16_enabled'):
99
+ m.fp16_enabled = True
100
+
101
+
102
+ def patch_norm_fp32(module):
103
+ if isinstance(module, (_BatchNorm, nn.GroupNorm)):
104
+ module.float()
105
+ module.forward = patch_forward_method(module.forward, torch.half,
106
+ torch.float)
107
+ for child in module.children():
108
+ patch_norm_fp32(child)
109
+ return module
110
+
111
+
112
+ def patch_forward_method(func, src_type, dst_type, convert_output=True):
113
+ """Patch the forward method of a module.
114
+
115
+ Args:
116
+ func (callable): The original forward method.
117
+ src_type (torch.dtype): Type of input arguments to be converted from.
118
+ dst_type (torch.dtype): Type of input arguments to be converted to.
119
+ convert_output (bool): Whether to convert the output back to src_type.
120
+
121
+ Returns:
122
+ callable: The patched forward method.
123
+ """
124
+
125
+ def new_forward(*args, **kwargs):
126
+ output = func(*cast_tensor_type(args, src_type, dst_type),
127
+ **cast_tensor_type(kwargs, src_type, dst_type))
128
+ if convert_output:
129
+ output = cast_tensor_type(output, dst_type, src_type)
130
+ return output
131
+
132
+ return new_forward
CAGE_expression_inference-apvit/apvit_mmcls/core/fp16/utils.py ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from collections import abc
2
+
3
+ import numpy as np
4
+ import torch
5
+
6
+
7
+ def cast_tensor_type(inputs, src_type, dst_type):
8
+ if isinstance(inputs, torch.Tensor):
9
+ return inputs.to(dst_type)
10
+ elif isinstance(inputs, str):
11
+ return inputs
12
+ elif isinstance(inputs, np.ndarray):
13
+ return inputs
14
+ elif isinstance(inputs, abc.Mapping):
15
+ return type(inputs)({
16
+ k: cast_tensor_type(v, src_type, dst_type)
17
+ for k, v in inputs.items()
18
+ })
19
+ elif isinstance(inputs, abc.Iterable):
20
+ return type(inputs)(
21
+ cast_tensor_type(item, src_type, dst_type) for item in inputs)
22
+ else:
23
+ return inputs
CAGE_expression_inference-apvit/apvit_mmcls/core/utils/__init__.py ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ from .dist_utils import DistOptimizerHook, allreduce_grads
2
+ from .misc import multi_apply
3
+
4
+ __all__ = ['allreduce_grads', 'DistOptimizerHook', 'multi_apply']
CAGE_expression_inference-apvit/apvit_mmcls/core/utils/dist_utils.py ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from collections import OrderedDict
2
+
3
+ import torch.distributed as dist
4
+ from mmcv.runner import OptimizerHook
5
+ from torch._utils import (_flatten_dense_tensors, _take_tensors,
6
+ _unflatten_dense_tensors)
7
+
8
+
9
+ def _allreduce_coalesced(tensors, world_size, bucket_size_mb=-1):
10
+ if bucket_size_mb > 0:
11
+ bucket_size_bytes = bucket_size_mb * 1024 * 1024
12
+ buckets = _take_tensors(tensors, bucket_size_bytes)
13
+ else:
14
+ buckets = OrderedDict()
15
+ for tensor in tensors:
16
+ tp = tensor.type()
17
+ if tp not in buckets:
18
+ buckets[tp] = []
19
+ buckets[tp].append(tensor)
20
+ buckets = buckets.values()
21
+
22
+ for bucket in buckets:
23
+ flat_tensors = _flatten_dense_tensors(bucket)
24
+ dist.all_reduce(flat_tensors)
25
+ flat_tensors.div_(world_size)
26
+ for tensor, synced in zip(
27
+ bucket, _unflatten_dense_tensors(flat_tensors, bucket)):
28
+ tensor.copy_(synced)
29
+
30
+
31
+ def allreduce_grads(params, coalesce=True, bucket_size_mb=-1):
32
+ grads = [
33
+ param.grad.data for param in params
34
+ if param.requires_grad and param.grad is not None
35
+ ]
36
+ world_size = dist.get_world_size()
37
+ if coalesce:
38
+ _allreduce_coalesced(grads, world_size, bucket_size_mb)
39
+ else:
40
+ for tensor in grads:
41
+ dist.all_reduce(tensor.div_(world_size))
42
+
43
+
44
+ class DistOptimizerHook(OptimizerHook):
45
+
46
+ def __init__(self, grad_clip=None, coalesce=True, bucket_size_mb=-1):
47
+ self.grad_clip = grad_clip
48
+ self.coalesce = coalesce
49
+ self.bucket_size_mb = bucket_size_mb
50
+
51
+ def after_train_iter(self, runner):
52
+ runner.optimizer.zero_grad()
53
+ runner.outputs['loss'].backward()
54
+ if self.grad_clip is not None:
55
+ self.clip_grads(runner.model.parameters())
56
+ runner.optimizer.step()
CAGE_expression_inference-apvit/apvit_mmcls/core/utils/misc.py ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ from functools import partial
2
+
3
+
4
+ def multi_apply(func, *args, **kwargs):
5
+ pfunc = partial(func, **kwargs) if kwargs else func
6
+ map_results = map(pfunc, *args)
7
+ return tuple(map(list, zip(*map_results)))
CAGE_expression_inference-apvit/apvit_mmcls/datasets/__init__.py ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from .base_dataset import BaseDataset
2
+ from .builder import DATASETS, PIPELINES, build_dataloader, build_dataset
3
+ from .cifar import CIFAR10, CIFAR100
4
+ from .dataset_wrappers import (ClassBalancedDataset, ConcatDataset,
5
+ RepeatDataset)
6
+ from .imagenet import ImageNet
7
+ from .mnist import MNIST, FashionMNIST
8
+ from .samplers import DistributedSampler
9
+ from .raf import RAF
10
+
11
+ __all__ = [
12
+ 'BaseDataset', 'ImageNet', 'CIFAR10', 'CIFAR100', 'MNIST', 'FashionMNIST',
13
+ 'build_dataloader', 'build_dataset', 'Compose', 'DistributedSampler',
14
+ 'ConcatDataset', 'RepeatDataset', 'ClassBalancedDataset', 'DATASETS',
15
+ 'PIPELINES', 'RAF',
16
+ ]
CAGE_expression_inference-apvit/apvit_mmcls/datasets/base_dataset.py ADDED
@@ -0,0 +1,185 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import copy
2
+ from abc import ABCMeta, abstractmethod
3
+ import os
4
+ from shutil import copyfile
5
+
6
+ import mmcv
7
+ import numpy as np
8
+ from torch.utils.data import Dataset
9
+
10
+ from mmcls.models.losses import accuracy, f1_score, precision, recall
11
+ from mmcls.models.losses.eval_metrics import class_accuracy
12
+ from .pipelines import Compose
13
+
14
+
15
+ class BaseDataset(Dataset, metaclass=ABCMeta):
16
+ """Base dataset.
17
+
18
+ Args:
19
+ data_prefix (str): the prefix of data path
20
+ pipeline (list): a list of dict, where each element represents
21
+ a operation defined in `mmcls.datasets.pipelines`
22
+ ann_file (str | None): the annotation file. When ann_file is str,
23
+ the subclass is expected to read from the ann_file. When ann_file
24
+ is None, the subclass is expected to read according to data_prefix
25
+ test_mode (bool): in train mode or test mode
26
+ """
27
+
28
+ CLASSES = None
29
+
30
+ def __init__(self,
31
+ data_prefix,
32
+ pipeline,
33
+ classes=None,
34
+ ann_file=None,
35
+ test_mode=False):
36
+ super(BaseDataset, self).__init__()
37
+
38
+ self.ann_file = ann_file
39
+ self.data_prefix = data_prefix
40
+ self.test_mode = test_mode
41
+ self.pipeline = Compose(pipeline)
42
+ self.data_infos = self.load_annotations()
43
+ # self.data_infos = self.load_exp_and_au_annotations()
44
+ self.CLASSES = self.get_classes(classes)
45
+ if os.environ.get('DEBUG_MODE', '0') == '1':
46
+ self.data_infos = self.data_infos[:30]
47
+
48
+ @abstractmethod
49
+ def load_annotations(self):
50
+ pass
51
+
52
+ @property
53
+ def class_to_idx(self):
54
+ """Map mapping class name to class index.
55
+
56
+ Returns:
57
+ dict: mapping from class name to class index.
58
+ """
59
+
60
+ return {_class: i for i, _class in enumerate(self.CLASSES)}
61
+
62
+ def get_gt_labels(self):
63
+ """Get all ground-truth labels (categories).
64
+
65
+ Returns:
66
+ list[int]: categories for all images.
67
+ """
68
+
69
+ gt_labels = np.array([data['gt_label'] for data in self.data_infos])
70
+ return gt_labels
71
+
72
+ def get_coarse_labels(self):
73
+ coarse_labels = np.array([data['coarse_label'] for data in self.data_infos])
74
+ return coarse_labels
75
+
76
+ def get_cat_ids(self, idx):
77
+ """Get category id by index.
78
+
79
+ Args:
80
+ idx (int): Index of data.
81
+
82
+ Returns:
83
+ int: Image category of specified index.
84
+ """
85
+
86
+ return (int(self.data_infos[idx]['gt_label'].astype(np.int)), )
87
+
88
+ def prepare_data(self, idx):
89
+ results = copy.deepcopy(self.data_infos[idx])
90
+ return self.pipeline(results)
91
+
92
+ def __len__(self):
93
+ return len(self.data_infos)
94
+
95
+ def __getitem__(self, idx):
96
+ return self.prepare_data(idx)
97
+
98
+ @classmethod
99
+ def get_classes(cls, classes=None):
100
+ """Get class names of current dataset.
101
+ Args:
102
+ classes (Sequence[str] | str | None): If classes is None, use
103
+ default CLASSES defined by builtin dataset. If classes is a
104
+ string, take it as a file name. The file contains the name of
105
+ classes where each line contains one class name. If classes is
106
+ a tuple or list, override the CLASSES defined by the dataset.
107
+
108
+ Returns:
109
+ tuple[str] or list[str]: Names of categories of the dataset.
110
+ """
111
+ if classes is None:
112
+ return cls.CLASSES
113
+
114
+ if isinstance(classes, str):
115
+ # take it as a file path
116
+ class_names = mmcv.list_from_file(classes)
117
+ elif isinstance(classes, (tuple, list)):
118
+ class_names = classes
119
+ else:
120
+ raise ValueError(f'Unsupported type {type(classes)} of classes.')
121
+
122
+ return class_names
123
+
124
+ def evaluate(self,
125
+ results,
126
+ metric='accuracy',
127
+ metric_options={'topk': (1, 2)},
128
+ logger=None):
129
+ """Evaluate the dataset.
130
+
131
+ Args:
132
+ results (list): Testing results of the dataset.
133
+ metric (str | list[str]): Metrics to be evaluated.
134
+ Default value is `accuracy`.
135
+ logger (logging.Logger | None | str): Logger used for printing
136
+ related information during evaluation. Default: None.
137
+ Returns:
138
+ dict: evaluation results
139
+ """
140
+ if isinstance(metric, str):
141
+ metrics = [metric]
142
+ else:
143
+ metrics = metric
144
+ allowed_metrics = ['accuracy', 'precision', 'recall', 'f1_score', 'class_accuracy']
145
+ eval_results = {}
146
+ for metric in metrics:
147
+ if metric not in allowed_metrics:
148
+ raise KeyError(f'metric {metric} is not supported.')
149
+ results = np.vstack(results)
150
+ gt_labels = self.get_gt_labels()
151
+ num_imgs = len(results)
152
+ assert len(gt_labels) == num_imgs, f'{len(gt_labels)}, {num_imgs}'
153
+ # convert gt_labels to another dataset format for cross-dataset test
154
+ # raf2affect_dict = [6, 3, 4, 0, 1, 2, 5] # RAF -> AffectNet实验需要将RAF标签修改为AffectNet的标签
155
+ # affect2raf_dict = [3, 4, 5, 1, 2, 6, 0]
156
+ # raf2ferplus_dict = [6,3,0,4,5,2,1,None]
157
+ # gt_labels = [raf2ferplus_dict[i] for i in gt_labels]
158
+ # # specific process for RAF -> FERPlus
159
+ # results = [results[i] for i in range(len(results)) if gt_labels[i] is not None]
160
+ # gt_labels = [gt_labels[i] for i in range(len(gt_labels)) if gt_labels[i] is not None]
161
+ # results = np.array(results)
162
+ # gt_labels = np.array(gt_labels)
163
+
164
+ if metric == 'accuracy':
165
+ topk = metric_options.get('topk')
166
+ acc = accuracy(results, gt_labels, topk)
167
+ eval_result = {f'top-{k}': a.item() for k, a in zip(topk, acc)}
168
+ elif metric == 'precision':
169
+ precision_value = precision(results, gt_labels)
170
+ eval_result = {'precision': precision_value}
171
+ elif metric == 'recall':
172
+ recall_value = recall(results, gt_labels)
173
+ eval_result = {'recall': recall_value}
174
+ elif metric == 'f1_score':
175
+ f1_score_value = f1_score(results, gt_labels)
176
+ eval_result = {'f1_score': f1_score_value}
177
+ elif metric == 'class_accuracy':
178
+ class_accuracy_value = class_accuracy(results, gt_labels, self.CLASSES)
179
+ print('\n')
180
+ for name, val in zip(self.CLASSES, class_accuracy_value):
181
+ print(f'{name}: \t{val}')
182
+ print('\n')
183
+ eval_result = dict()
184
+ eval_results.update(eval_result)
185
+ return eval_results
CAGE_expression_inference-apvit/apvit_mmcls/datasets/builder.py ADDED
@@ -0,0 +1,110 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import platform
2
+ import random
3
+ from functools import partial
4
+
5
+ import numpy as np
6
+ from mmcv.parallel import collate
7
+ from mmcv.runner import get_dist_info
8
+ from mmcv.utils import Registry, build_from_cfg
9
+ from torch.utils.data import DataLoader
10
+
11
+ from .samplers import DistributedSampler
12
+
13
+ if platform.system() != 'Windows':
14
+ # https://github.com/pytorch/pytorch/issues/973
15
+ import resource
16
+ rlimit = resource.getrlimit(resource.RLIMIT_NOFILE)
17
+ hard_limit = rlimit[1]
18
+ soft_limit = min(4096, hard_limit)
19
+ resource.setrlimit(resource.RLIMIT_NOFILE, (soft_limit, hard_limit))
20
+
21
+ DATASETS = Registry('dataset')
22
+ PIPELINES = Registry('pipeline')
23
+
24
+
25
+ def build_dataset(cfg, default_args=None):
26
+ from .dataset_wrappers import (ConcatDataset, RepeatDataset,
27
+ ClassBalancedDataset)
28
+ cfg = cfg.copy()
29
+ if isinstance(cfg, (list, tuple)):
30
+ dataset = ConcatDataset([build_dataset(c, default_args) for c in cfg])
31
+ elif cfg['type'] == 'RepeatDataset':
32
+ dataset = RepeatDataset(
33
+ build_dataset(cfg['dataset'], default_args), cfg['times'])
34
+ elif cfg['type'] == 'ClassBalancedDataset':
35
+ ds = build_dataset(cfg['dataset'], default_args)
36
+ cfg['dataset'] = ds
37
+ dataset = ClassBalancedDataset(**cfg)
38
+ else:
39
+ dataset = build_from_cfg(cfg, DATASETS, default_args)
40
+
41
+ return dataset
42
+
43
+
44
+ def build_dataloader(dataset,
45
+ samples_per_gpu,
46
+ workers_per_gpu,
47
+ num_gpus=1,
48
+ dist=True,
49
+ shuffle=True,
50
+ round_up=True,
51
+ seed=None,
52
+ **kwargs):
53
+ """Build PyTorch DataLoader.
54
+
55
+ In distributed training, each GPU/process has a dataloader.
56
+ In non-distributed training, there is only one dataloader for all GPUs.
57
+
58
+ Args:
59
+ dataset (Dataset): A PyTorch dataset.
60
+ samples_per_gpu (int): Number of training samples on each GPU, i.e.,
61
+ batch size of each GPU.
62
+ workers_per_gpu (int): How many subprocesses to use for data loading
63
+ for each GPU.
64
+ num_gpus (int): Number of GPUs. Only used in non-distributed training.
65
+ dist (bool): Distributed training/test or not. Default: True.
66
+ shuffle (bool): Whether to shuffle the data at every epoch.
67
+ Default: True.
68
+ round_up (bool): Whether to round up the length of dataset by adding
69
+ extra samples to make it evenly divisible. Default: True.
70
+ kwargs: any keyword argument to be used to initialize DataLoader
71
+
72
+ Returns:
73
+ DataLoader: A PyTorch dataloader.
74
+ """
75
+ rank, world_size = get_dist_info()
76
+ if dist:
77
+ sampler = DistributedSampler(
78
+ dataset, world_size, rank, shuffle=shuffle, round_up=round_up)
79
+ shuffle = False
80
+ batch_size = samples_per_gpu
81
+ num_workers = workers_per_gpu
82
+ else:
83
+ sampler = None
84
+ batch_size = num_gpus * samples_per_gpu
85
+ num_workers = num_gpus * workers_per_gpu
86
+
87
+ init_fn = partial(
88
+ worker_init_fn, num_workers=num_workers, rank=rank,
89
+ seed=seed) if seed is not None else None
90
+
91
+ data_loader = DataLoader(
92
+ dataset,
93
+ batch_size=batch_size,
94
+ sampler=sampler,
95
+ num_workers=num_workers,
96
+ collate_fn=partial(collate, samples_per_gpu=samples_per_gpu),
97
+ pin_memory=False,
98
+ shuffle=shuffle,
99
+ worker_init_fn=init_fn,
100
+ **kwargs)
101
+
102
+ return data_loader
103
+
104
+
105
+ def worker_init_fn(worker_id, num_workers, rank, seed):
106
+ # The seed of each worker equals to
107
+ # num_worker * rank + worker_id + user_seed
108
+ worker_seed = num_workers * rank + worker_id + seed
109
+ np.random.seed(worker_seed)
110
+ random.seed(worker_seed)
CAGE_expression_inference-apvit/apvit_mmcls/datasets/cifar.py ADDED
@@ -0,0 +1,123 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import os.path
3
+ import pickle
4
+
5
+ import numpy as np
6
+
7
+ from .base_dataset import BaseDataset
8
+ from .builder import DATASETS
9
+ from .utils import check_integrity, download_and_extract_archive
10
+
11
+
12
+ @DATASETS.register_module()
13
+ class CIFAR10(BaseDataset):
14
+ """`CIFAR10 <https://www.cs.toronto.edu/~kriz/cifar.html>`_ Dataset.
15
+
16
+ This implementation is modified from
17
+ https://github.com/pytorch/vision/blob/master/torchvision/datasets/cifar.py # noqa: E501
18
+ """
19
+
20
+ base_folder = 'cifar-10-batches-py'
21
+ url = 'https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz'
22
+ filename = 'cifar-10-python.tar.gz'
23
+ tgz_md5 = 'c58f30108f718f92721af3b95e74349a'
24
+ train_list = [
25
+ ['data_batch_1', 'c99cafc152244af753f735de768cd75f'],
26
+ ['data_batch_2', 'd4bba439e000b95fd0a9bffe97cbabec'],
27
+ ['data_batch_3', '54ebc095f3ab1f0389bbae665268c751'],
28
+ ['data_batch_4', '634d18415352ddfa80567beed471001a'],
29
+ ['data_batch_5', '482c414d41f54cd18b22e5b47cb7c3cb'],
30
+ ]
31
+
32
+ test_list = [
33
+ ['test_batch', '40351d587109b95175f43aff81a1287e'],
34
+ ]
35
+ meta = {
36
+ 'filename': 'batches.meta',
37
+ 'key': 'label_names',
38
+ 'md5': '5ff9c542aee3614f3951f8cda6e48888',
39
+ }
40
+
41
+ def load_annotations(self):
42
+
43
+ if not self._check_integrity():
44
+ download_and_extract_archive(
45
+ self.url,
46
+ self.data_prefix,
47
+ filename=self.filename,
48
+ md5=self.tgz_md5)
49
+
50
+ if not self.test_mode:
51
+ downloaded_list = self.train_list
52
+ else:
53
+ downloaded_list = self.test_list
54
+
55
+ self.imgs = []
56
+ self.gt_labels = []
57
+
58
+ # load the picked numpy arrays
59
+ for file_name, checksum in downloaded_list:
60
+ file_path = os.path.join(self.data_prefix, self.base_folder,
61
+ file_name)
62
+ with open(file_path, 'rb') as f:
63
+ entry = pickle.load(f, encoding='latin1')
64
+ self.imgs.append(entry['data'])
65
+ if 'labels' in entry:
66
+ self.gt_labels.extend(entry['labels'])
67
+ else:
68
+ self.gt_labels.extend(entry['fine_labels'])
69
+
70
+ self.imgs = np.vstack(self.imgs).reshape(-1, 3, 32, 32)
71
+ self.imgs = self.imgs.transpose((0, 2, 3, 1)) # convert to HWC
72
+
73
+ self._load_meta()
74
+
75
+ data_infos = []
76
+ for img, gt_label in zip(self.imgs, self.gt_labels):
77
+ gt_label = np.array(gt_label, dtype=np.int64)
78
+ info = {'img': img, 'gt_label': gt_label}
79
+ data_infos.append(info)
80
+ return data_infos
81
+
82
+ def _load_meta(self):
83
+ path = os.path.join(self.data_prefix, self.base_folder,
84
+ self.meta['filename'])
85
+ if not check_integrity(path, self.meta['md5']):
86
+ raise RuntimeError(
87
+ 'Dataset metadata file not found or corrupted.' +
88
+ ' You can use download=True to download it')
89
+ with open(path, 'rb') as infile:
90
+ data = pickle.load(infile, encoding='latin1')
91
+ self.CLASSES = data[self.meta['key']]
92
+
93
+ def _check_integrity(self):
94
+ root = self.data_prefix
95
+ for fentry in (self.train_list + self.test_list):
96
+ filename, md5 = fentry[0], fentry[1]
97
+ fpath = os.path.join(root, self.base_folder, filename)
98
+ if not check_integrity(fpath, md5):
99
+ return False
100
+ return True
101
+
102
+
103
+ @DATASETS.register_module()
104
+ class CIFAR100(CIFAR10):
105
+ """`CIFAR100 <https://www.cs.toronto.edu/~kriz/cifar.html>`_ Dataset.
106
+ """
107
+
108
+ base_folder = 'cifar-100-python'
109
+ url = 'https://www.cs.toronto.edu/~kriz/cifar-100-python.tar.gz'
110
+ filename = 'cifar-100-python.tar.gz'
111
+ tgz_md5 = 'eb9058c3a382ffc7106e4002c42a8d85'
112
+ train_list = [
113
+ ['train', '16019d7e3df5f24257cddd939b257f8d'],
114
+ ]
115
+
116
+ test_list = [
117
+ ['test', 'f0ef6b0ae62326f3e7ffdfab6717acfc'],
118
+ ]
119
+ meta = {
120
+ 'filename': 'meta',
121
+ 'key': 'fine_label_names',
122
+ 'md5': '7973b15100ade9c7d40fb424638fde48',
123
+ }
CAGE_expression_inference-apvit/apvit_mmcls/datasets/dataset_wrappers.py ADDED
@@ -0,0 +1,173 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import bisect
2
+ import math
3
+ from collections import defaultdict
4
+
5
+ import numpy as np
6
+ from torch.utils.data.dataset import ConcatDataset as _ConcatDataset
7
+
8
+ from .builder import DATASETS
9
+
10
+
11
+ @DATASETS.register_module()
12
+ class ConcatDataset(_ConcatDataset):
13
+ """A wrapper of concatenated dataset.
14
+
15
+ Same as :obj:`torch.utils.data.dataset.ConcatDataset`, but
16
+ add `get_cat_ids` function.
17
+
18
+ Args:
19
+ datasets (list[:obj:`Dataset`]): A list of datasets.
20
+ """
21
+
22
+ def __init__(self, datasets):
23
+ super(ConcatDataset, self).__init__(datasets)
24
+ self.CLASSES = datasets[0].CLASSES
25
+
26
+ def get_cat_ids(self, idx):
27
+ if idx < 0:
28
+ if -idx > len(self):
29
+ raise ValueError(
30
+ 'absolute value of index should not exceed dataset length')
31
+ idx = len(self) + idx
32
+ dataset_idx = bisect.bisect_right(self.cumulative_sizes, idx)
33
+ if dataset_idx == 0:
34
+ sample_idx = idx
35
+ else:
36
+ sample_idx = idx - self.cumulative_sizes[dataset_idx - 1]
37
+ return self.datasets[dataset_idx].get_cat_ids(sample_idx)
38
+
39
+
40
+ @DATASETS.register_module()
41
+ class RepeatDataset(object):
42
+ """A wrapper of repeated dataset.
43
+
44
+ The length of repeated dataset will be `times` larger than the original
45
+ dataset. This is useful when the data loading time is long but the dataset
46
+ is small. Using RepeatDataset can reduce the data loading time between
47
+ epochs.
48
+
49
+ Args:
50
+ dataset (:obj:`Dataset`): The dataset to be repeated.
51
+ times (int): Repeat times.
52
+ """
53
+
54
+ def __init__(self, dataset, times):
55
+ self.dataset = dataset
56
+ self.times = times
57
+ self.CLASSES = dataset.CLASSES
58
+
59
+ self._ori_len = len(self.dataset)
60
+
61
+ def __getitem__(self, idx):
62
+ return self.dataset[idx % self._ori_len]
63
+
64
+ def get_cat_ids(self, idx):
65
+ return self.dataset.get_cat_ids(idx % self._ori_len)
66
+
67
+ def __len__(self):
68
+ return self.times * self._ori_len
69
+
70
+
71
+ # Modified from https://github.com/facebookresearch/detectron2/blob/41d475b75a230221e21d9cac5d69655e3415e3a4/detectron2/data/samplers/distributed_sampler.py#L57 # noqa
72
+ @DATASETS.register_module()
73
+ class ClassBalancedDataset(object):
74
+ """A wrapper of repeated dataset with repeat factor.
75
+
76
+ Suitable for training on class imbalanced datasets like LVIS. Following
77
+ the sampling strategy in [1], in each epoch, an image may appear multiple
78
+ times based on its "repeat factor".
79
+ The repeat factor for an image is a function of the frequency the rarest
80
+ category labeled in that image. The "frequency of category c" in [0, 1]
81
+ is defined by the fraction of images in the training set (without repeats)
82
+ in which category c appears.
83
+ The dataset needs to instantiate :func:`self.get_cat_ids(idx)` to support
84
+ ClassBalancedDataset.
85
+ The repeat factor is computed as followed.
86
+ 1. For each category c, compute the fraction # of images
87
+ that contain it: f(c)
88
+ 2. For each category c, compute the category-level repeat factor:
89
+ r(c) = max(1, sqrt(t/f(c)))
90
+ 3. For each image I and its labels L(I), compute the image-level repeat
91
+ factor:
92
+ r(I) = max_{c in L(I)} r(c)
93
+
94
+ References:
95
+ .. [1] https://arxiv.org/pdf/1908.03195.pdf
96
+
97
+ Args:
98
+ dataset (:obj:`CustomDataset`): The dataset to be repeated.
99
+ oversample_thr (float): frequency threshold below which data is
100
+ repeated. For categories with `f_c` >= `oversample_thr`, there is
101
+ no oversampling. For categories with `f_c` < `oversample_thr`, the
102
+ degree of oversampling following the square-root inverse frequency
103
+ heuristic above.
104
+ """
105
+
106
+ def __init__(self, dataset, oversample_thr, method='sqrt', **kwargs):
107
+ assert(method in ('sqrt', 'reciprocal')) # reciprocal,倒数,绝对 balance, repeat_factor = f(c) / max( fc )
108
+ self.method = method
109
+ self.dataset = dataset
110
+ self.oversample_thr = oversample_thr
111
+ self.CLASSES = dataset.CLASSES
112
+
113
+ repeat_factors = self._get_repeat_factors(dataset, oversample_thr)
114
+ repeat_indices = []
115
+ for dataset_index, repeat_factor in enumerate(repeat_factors):
116
+ repeat_indices.extend([dataset_index] * math.ceil(repeat_factor))
117
+ self.repeat_indices = repeat_indices
118
+
119
+ flags = []
120
+ if hasattr(self.dataset, 'flag'):
121
+ for flag, repeat_factor in zip(self.dataset.flag, repeat_factors):
122
+ flags.extend([flag] * int(math.ceil(repeat_factor)))
123
+ assert len(flags) == len(repeat_indices)
124
+ self.flag = np.asarray(flags, dtype=np.uint8)
125
+
126
+ def _get_repeat_factors(self, dataset, repeat_thr):
127
+ # 1. For each category c, compute the fraction # of images
128
+ # that contain it: f(c)
129
+ category_freq = defaultdict(int)
130
+ num_images = len(dataset)
131
+ for idx in range(num_images):
132
+ cat_ids = set(self.dataset.get_cat_ids(idx))
133
+ for cat_id in cat_ids:
134
+ category_freq[cat_id] += 1
135
+ for k, v in category_freq.items():
136
+ assert v > 0, f'caterogy {k} does not contain any images'
137
+ category_freq[k] = v / num_images
138
+
139
+ # 2. For each category c, compute the category-level repeat factor:
140
+ # r(c) = max(1, sqrt(t/f(c)))
141
+ if self.method == 'sqrt':
142
+ category_repeat = {
143
+ cat_id: max(1.0, math.sqrt(repeat_thr / cat_freq))
144
+ for cat_id, cat_freq in category_freq.items()
145
+ }
146
+ elif self.method == 'reciprocal':
147
+ cat_freq_max = 0
148
+ for cat_id, cat_freq in category_freq.items():
149
+ cat_freq_max = max(cat_freq_max, cat_freq)
150
+ print('cat_freq_max: ', cat_freq_max)
151
+ category_repeat = {
152
+ cat_id: cat_freq_max / cat_freq
153
+ for cat_id, cat_freq in category_freq.items()
154
+ }
155
+ # 3. For each image I and its labels L(I), compute the image-level
156
+ # repeat factor:
157
+ # r(I) = max_{c in L(I)} r(c)
158
+ repeat_factors = []
159
+ for idx in range(num_images):
160
+ cat_ids = set(self.dataset.get_cat_ids(idx))
161
+ repeat_factor = max(
162
+ {category_repeat[cat_id]
163
+ for cat_id in cat_ids})
164
+ repeat_factors.append(repeat_factor)
165
+
166
+ return repeat_factors
167
+
168
+ def __getitem__(self, idx):
169
+ ori_index = self.repeat_indices[idx]
170
+ return self.dataset[ori_index]
171
+
172
+ def __len__(self):
173
+ return len(self.repeat_indices)
CAGE_expression_inference-apvit/apvit_mmcls/datasets/imagenet.py ADDED
@@ -0,0 +1,1105 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+
3
+ import numpy as np
4
+
5
+ from .base_dataset import BaseDataset
6
+ from .builder import DATASETS
7
+
8
+
9
+ def has_file_allowed_extension(filename, extensions):
10
+ """Checks if a file is an allowed extension.
11
+
12
+ Args:
13
+ filename (string): path to a file
14
+
15
+ Returns:
16
+ bool: True if the filename ends with a known image extension
17
+ """
18
+ filename_lower = filename.lower()
19
+ return any(filename_lower.endswith(ext) for ext in extensions)
20
+
21
+
22
+ def find_folders(root):
23
+ """Find classes by folders under a root.
24
+
25
+ Args:
26
+ root (string): root directory of folders
27
+
28
+ Returns:
29
+ folder_to_idx (dict): the map from folder name to class idx
30
+ """
31
+ folders = [
32
+ d for d in os.listdir(root) if os.path.isdir(os.path.join(root, d))
33
+ ]
34
+ folders.sort()
35
+ folder_to_idx = {folders[i]: i for i in range(len(folders))}
36
+ return folder_to_idx
37
+
38
+
39
+ def get_samples(root, folder_to_idx, extensions):
40
+ """Make dataset by walking all images under a root.
41
+
42
+ Args:
43
+ root (string): root directory of folders
44
+ folder_to_idx (dict): the map from class name to class idx
45
+ extensions (tuple): allowed extensions
46
+
47
+ Returns:
48
+ samples (list): a list of tuple where each element is (image, label)
49
+ """
50
+ samples = []
51
+ root = os.path.expanduser(root)
52
+ for folder_name in sorted(os.listdir(root)):
53
+ _dir = os.path.join(root, folder_name)
54
+ if not os.path.isdir(_dir):
55
+ continue
56
+
57
+ for _, _, fns in sorted(os.walk(_dir)):
58
+ for fn in sorted(fns):
59
+ if has_file_allowed_extension(fn, extensions):
60
+ path = os.path.join(folder_name, fn)
61
+ item = (path, folder_to_idx[folder_name])
62
+ samples.append(item)
63
+ return samples
64
+
65
+
66
+ @DATASETS.register_module()
67
+ class ImageNet(BaseDataset):
68
+ """`ImageNet <http://www.image-net.org>`_ Dataset.
69
+
70
+ This implementation is modified from
71
+ https://github.com/pytorch/vision/blob/master/torchvision/datasets/imagenet.py # noqa: E501
72
+ """
73
+
74
+ IMG_EXTENSIONS = ('.jpg', '.jpeg', '.png', '.ppm', '.bmp', '.pgm', '.tif')
75
+ CLASSES = [
76
+ 'tench, Tinca tinca',
77
+ 'goldfish, Carassius auratus',
78
+ 'great white shark, white shark, man-eater, man-eating shark, Carcharodon carcharias', # noqa: E501
79
+ 'tiger shark, Galeocerdo cuvieri',
80
+ 'hammerhead, hammerhead shark',
81
+ 'electric ray, crampfish, numbfish, torpedo',
82
+ 'stingray',
83
+ 'cock',
84
+ 'hen',
85
+ 'ostrich, Struthio camelus',
86
+ 'brambling, Fringilla montifringilla',
87
+ 'goldfinch, Carduelis carduelis',
88
+ 'house finch, linnet, Carpodacus mexicanus',
89
+ 'junco, snowbird',
90
+ 'indigo bunting, indigo finch, indigo bird, Passerina cyanea',
91
+ 'robin, American robin, Turdus migratorius',
92
+ 'bulbul',
93
+ 'jay',
94
+ 'magpie',
95
+ 'chickadee',
96
+ 'water ouzel, dipper',
97
+ 'kite',
98
+ 'bald eagle, American eagle, Haliaeetus leucocephalus',
99
+ 'vulture',
100
+ 'great grey owl, great gray owl, Strix nebulosa',
101
+ 'European fire salamander, Salamandra salamandra',
102
+ 'common newt, Triturus vulgaris',
103
+ 'eft',
104
+ 'spotted salamander, Ambystoma maculatum',
105
+ 'axolotl, mud puppy, Ambystoma mexicanum',
106
+ 'bullfrog, Rana catesbeiana',
107
+ 'tree frog, tree-frog',
108
+ 'tailed frog, bell toad, ribbed toad, tailed toad, Ascaphus trui',
109
+ 'loggerhead, loggerhead turtle, Caretta caretta',
110
+ 'leatherback turtle, leatherback, leathery turtle, Dermochelys coriacea', # noqa: E501
111
+ 'mud turtle',
112
+ 'terrapin',
113
+ 'box turtle, box tortoise',
114
+ 'banded gecko',
115
+ 'common iguana, iguana, Iguana iguana',
116
+ 'American chameleon, anole, Anolis carolinensis',
117
+ 'whiptail, whiptail lizard',
118
+ 'agama',
119
+ 'frilled lizard, Chlamydosaurus kingi',
120
+ 'alligator lizard',
121
+ 'Gila monster, Heloderma suspectum',
122
+ 'green lizard, Lacerta viridis',
123
+ 'African chameleon, Chamaeleo chamaeleon',
124
+ 'Komodo dragon, Komodo lizard, dragon lizard, giant lizard, Varanus komodoensis', # noqa: E501
125
+ 'African crocodile, Nile crocodile, Crocodylus niloticus',
126
+ 'American alligator, Alligator mississipiensis',
127
+ 'triceratops',
128
+ 'thunder snake, worm snake, Carphophis amoenus',
129
+ 'ringneck snake, ring-necked snake, ring snake',
130
+ 'hognose snake, puff adder, sand viper',
131
+ 'green snake, grass snake',
132
+ 'king snake, kingsnake',
133
+ 'garter snake, grass snake',
134
+ 'water snake',
135
+ 'vine snake',
136
+ 'night snake, Hypsiglena torquata',
137
+ 'boa constrictor, Constrictor constrictor',
138
+ 'rock python, rock snake, Python sebae',
139
+ 'Indian cobra, Naja naja',
140
+ 'green mamba',
141
+ 'sea snake',
142
+ 'horned viper, cerastes, sand viper, horned asp, Cerastes cornutus',
143
+ 'diamondback, diamondback rattlesnake, Crotalus adamanteus',
144
+ 'sidewinder, horned rattlesnake, Crotalus cerastes',
145
+ 'trilobite',
146
+ 'harvestman, daddy longlegs, Phalangium opilio',
147
+ 'scorpion',
148
+ 'black and gold garden spider, Argiope aurantia',
149
+ 'barn spider, Araneus cavaticus',
150
+ 'garden spider, Aranea diademata',
151
+ 'black widow, Latrodectus mactans',
152
+ 'tarantula',
153
+ 'wolf spider, hunting spider',
154
+ 'tick',
155
+ 'centipede',
156
+ 'black grouse',
157
+ 'ptarmigan',
158
+ 'ruffed grouse, partridge, Bonasa umbellus',
159
+ 'prairie chicken, prairie grouse, prairie fowl',
160
+ 'peacock',
161
+ 'quail',
162
+ 'partridge',
163
+ 'African grey, African gray, Psittacus erithacus',
164
+ 'macaw',
165
+ 'sulphur-crested cockatoo, Kakatoe galerita, Cacatua galerita',
166
+ 'lorikeet',
167
+ 'coucal',
168
+ 'bee eater',
169
+ 'hornbill',
170
+ 'hummingbird',
171
+ 'jacamar',
172
+ 'toucan',
173
+ 'drake',
174
+ 'red-breasted merganser, Mergus serrator',
175
+ 'goose',
176
+ 'black swan, Cygnus atratus',
177
+ 'tusker',
178
+ 'echidna, spiny anteater, anteater',
179
+ 'platypus, duckbill, duckbilled platypus, duck-billed platypus, Ornithorhynchus anatinus', # noqa: E501
180
+ 'wallaby, brush kangaroo',
181
+ 'koala, koala bear, kangaroo bear, native bear, Phascolarctos cinereus', # noqa: E501
182
+ 'wombat',
183
+ 'jellyfish',
184
+ 'sea anemone, anemone',
185
+ 'brain coral',
186
+ 'flatworm, platyhelminth',
187
+ 'nematode, nematode worm, roundworm',
188
+ 'conch',
189
+ 'snail',
190
+ 'slug',
191
+ 'sea slug, nudibranch',
192
+ 'chiton, coat-of-mail shell, sea cradle, polyplacophore',
193
+ 'chambered nautilus, pearly nautilus, nautilus',
194
+ 'Dungeness crab, Cancer magister',
195
+ 'rock crab, Cancer irroratus',
196
+ 'fiddler crab',
197
+ 'king crab, Alaska crab, Alaskan king crab, Alaska king crab, Paralithodes camtschatica', # noqa: E501
198
+ 'American lobster, Northern lobster, Maine lobster, Homarus americanus', # noqa: E501
199
+ 'spiny lobster, langouste, rock lobster, crawfish, crayfish, sea crawfish', # noqa: E501
200
+ 'crayfish, crawfish, crawdad, crawdaddy',
201
+ 'hermit crab',
202
+ 'isopod',
203
+ 'white stork, Ciconia ciconia',
204
+ 'black stork, Ciconia nigra',
205
+ 'spoonbill',
206
+ 'flamingo',
207
+ 'little blue heron, Egretta caerulea',
208
+ 'American egret, great white heron, Egretta albus',
209
+ 'bittern',
210
+ 'crane',
211
+ 'limpkin, Aramus pictus',
212
+ 'European gallinule, Porphyrio porphyrio',
213
+ 'American coot, marsh hen, mud hen, water hen, Fulica americana',
214
+ 'bustard',
215
+ 'ruddy turnstone, Arenaria interpres',
216
+ 'red-backed sandpiper, dunlin, Erolia alpina',
217
+ 'redshank, Tringa totanus',
218
+ 'dowitcher',
219
+ 'oystercatcher, oyster catcher',
220
+ 'pelican',
221
+ 'king penguin, Aptenodytes patagonica',
222
+ 'albatross, mollymawk',
223
+ 'grey whale, gray whale, devilfish, Eschrichtius gibbosus, Eschrichtius robustus', # noqa: E501
224
+ 'killer whale, killer, orca, grampus, sea wolf, Orcinus orca',
225
+ 'dugong, Dugong dugon',
226
+ 'sea lion',
227
+ 'Chihuahua',
228
+ 'Japanese spaniel',
229
+ 'Maltese dog, Maltese terrier, Maltese',
230
+ 'Pekinese, Pekingese, Peke',
231
+ 'Shih-Tzu',
232
+ 'Blenheim spaniel',
233
+ 'papillon',
234
+ 'toy terrier',
235
+ 'Rhodesian ridgeback',
236
+ 'Afghan hound, Afghan',
237
+ 'basset, basset hound',
238
+ 'beagle',
239
+ 'bloodhound, sleuthhound',
240
+ 'bluetick',
241
+ 'black-and-tan coonhound',
242
+ 'Walker hound, Walker foxhound',
243
+ 'English foxhound',
244
+ 'redbone',
245
+ 'borzoi, Russian wolfhound',
246
+ 'Irish wolfhound',
247
+ 'Italian greyhound',
248
+ 'whippet',
249
+ 'Ibizan hound, Ibizan Podenco',
250
+ 'Norwegian elkhound, elkhound',
251
+ 'otterhound, otter hound',
252
+ 'Saluki, gazelle hound',
253
+ 'Scottish deerhound, deerhound',
254
+ 'Weimaraner',
255
+ 'Staffordshire bullterrier, Staffordshire bull terrier',
256
+ 'American Staffordshire terrier, Staffordshire terrier, American pit bull terrier, pit bull terrier', # noqa: E501
257
+ 'Bedlington terrier',
258
+ 'Border terrier',
259
+ 'Kerry blue terrier',
260
+ 'Irish terrier',
261
+ 'Norfolk terrier',
262
+ 'Norwich terrier',
263
+ 'Yorkshire terrier',
264
+ 'wire-haired fox terrier',
265
+ 'Lakeland terrier',
266
+ 'Sealyham terrier, Sealyham',
267
+ 'Airedale, Airedale terrier',
268
+ 'cairn, cairn terrier',
269
+ 'Australian terrier',
270
+ 'Dandie Dinmont, Dandie Dinmont terrier',
271
+ 'Boston bull, Boston terrier',
272
+ 'miniature schnauzer',
273
+ 'giant schnauzer',
274
+ 'standard schnauzer',
275
+ 'Scotch terrier, Scottish terrier, Scottie',
276
+ 'Tibetan terrier, chrysanthemum dog',
277
+ 'silky terrier, Sydney silky',
278
+ 'soft-coated wheaten terrier',
279
+ 'West Highland white terrier',
280
+ 'Lhasa, Lhasa apso',
281
+ 'flat-coated retriever',
282
+ 'curly-coated retriever',
283
+ 'golden retriever',
284
+ 'Labrador retriever',
285
+ 'Chesapeake Bay retriever',
286
+ 'German short-haired pointer',
287
+ 'vizsla, Hungarian pointer',
288
+ 'English setter',
289
+ 'Irish setter, red setter',
290
+ 'Gordon setter',
291
+ 'Brittany spaniel',
292
+ 'clumber, clumber spaniel',
293
+ 'English springer, English springer spaniel',
294
+ 'Welsh springer spaniel',
295
+ 'cocker spaniel, English cocker spaniel, cocker',
296
+ 'Sussex spaniel',
297
+ 'Irish water spaniel',
298
+ 'kuvasz',
299
+ 'schipperke',
300
+ 'groenendael',
301
+ 'malinois',
302
+ 'briard',
303
+ 'kelpie',
304
+ 'komondor',
305
+ 'Old English sheepdog, bobtail',
306
+ 'Shetland sheepdog, Shetland sheep dog, Shetland',
307
+ 'collie',
308
+ 'Border collie',
309
+ 'Bouvier des Flandres, Bouviers des Flandres',
310
+ 'Rottweiler',
311
+ 'German shepherd, German shepherd dog, German police dog, alsatian',
312
+ 'Doberman, Doberman pinscher',
313
+ 'miniature pinscher',
314
+ 'Greater Swiss Mountain dog',
315
+ 'Bernese mountain dog',
316
+ 'Appenzeller',
317
+ 'EntleBucher',
318
+ 'boxer',
319
+ 'bull mastiff',
320
+ 'Tibetan mastiff',
321
+ 'French bulldog',
322
+ 'Great Dane',
323
+ 'Saint Bernard, St Bernard',
324
+ 'Eskimo dog, husky',
325
+ 'malamute, malemute, Alaskan malamute',
326
+ 'Siberian husky',
327
+ 'dalmatian, coach dog, carriage dog',
328
+ 'affenpinscher, monkey pinscher, monkey dog',
329
+ 'basenji',
330
+ 'pug, pug-dog',
331
+ 'Leonberg',
332
+ 'Newfoundland, Newfoundland dog',
333
+ 'Great Pyrenees',
334
+ 'Samoyed, Samoyede',
335
+ 'Pomeranian',
336
+ 'chow, chow chow',
337
+ 'keeshond',
338
+ 'Brabancon griffon',
339
+ 'Pembroke, Pembroke Welsh corgi',
340
+ 'Cardigan, Cardigan Welsh corgi',
341
+ 'toy poodle',
342
+ 'miniature poodle',
343
+ 'standard poodle',
344
+ 'Mexican hairless',
345
+ 'timber wolf, grey wolf, gray wolf, Canis lupus',
346
+ 'white wolf, Arctic wolf, Canis lupus tundrarum',
347
+ 'red wolf, maned wolf, Canis rufus, Canis niger',
348
+ 'coyote, prairie wolf, brush wolf, Canis latrans',
349
+ 'dingo, warrigal, warragal, Canis dingo',
350
+ 'dhole, Cuon alpinus',
351
+ 'African hunting dog, hyena dog, Cape hunting dog, Lycaon pictus',
352
+ 'hyena, hyaena',
353
+ 'red fox, Vulpes vulpes',
354
+ 'kit fox, Vulpes macrotis',
355
+ 'Arctic fox, white fox, Alopex lagopus',
356
+ 'grey fox, gray fox, Urocyon cinereoargenteus',
357
+ 'tabby, tabby cat',
358
+ 'tiger cat',
359
+ 'Persian cat',
360
+ 'Siamese cat, Siamese',
361
+ 'Egyptian cat',
362
+ 'cougar, puma, catamount, mountain lion, painter, panther, Felis concolor', # noqa: E501
363
+ 'lynx, catamount',
364
+ 'leopard, Panthera pardus',
365
+ 'snow leopard, ounce, Panthera uncia',
366
+ 'jaguar, panther, Panthera onca, Felis onca',
367
+ 'lion, king of beasts, Panthera leo',
368
+ 'tiger, Panthera tigris',
369
+ 'cheetah, chetah, Acinonyx jubatus',
370
+ 'brown bear, bruin, Ursus arctos',
371
+ 'American black bear, black bear, Ursus americanus, Euarctos americanus', # noqa: E501
372
+ 'ice bear, polar bear, Ursus Maritimus, Thalarctos maritimus',
373
+ 'sloth bear, Melursus ursinus, Ursus ursinus',
374
+ 'mongoose',
375
+ 'meerkat, mierkat',
376
+ 'tiger beetle',
377
+ 'ladybug, ladybeetle, lady beetle, ladybird, ladybird beetle',
378
+ 'ground beetle, carabid beetle',
379
+ 'long-horned beetle, longicorn, longicorn beetle',
380
+ 'leaf beetle, chrysomelid',
381
+ 'dung beetle',
382
+ 'rhinoceros beetle',
383
+ 'weevil',
384
+ 'fly',
385
+ 'bee',
386
+ 'ant, emmet, pismire',
387
+ 'grasshopper, hopper',
388
+ 'cricket',
389
+ 'walking stick, walkingstick, stick insect',
390
+ 'cockroach, roach',
391
+ 'mantis, mantid',
392
+ 'cicada, cicala',
393
+ 'leafhopper',
394
+ 'lacewing, lacewing fly',
395
+ "dragonfly, darning needle, devil's darning needle, sewing needle, snake feeder, snake doctor, mosquito hawk, skeeter hawk", # noqa: E501
396
+ 'damselfly',
397
+ 'admiral',
398
+ 'ringlet, ringlet butterfly',
399
+ 'monarch, monarch butterfly, milkweed butterfly, Danaus plexippus',
400
+ 'cabbage butterfly',
401
+ 'sulphur butterfly, sulfur butterfly',
402
+ 'lycaenid, lycaenid butterfly',
403
+ 'starfish, sea star',
404
+ 'sea urchin',
405
+ 'sea cucumber, holothurian',
406
+ 'wood rabbit, cottontail, cottontail rabbit',
407
+ 'hare',
408
+ 'Angora, Angora rabbit',
409
+ 'hamster',
410
+ 'porcupine, hedgehog',
411
+ 'fox squirrel, eastern fox squirrel, Sciurus niger',
412
+ 'marmot',
413
+ 'beaver',
414
+ 'guinea pig, Cavia cobaya',
415
+ 'sorrel',
416
+ 'zebra',
417
+ 'hog, pig, grunter, squealer, Sus scrofa',
418
+ 'wild boar, boar, Sus scrofa',
419
+ 'warthog',
420
+ 'hippopotamus, hippo, river horse, Hippopotamus amphibius',
421
+ 'ox',
422
+ 'water buffalo, water ox, Asiatic buffalo, Bubalus bubalis',
423
+ 'bison',
424
+ 'ram, tup',
425
+ 'bighorn, bighorn sheep, cimarron, Rocky Mountain bighorn, Rocky Mountain sheep, Ovis canadensis', # noqa: E501
426
+ 'ibex, Capra ibex',
427
+ 'hartebeest',
428
+ 'impala, Aepyceros melampus',
429
+ 'gazelle',
430
+ 'Arabian camel, dromedary, Camelus dromedarius',
431
+ 'llama',
432
+ 'weasel',
433
+ 'mink',
434
+ 'polecat, fitch, foulmart, foumart, Mustela putorius',
435
+ 'black-footed ferret, ferret, Mustela nigripes',
436
+ 'otter',
437
+ 'skunk, polecat, wood pussy',
438
+ 'badger',
439
+ 'armadillo',
440
+ 'three-toed sloth, ai, Bradypus tridactylus',
441
+ 'orangutan, orang, orangutang, Pongo pygmaeus',
442
+ 'gorilla, Gorilla gorilla',
443
+ 'chimpanzee, chimp, Pan troglodytes',
444
+ 'gibbon, Hylobates lar',
445
+ 'siamang, Hylobates syndactylus, Symphalangus syndactylus',
446
+ 'guenon, guenon monkey',
447
+ 'patas, hussar monkey, Erythrocebus patas',
448
+ 'baboon',
449
+ 'macaque',
450
+ 'langur',
451
+ 'colobus, colobus monkey',
452
+ 'proboscis monkey, Nasalis larvatus',
453
+ 'marmoset',
454
+ 'capuchin, ringtail, Cebus capucinus',
455
+ 'howler monkey, howler',
456
+ 'titi, titi monkey',
457
+ 'spider monkey, Ateles geoffroyi',
458
+ 'squirrel monkey, Saimiri sciureus',
459
+ 'Madagascar cat, ring-tailed lemur, Lemur catta',
460
+ 'indri, indris, Indri indri, Indri brevicaudatus',
461
+ 'Indian elephant, Elephas maximus',
462
+ 'African elephant, Loxodonta africana',
463
+ 'lesser panda, red panda, panda, bear cat, cat bear, Ailurus fulgens',
464
+ 'giant panda, panda, panda bear, coon bear, Ailuropoda melanoleuca',
465
+ 'barracouta, snoek',
466
+ 'eel',
467
+ 'coho, cohoe, coho salmon, blue jack, silver salmon, Oncorhynchus kisutch', # noqa: E501
468
+ 'rock beauty, Holocanthus tricolor',
469
+ 'anemone fish',
470
+ 'sturgeon',
471
+ 'gar, garfish, garpike, billfish, Lepisosteus osseus',
472
+ 'lionfish',
473
+ 'puffer, pufferfish, blowfish, globefish',
474
+ 'abacus',
475
+ 'abaya',
476
+ "academic gown, academic robe, judge's robe",
477
+ 'accordion, piano accordion, squeeze box',
478
+ 'acoustic guitar',
479
+ 'aircraft carrier, carrier, flattop, attack aircraft carrier',
480
+ 'airliner',
481
+ 'airship, dirigible',
482
+ 'altar',
483
+ 'ambulance',
484
+ 'amphibian, amphibious vehicle',
485
+ 'analog clock',
486
+ 'apiary, bee house',
487
+ 'apron',
488
+ 'ashcan, trash can, garbage can, wastebin, ash bin, ash-bin, ashbin, dustbin, trash barrel, trash bin', # noqa: E501
489
+ 'assault rifle, assault gun',
490
+ 'backpack, back pack, knapsack, packsack, rucksack, haversack',
491
+ 'bakery, bakeshop, bakehouse',
492
+ 'balance beam, beam',
493
+ 'balloon',
494
+ 'ballpoint, ballpoint pen, ballpen, Biro',
495
+ 'Band Aid',
496
+ 'banjo',
497
+ 'bannister, banister, balustrade, balusters, handrail',
498
+ 'barbell',
499
+ 'barber chair',
500
+ 'barbershop',
501
+ 'barn',
502
+ 'barometer',
503
+ 'barrel, cask',
504
+ 'barrow, garden cart, lawn cart, wheelbarrow',
505
+ 'baseball',
506
+ 'basketball',
507
+ 'bassinet',
508
+ 'bassoon',
509
+ 'bathing cap, swimming cap',
510
+ 'bath towel',
511
+ 'bathtub, bathing tub, bath, tub',
512
+ 'beach wagon, station wagon, wagon, estate car, beach waggon, station waggon, waggon', # noqa: E501
513
+ 'beacon, lighthouse, beacon light, pharos',
514
+ 'beaker',
515
+ 'bearskin, busby, shako',
516
+ 'beer bottle',
517
+ 'beer glass',
518
+ 'bell cote, bell cot',
519
+ 'bib',
520
+ 'bicycle-built-for-two, tandem bicycle, tandem',
521
+ 'bikini, two-piece',
522
+ 'binder, ring-binder',
523
+ 'binoculars, field glasses, opera glasses',
524
+ 'birdhouse',
525
+ 'boathouse',
526
+ 'bobsled, bobsleigh, bob',
527
+ 'bolo tie, bolo, bola tie, bola',
528
+ 'bonnet, poke bonnet',
529
+ 'bookcase',
530
+ 'bookshop, bookstore, bookstall',
531
+ 'bottlecap',
532
+ 'bow',
533
+ 'bow tie, bow-tie, bowtie',
534
+ 'brass, memorial tablet, plaque',
535
+ 'brassiere, bra, bandeau',
536
+ 'breakwater, groin, groyne, mole, bulwark, seawall, jetty',
537
+ 'breastplate, aegis, egis',
538
+ 'broom',
539
+ 'bucket, pail',
540
+ 'buckle',
541
+ 'bulletproof vest',
542
+ 'bullet train, bullet',
543
+ 'butcher shop, meat market',
544
+ 'cab, hack, taxi, taxicab',
545
+ 'caldron, cauldron',
546
+ 'candle, taper, wax light',
547
+ 'cannon',
548
+ 'canoe',
549
+ 'can opener, tin opener',
550
+ 'cardigan',
551
+ 'car mirror',
552
+ 'carousel, carrousel, merry-go-round, roundabout, whirligig',
553
+ "carpenter's kit, tool kit",
554
+ 'carton',
555
+ 'car wheel',
556
+ 'cash machine, cash dispenser, automated teller machine, automatic teller machine, automated teller, automatic teller, ATM', # noqa: E501
557
+ 'cassette',
558
+ 'cassette player',
559
+ 'castle',
560
+ 'catamaran',
561
+ 'CD player',
562
+ 'cello, violoncello',
563
+ 'cellular telephone, cellular phone, cellphone, cell, mobile phone',
564
+ 'chain',
565
+ 'chainlink fence',
566
+ 'chain mail, ring mail, mail, chain armor, chain armour, ring armor, ring armour', # noqa: E501
567
+ 'chain saw, chainsaw',
568
+ 'chest',
569
+ 'chiffonier, commode',
570
+ 'chime, bell, gong',
571
+ 'china cabinet, china closet',
572
+ 'Christmas stocking',
573
+ 'church, church building',
574
+ 'cinema, movie theater, movie theatre, movie house, picture palace',
575
+ 'cleaver, meat cleaver, chopper',
576
+ 'cliff dwelling',
577
+ 'cloak',
578
+ 'clog, geta, patten, sabot',
579
+ 'cocktail shaker',
580
+ 'coffee mug',
581
+ 'coffeepot',
582
+ 'coil, spiral, volute, whorl, helix',
583
+ 'combination lock',
584
+ 'computer keyboard, keypad',
585
+ 'confectionery, confectionary, candy store',
586
+ 'container ship, containership, container vessel',
587
+ 'convertible',
588
+ 'corkscrew, bottle screw',
589
+ 'cornet, horn, trumpet, trump',
590
+ 'cowboy boot',
591
+ 'cowboy hat, ten-gallon hat',
592
+ 'cradle',
593
+ 'crane',
594
+ 'crash helmet',
595
+ 'crate',
596
+ 'crib, cot',
597
+ 'Crock Pot',
598
+ 'croquet ball',
599
+ 'crutch',
600
+ 'cuirass',
601
+ 'dam, dike, dyke',
602
+ 'desk',
603
+ 'desktop computer',
604
+ 'dial telephone, dial phone',
605
+ 'diaper, nappy, napkin',
606
+ 'digital clock',
607
+ 'digital watch',
608
+ 'dining table, board',
609
+ 'dishrag, dishcloth',
610
+ 'dishwasher, dish washer, dishwashing machine',
611
+ 'disk brake, disc brake',
612
+ 'dock, dockage, docking facility',
613
+ 'dogsled, dog sled, dog sleigh',
614
+ 'dome',
615
+ 'doormat, welcome mat',
616
+ 'drilling platform, offshore rig',
617
+ 'drum, membranophone, tympan',
618
+ 'drumstick',
619
+ 'dumbbell',
620
+ 'Dutch oven',
621
+ 'electric fan, blower',
622
+ 'electric guitar',
623
+ 'electric locomotive',
624
+ 'entertainment center',
625
+ 'envelope',
626
+ 'espresso maker',
627
+ 'face powder',
628
+ 'feather boa, boa',
629
+ 'file, file cabinet, filing cabinet',
630
+ 'fireboat',
631
+ 'fire engine, fire truck',
632
+ 'fire screen, fireguard',
633
+ 'flagpole, flagstaff',
634
+ 'flute, transverse flute',
635
+ 'folding chair',
636
+ 'football helmet',
637
+ 'forklift',
638
+ 'fountain',
639
+ 'fountain pen',
640
+ 'four-poster',
641
+ 'freight car',
642
+ 'French horn, horn',
643
+ 'frying pan, frypan, skillet',
644
+ 'fur coat',
645
+ 'garbage truck, dustcart',
646
+ 'gasmask, respirator, gas helmet',
647
+ 'gas pump, gasoline pump, petrol pump, island dispenser',
648
+ 'goblet',
649
+ 'go-kart',
650
+ 'golf ball',
651
+ 'golfcart, golf cart',
652
+ 'gondola',
653
+ 'gong, tam-tam',
654
+ 'gown',
655
+ 'grand piano, grand',
656
+ 'greenhouse, nursery, glasshouse',
657
+ 'grille, radiator grille',
658
+ 'grocery store, grocery, food market, market',
659
+ 'guillotine',
660
+ 'hair slide',
661
+ 'hair spray',
662
+ 'half track',
663
+ 'hammer',
664
+ 'hamper',
665
+ 'hand blower, blow dryer, blow drier, hair dryer, hair drier',
666
+ 'hand-held computer, hand-held microcomputer',
667
+ 'handkerchief, hankie, hanky, hankey',
668
+ 'hard disc, hard disk, fixed disk',
669
+ 'harmonica, mouth organ, harp, mouth harp',
670
+ 'harp',
671
+ 'harvester, reaper',
672
+ 'hatchet',
673
+ 'holster',
674
+ 'home theater, home theatre',
675
+ 'honeycomb',
676
+ 'hook, claw',
677
+ 'hoopskirt, crinoline',
678
+ 'horizontal bar, high bar',
679
+ 'horse cart, horse-cart',
680
+ 'hourglass',
681
+ 'iPod',
682
+ 'iron, smoothing iron',
683
+ "jack-o'-lantern",
684
+ 'jean, blue jean, denim',
685
+ 'jeep, landrover',
686
+ 'jersey, T-shirt, tee shirt',
687
+ 'jigsaw puzzle',
688
+ 'jinrikisha, ricksha, rickshaw',
689
+ 'joystick',
690
+ 'kimono',
691
+ 'knee pad',
692
+ 'knot',
693
+ 'lab coat, laboratory coat',
694
+ 'ladle',
695
+ 'lampshade, lamp shade',
696
+ 'laptop, laptop computer',
697
+ 'lawn mower, mower',
698
+ 'lens cap, lens cover',
699
+ 'letter opener, paper knife, paperknife',
700
+ 'library',
701
+ 'lifeboat',
702
+ 'lighter, light, igniter, ignitor',
703
+ 'limousine, limo',
704
+ 'liner, ocean liner',
705
+ 'lipstick, lip rouge',
706
+ 'Loafer',
707
+ 'lotion',
708
+ 'loudspeaker, speaker, speaker unit, loudspeaker system, speaker system', # noqa: E501
709
+ "loupe, jeweler's loupe",
710
+ 'lumbermill, sawmill',
711
+ 'magnetic compass',
712
+ 'mailbag, postbag',
713
+ 'mailbox, letter box',
714
+ 'maillot',
715
+ 'maillot, tank suit',
716
+ 'manhole cover',
717
+ 'maraca',
718
+ 'marimba, xylophone',
719
+ 'mask',
720
+ 'matchstick',
721
+ 'maypole',
722
+ 'maze, labyrinth',
723
+ 'measuring cup',
724
+ 'medicine chest, medicine cabinet',
725
+ 'megalith, megalithic structure',
726
+ 'microphone, mike',
727
+ 'microwave, microwave oven',
728
+ 'military uniform',
729
+ 'milk can',
730
+ 'minibus',
731
+ 'miniskirt, mini',
732
+ 'minivan',
733
+ 'missile',
734
+ 'mitten',
735
+ 'mixing bowl',
736
+ 'mobile home, manufactured home',
737
+ 'Model T',
738
+ 'modem',
739
+ 'monastery',
740
+ 'monitor',
741
+ 'moped',
742
+ 'mortar',
743
+ 'mortarboard',
744
+ 'mosque',
745
+ 'mosquito net',
746
+ 'motor scooter, scooter',
747
+ 'mountain bike, all-terrain bike, off-roader',
748
+ 'mountain tent',
749
+ 'mouse, computer mouse',
750
+ 'mousetrap',
751
+ 'moving van',
752
+ 'muzzle',
753
+ 'nail',
754
+ 'neck brace',
755
+ 'necklace',
756
+ 'nipple',
757
+ 'notebook, notebook computer',
758
+ 'obelisk',
759
+ 'oboe, hautboy, hautbois',
760
+ 'ocarina, sweet potato',
761
+ 'odometer, hodometer, mileometer, milometer',
762
+ 'oil filter',
763
+ 'organ, pipe organ',
764
+ 'oscilloscope, scope, cathode-ray oscilloscope, CRO',
765
+ 'overskirt',
766
+ 'oxcart',
767
+ 'oxygen mask',
768
+ 'packet',
769
+ 'paddle, boat paddle',
770
+ 'paddlewheel, paddle wheel',
771
+ 'padlock',
772
+ 'paintbrush',
773
+ "pajama, pyjama, pj's, jammies",
774
+ 'palace',
775
+ 'panpipe, pandean pipe, syrinx',
776
+ 'paper towel',
777
+ 'parachute, chute',
778
+ 'parallel bars, bars',
779
+ 'park bench',
780
+ 'parking meter',
781
+ 'passenger car, coach, carriage',
782
+ 'patio, terrace',
783
+ 'pay-phone, pay-station',
784
+ 'pedestal, plinth, footstall',
785
+ 'pencil box, pencil case',
786
+ 'pencil sharpener',
787
+ 'perfume, essence',
788
+ 'Petri dish',
789
+ 'photocopier',
790
+ 'pick, plectrum, plectron',
791
+ 'pickelhaube',
792
+ 'picket fence, paling',
793
+ 'pickup, pickup truck',
794
+ 'pier',
795
+ 'piggy bank, penny bank',
796
+ 'pill bottle',
797
+ 'pillow',
798
+ 'ping-pong ball',
799
+ 'pinwheel',
800
+ 'pirate, pirate ship',
801
+ 'pitcher, ewer',
802
+ "plane, carpenter's plane, woodworking plane",
803
+ 'planetarium',
804
+ 'plastic bag',
805
+ 'plate rack',
806
+ 'plow, plough',
807
+ "plunger, plumber's helper",
808
+ 'Polaroid camera, Polaroid Land camera',
809
+ 'pole',
810
+ 'police van, police wagon, paddy wagon, patrol wagon, wagon, black Maria', # noqa: E501
811
+ 'poncho',
812
+ 'pool table, billiard table, snooker table',
813
+ 'pop bottle, soda bottle',
814
+ 'pot, flowerpot',
815
+ "potter's wheel",
816
+ 'power drill',
817
+ 'prayer rug, prayer mat',
818
+ 'printer',
819
+ 'prison, prison house',
820
+ 'projectile, missile',
821
+ 'projector',
822
+ 'puck, hockey puck',
823
+ 'punching bag, punch bag, punching ball, punchball',
824
+ 'purse',
825
+ 'quill, quill pen',
826
+ 'quilt, comforter, comfort, puff',
827
+ 'racer, race car, racing car',
828
+ 'racket, racquet',
829
+ 'radiator',
830
+ 'radio, wireless',
831
+ 'radio telescope, radio reflector',
832
+ 'rain barrel',
833
+ 'recreational vehicle, RV, R.V.',
834
+ 'reel',
835
+ 'reflex camera',
836
+ 'refrigerator, icebox',
837
+ 'remote control, remote',
838
+ 'restaurant, eating house, eating place, eatery',
839
+ 'revolver, six-gun, six-shooter',
840
+ 'rifle',
841
+ 'rocking chair, rocker',
842
+ 'rotisserie',
843
+ 'rubber eraser, rubber, pencil eraser',
844
+ 'rugby ball',
845
+ 'rule, ruler',
846
+ 'running shoe',
847
+ 'safe',
848
+ 'safety pin',
849
+ 'saltshaker, salt shaker',
850
+ 'sandal',
851
+ 'sarong',
852
+ 'sax, saxophone',
853
+ 'scabbard',
854
+ 'scale, weighing machine',
855
+ 'school bus',
856
+ 'schooner',
857
+ 'scoreboard',
858
+ 'screen, CRT screen',
859
+ 'screw',
860
+ 'screwdriver',
861
+ 'seat belt, seatbelt',
862
+ 'sewing machine',
863
+ 'shield, buckler',
864
+ 'shoe shop, shoe-shop, shoe store',
865
+ 'shoji',
866
+ 'shopping basket',
867
+ 'shopping cart',
868
+ 'shovel',
869
+ 'shower cap',
870
+ 'shower curtain',
871
+ 'ski',
872
+ 'ski mask',
873
+ 'sleeping bag',
874
+ 'slide rule, slipstick',
875
+ 'sliding door',
876
+ 'slot, one-armed bandit',
877
+ 'snorkel',
878
+ 'snowmobile',
879
+ 'snowplow, snowplough',
880
+ 'soap dispenser',
881
+ 'soccer ball',
882
+ 'sock',
883
+ 'solar dish, solar collector, solar furnace',
884
+ 'sombrero',
885
+ 'soup bowl',
886
+ 'space bar',
887
+ 'space heater',
888
+ 'space shuttle',
889
+ 'spatula',
890
+ 'speedboat',
891
+ "spider web, spider's web",
892
+ 'spindle',
893
+ 'sports car, sport car',
894
+ 'spotlight, spot',
895
+ 'stage',
896
+ 'steam locomotive',
897
+ 'steel arch bridge',
898
+ 'steel drum',
899
+ 'stethoscope',
900
+ 'stole',
901
+ 'stone wall',
902
+ 'stopwatch, stop watch',
903
+ 'stove',
904
+ 'strainer',
905
+ 'streetcar, tram, tramcar, trolley, trolley car',
906
+ 'stretcher',
907
+ 'studio couch, day bed',
908
+ 'stupa, tope',
909
+ 'submarine, pigboat, sub, U-boat',
910
+ 'suit, suit of clothes',
911
+ 'sundial',
912
+ 'sunglass',
913
+ 'sunglasses, dark glasses, shades',
914
+ 'sunscreen, sunblock, sun blocker',
915
+ 'suspension bridge',
916
+ 'swab, swob, mop',
917
+ 'sweatshirt',
918
+ 'swimming trunks, bathing trunks',
919
+ 'swing',
920
+ 'switch, electric switch, electrical switch',
921
+ 'syringe',
922
+ 'table lamp',
923
+ 'tank, army tank, armored combat vehicle, armoured combat vehicle',
924
+ 'tape player',
925
+ 'teapot',
926
+ 'teddy, teddy bear',
927
+ 'television, television system',
928
+ 'tennis ball',
929
+ 'thatch, thatched roof',
930
+ 'theater curtain, theatre curtain',
931
+ 'thimble',
932
+ 'thresher, thrasher, threshing machine',
933
+ 'throne',
934
+ 'tile roof',
935
+ 'toaster',
936
+ 'tobacco shop, tobacconist shop, tobacconist',
937
+ 'toilet seat',
938
+ 'torch',
939
+ 'totem pole',
940
+ 'tow truck, tow car, wrecker',
941
+ 'toyshop',
942
+ 'tractor',
943
+ 'trailer truck, tractor trailer, trucking rig, rig, articulated lorry, semi', # noqa: E501
944
+ 'tray',
945
+ 'trench coat',
946
+ 'tricycle, trike, velocipede',
947
+ 'trimaran',
948
+ 'tripod',
949
+ 'triumphal arch',
950
+ 'trolleybus, trolley coach, trackless trolley',
951
+ 'trombone',
952
+ 'tub, vat',
953
+ 'turnstile',
954
+ 'typewriter keyboard',
955
+ 'umbrella',
956
+ 'unicycle, monocycle',
957
+ 'upright, upright piano',
958
+ 'vacuum, vacuum cleaner',
959
+ 'vase',
960
+ 'vault',
961
+ 'velvet',
962
+ 'vending machine',
963
+ 'vestment',
964
+ 'viaduct',
965
+ 'violin, fiddle',
966
+ 'volleyball',
967
+ 'waffle iron',
968
+ 'wall clock',
969
+ 'wallet, billfold, notecase, pocketbook',
970
+ 'wardrobe, closet, press',
971
+ 'warplane, military plane',
972
+ 'washbasin, handbasin, washbowl, lavabo, wash-hand basin',
973
+ 'washer, automatic washer, washing machine',
974
+ 'water bottle',
975
+ 'water jug',
976
+ 'water tower',
977
+ 'whiskey jug',
978
+ 'whistle',
979
+ 'wig',
980
+ 'window screen',
981
+ 'window shade',
982
+ 'Windsor tie',
983
+ 'wine bottle',
984
+ 'wing',
985
+ 'wok',
986
+ 'wooden spoon',
987
+ 'wool, woolen, woollen',
988
+ 'worm fence, snake fence, snake-rail fence, Virginia fence',
989
+ 'wreck',
990
+ 'yawl',
991
+ 'yurt',
992
+ 'web site, website, internet site, site',
993
+ 'comic book',
994
+ 'crossword puzzle, crossword',
995
+ 'street sign',
996
+ 'traffic light, traffic signal, stoplight',
997
+ 'book jacket, dust cover, dust jacket, dust wrapper',
998
+ 'menu',
999
+ 'plate',
1000
+ 'guacamole',
1001
+ 'consomme',
1002
+ 'hot pot, hotpot',
1003
+ 'trifle',
1004
+ 'ice cream, icecream',
1005
+ 'ice lolly, lolly, lollipop, popsicle',
1006
+ 'French loaf',
1007
+ 'bagel, beigel',
1008
+ 'pretzel',
1009
+ 'cheeseburger',
1010
+ 'hotdog, hot dog, red hot',
1011
+ 'mashed potato',
1012
+ 'head cabbage',
1013
+ 'broccoli',
1014
+ 'cauliflower',
1015
+ 'zucchini, courgette',
1016
+ 'spaghetti squash',
1017
+ 'acorn squash',
1018
+ 'butternut squash',
1019
+ 'cucumber, cuke',
1020
+ 'artichoke, globe artichoke',
1021
+ 'bell pepper',
1022
+ 'cardoon',
1023
+ 'mushroom',
1024
+ 'Granny Smith',
1025
+ 'strawberry',
1026
+ 'orange',
1027
+ 'lemon',
1028
+ 'fig',
1029
+ 'pineapple, ananas',
1030
+ 'banana',
1031
+ 'jackfruit, jak, jack',
1032
+ 'custard apple',
1033
+ 'pomegranate',
1034
+ 'hay',
1035
+ 'carbonara',
1036
+ 'chocolate sauce, chocolate syrup',
1037
+ 'dough',
1038
+ 'meat loaf, meatloaf',
1039
+ 'pizza, pizza pie',
1040
+ 'potpie',
1041
+ 'burrito',
1042
+ 'red wine',
1043
+ 'espresso',
1044
+ 'cup',
1045
+ 'eggnog',
1046
+ 'alp',
1047
+ 'bubble',
1048
+ 'cliff, drop, drop-off',
1049
+ 'coral reef',
1050
+ 'geyser',
1051
+ 'lakeside, lakeshore',
1052
+ 'promontory, headland, head, foreland',
1053
+ 'sandbar, sand bar',
1054
+ 'seashore, coast, seacoast, sea-coast',
1055
+ 'valley, vale',
1056
+ 'volcano',
1057
+ 'ballplayer, baseball player',
1058
+ 'groom, bridegroom',
1059
+ 'scuba diver',
1060
+ 'rapeseed',
1061
+ 'daisy',
1062
+ "yellow lady's slipper, yellow lady-slipper, Cypripedium calceolus, Cypripedium parviflorum", # noqa: E501
1063
+ 'corn',
1064
+ 'acorn',
1065
+ 'hip, rose hip, rosehip',
1066
+ 'buckeye, horse chestnut, conker',
1067
+ 'coral fungus',
1068
+ 'agaric',
1069
+ 'gyromitra',
1070
+ 'stinkhorn, carrion fungus',
1071
+ 'earthstar',
1072
+ 'hen-of-the-woods, hen of the woods, Polyporus frondosus, Grifola frondosa', # noqa: E501
1073
+ 'bolete',
1074
+ 'ear, spike, capitulum',
1075
+ 'toilet tissue, toilet paper, bathroom tissue'
1076
+ ]
1077
+
1078
+ def load_annotations(self):
1079
+ if self.ann_file is None:
1080
+ folder_to_idx = find_folders(self.data_prefix)
1081
+ samples = get_samples(
1082
+ self.data_prefix,
1083
+ folder_to_idx,
1084
+ extensions=self.IMG_EXTENSIONS)
1085
+ if len(samples) == 0:
1086
+ raise (RuntimeError('Found 0 files in subfolders of: '
1087
+ f'{self.data_prefix}. '
1088
+ 'Supported extensions are: '
1089
+ f'{",".join(self.IMG_EXTENSIONS)}'))
1090
+
1091
+ self.folder_to_idx = folder_to_idx
1092
+ elif isinstance(self.ann_file, str):
1093
+ with open(self.ann_file) as f:
1094
+ samples = [x.strip().split(' ') for x in f.readlines()]
1095
+ else:
1096
+ raise TypeError('ann_file must be a str or None')
1097
+ self.samples = samples
1098
+
1099
+ data_infos = []
1100
+ for filename, gt_label in self.samples:
1101
+ info = {'img_prefix': self.data_prefix}
1102
+ info['img_info'] = {'filename': filename}
1103
+ info['gt_label'] = np.array(gt_label, dtype=np.int64)
1104
+ data_infos.append(info)
1105
+ return data_infos
CAGE_expression_inference-apvit/apvit_mmcls/datasets/mnist.py ADDED
@@ -0,0 +1,171 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import codecs
2
+ import os
3
+ import os.path as osp
4
+
5
+ import numpy as np
6
+ import torch
7
+
8
+ from .base_dataset import BaseDataset
9
+ from .builder import DATASETS
10
+ from .utils import download_and_extract_archive, rm_suffix
11
+
12
+
13
+ @DATASETS.register_module()
14
+ class MNIST(BaseDataset):
15
+ """`MNIST <http://yann.lecun.com/exdb/mnist/>`_ Dataset.
16
+
17
+ This implementation is modified from
18
+ https://github.com/pytorch/vision/blob/master/torchvision/datasets/mnist.py # noqa: E501
19
+ """
20
+
21
+ resource_prefix = 'http://yann.lecun.com/exdb/mnist/'
22
+ resources = {
23
+ 'train_image_file':
24
+ ('train-images-idx3-ubyte.gz', 'f68b3c2dcbeaaa9fbdd348bbdeb94873'),
25
+ 'train_label_file':
26
+ ('train-labels-idx1-ubyte.gz', 'd53e105ee54ea40749a09fcbcd1e9432'),
27
+ 'test_image_file':
28
+ ('t10k-images-idx3-ubyte.gz', '9fb629c4189551a2d022fa330f9573f3'),
29
+ 'test_label_file':
30
+ ('t10k-labels-idx1-ubyte.gz', 'ec29112dd5afa0611ce80d1b7f02629c')
31
+ }
32
+
33
+ CLASSES = [
34
+ '0 - zero', '1 - one', '2 - two', '3 - three', '4 - four', '5 - five',
35
+ '6 - six', '7 - seven', '8 - eight', '9 - nine'
36
+ ]
37
+
38
+ def load_annotations(self):
39
+ train_image_file = osp.join(
40
+ self.data_prefix, rm_suffix(self.resources['train_image_file'][0]))
41
+ train_label_file = osp.join(
42
+ self.data_prefix, rm_suffix(self.resources['train_label_file'][0]))
43
+ test_image_file = osp.join(
44
+ self.data_prefix, rm_suffix(self.resources['test_image_file'][0]))
45
+ test_label_file = osp.join(
46
+ self.data_prefix, rm_suffix(self.resources['test_label_file'][0]))
47
+
48
+ if not osp.exists(train_image_file) or not osp.exists(
49
+ train_label_file) or not osp.exists(
50
+ test_image_file) or not osp.exists(test_label_file):
51
+ self.download()
52
+
53
+ train_set = (read_image_file(train_image_file),
54
+ read_label_file(train_label_file))
55
+ test_set = (read_image_file(test_image_file),
56
+ read_label_file(test_label_file))
57
+
58
+ if not self.test_mode:
59
+ imgs, gt_labels = train_set
60
+ else:
61
+ imgs, gt_labels = test_set
62
+
63
+ data_infos = []
64
+ for img, gt_label in zip(imgs, gt_labels):
65
+ gt_label = np.array(gt_label, dtype=np.int64)
66
+ info = {'img': img.numpy(), 'gt_label': gt_label}
67
+ data_infos.append(info)
68
+ return data_infos
69
+
70
+ def download(self):
71
+ os.makedirs(self.data_prefix, exist_ok=True)
72
+
73
+ # download files
74
+ for url, md5 in self.resources.values():
75
+ url = osp.join(self.resource_prefix, url)
76
+ filename = url.rpartition('/')[2]
77
+ download_and_extract_archive(
78
+ url,
79
+ download_root=self.data_prefix,
80
+ filename=filename,
81
+ md5=md5)
82
+
83
+
84
+ @DATASETS.register_module()
85
+ class FashionMNIST(MNIST):
86
+ """`Fashion-MNIST <https://github.com/zalandoresearch/fashion-mnist>`_
87
+ Dataset.
88
+ """
89
+
90
+ resource_prefix = 'http://fashion-mnist.s3-website.eu-central-1.amazonaws.com/' # noqa: E501
91
+ resources = {
92
+ 'train_image_file':
93
+ ('train-images-idx3-ubyte.gz', '8d4fb7e6c68d591d4c3dfef9ec88bf0d'),
94
+ 'train_label_file':
95
+ ('train-labels-idx1-ubyte.gz', '25c81989df183df01b3e8a0aad5dffbe'),
96
+ 'test_image_file':
97
+ ('t10k-images-idx3-ubyte.gz', 'bef4ecab320f06d8554ea6380940ec79'),
98
+ 'test_label_file':
99
+ ('t10k-labels-idx1-ubyte.gz', 'bb300cfdad3c16e7a12a480ee83cd310')
100
+ }
101
+ CLASSES = [
102
+ 'T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat', 'Sandal',
103
+ 'Shirt', 'Sneaker', 'Bag', 'Ankle boot'
104
+ ]
105
+
106
+
107
+ def get_int(b):
108
+ return int(codecs.encode(b, 'hex'), 16)
109
+
110
+
111
+ def open_maybe_compressed_file(path):
112
+ """Return a file object that possibly decompresses 'path' on the fly.
113
+ Decompression occurs when argument `path` is a string
114
+ and ends with '.gz' or '.xz'.
115
+ """
116
+ if not isinstance(path, str):
117
+ return path
118
+ if path.endswith('.gz'):
119
+ import gzip
120
+ return gzip.open(path, 'rb')
121
+ if path.endswith('.xz'):
122
+ import lzma
123
+ return lzma.open(path, 'rb')
124
+ return open(path, 'rb')
125
+
126
+
127
+ def read_sn3_pascalvincent_tensor(path, strict=True):
128
+ """Read a SN3 file in "Pascal Vincent" format
129
+ (Lush file 'libidx/idx-io.lsh').
130
+ Argument may be a filename, compressed filename, or file object.
131
+ """
132
+ # typemap
133
+ if not hasattr(read_sn3_pascalvincent_tensor, 'typemap'):
134
+ read_sn3_pascalvincent_tensor.typemap = {
135
+ 8: (torch.uint8, np.uint8, np.uint8),
136
+ 9: (torch.int8, np.int8, np.int8),
137
+ 11: (torch.int16, np.dtype('>i2'), 'i2'),
138
+ 12: (torch.int32, np.dtype('>i4'), 'i4'),
139
+ 13: (torch.float32, np.dtype('>f4'), 'f4'),
140
+ 14: (torch.float64, np.dtype('>f8'), 'f8')
141
+ }
142
+ # read
143
+ with open_maybe_compressed_file(path) as f:
144
+ data = f.read()
145
+ # parse
146
+ magic = get_int(data[0:4])
147
+ nd = magic % 256
148
+ ty = magic // 256
149
+ assert nd >= 1 and nd <= 3
150
+ assert ty >= 8 and ty <= 14
151
+ m = read_sn3_pascalvincent_tensor.typemap[ty]
152
+ s = [get_int(data[4 * (i + 1):4 * (i + 2)]) for i in range(nd)]
153
+ parsed = np.frombuffer(data, dtype=m[1], offset=(4 * (nd + 1)))
154
+ assert parsed.shape[0] == np.prod(s) or not strict
155
+ return torch.from_numpy(parsed.astype(m[2], copy=False)).view(*s)
156
+
157
+
158
+ def read_label_file(path):
159
+ with open(path, 'rb') as f:
160
+ x = read_sn3_pascalvincent_tensor(f, strict=False)
161
+ assert (x.dtype == torch.uint8)
162
+ assert (x.ndimension() == 1)
163
+ return x.long()
164
+
165
+
166
+ def read_image_file(path):
167
+ with open(path, 'rb') as f:
168
+ x = read_sn3_pascalvincent_tensor(f, strict=False)
169
+ assert (x.dtype == torch.uint8)
170
+ assert (x.ndimension() == 3)
171
+ return x
CAGE_expression_inference-apvit/apvit_mmcls/datasets/pipelines/__init__.py ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from .compose import Compose
2
+ from .formating import (Collect, ImageToTensor, ToNumpy, ToPIL, ToTensor,
3
+ Transpose, to_tensor)
4
+ from .loading import LoadImageFromFile
5
+ from .transforms import (RandomAppliedTrans, CenterCrop, RandomCrop, RandomFlip, RandomGrayscale,
6
+ RandomResizedCrop, Resize, RandomRotate, ColorJitter)
7
+ from .test_time_aug import MultiScaleFlipAug
8
+
9
+ __all__ = [
10
+ 'Compose', 'to_tensor', 'ToTensor', 'ImageToTensor', 'ToPIL', 'ToNumpy',
11
+ 'Transpose', 'Collect', 'LoadImageFromFile', 'Resize', 'CenterCrop',
12
+ 'RandomFlip', 'Normalize', 'RandomCrop', 'RandomResizedCrop',
13
+ 'RandomGrayscale', 'RandomAppliedTrans', 'RandomRotate', 'ColorJitter',
14
+ 'MultiScaleFlipAug'
15
+ ]
CAGE_expression_inference-apvit/apvit_mmcls/datasets/pipelines/compose.py ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from collections.abc import Sequence
2
+
3
+ from mmcv.utils import build_from_cfg
4
+
5
+ from ..builder import PIPELINES
6
+
7
+
8
+ @PIPELINES.register_module()
9
+ class Compose(object):
10
+ """Compose a data pipeline with a sequence of transforms.
11
+
12
+ Args:
13
+ transforms (list[dict | callable]):
14
+ Either config dicts of transforms or transform objects.
15
+ """
16
+
17
+ def __init__(self, transforms):
18
+ assert isinstance(transforms, Sequence)
19
+ self.transforms = []
20
+ for transform in transforms:
21
+ if isinstance(transform, dict):
22
+ transform = build_from_cfg(transform, PIPELINES)
23
+ self.transforms.append(transform)
24
+ elif callable(transform):
25
+ self.transforms.append(transform)
26
+ else:
27
+ raise TypeError('transform must be callable or a dict, but got'
28
+ f' {type(transform)}')
29
+
30
+ def __call__(self, data):
31
+ for t in self.transforms:
32
+ data = t(data)
33
+ if data is None:
34
+ return None
35
+ return data
36
+
37
+ def __repr__(self):
38
+ format_string = self.__class__.__name__ + '('
39
+ for t in self.transforms:
40
+ format_string += f'\n {t}'
41
+ format_string += '\n)'
42
+ return format_string
CAGE_expression_inference-apvit/apvit_mmcls/datasets/pipelines/formating.py ADDED
@@ -0,0 +1,156 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from collections.abc import Sequence
2
+
3
+ import mmcv
4
+ import numpy as np
5
+ import torch
6
+ from PIL import Image
7
+
8
+ from ..builder import PIPELINES
9
+
10
+
11
+ def to_tensor(data):
12
+ """Convert objects of various python types to :obj:`torch.Tensor`.
13
+
14
+ Supported types are: :class:`numpy.ndarray`, :class:`torch.Tensor`,
15
+ :class:`Sequence`, :class:`int` and :class:`float`.
16
+ """
17
+ if isinstance(data, torch.Tensor):
18
+ return data
19
+ elif isinstance(data, np.ndarray):
20
+ return torch.from_numpy(data)
21
+ elif isinstance(data, Sequence) and not mmcv.is_str(data):
22
+ return torch.tensor(data)
23
+ elif isinstance(data, int):
24
+ return torch.LongTensor([data])
25
+ elif isinstance(data, float):
26
+ return torch.FloatTensor([data])
27
+ else:
28
+ raise TypeError(
29
+ f'Type {type(data)} cannot be converted to tensor.'
30
+ 'Supported types are: `numpy.ndarray`, `torch.Tensor`, '
31
+ '`Sequence`, `int` and `float`')
32
+
33
+
34
+ @PIPELINES.register_module()
35
+ class ToTensor(object):
36
+
37
+ def __init__(self, keys):
38
+ self.keys = keys
39
+
40
+ def __call__(self, results):
41
+ for key in self.keys:
42
+ results[key] = to_tensor(results[key])
43
+ return results
44
+
45
+ def __repr__(self):
46
+ return self.__class__.__name__ + f'(keys={self.keys})'
47
+
48
+
49
+ @PIPELINES.register_module()
50
+ class ImageToTensor(object):
51
+
52
+ def __init__(self, keys):
53
+ self.keys = keys
54
+
55
+ def __call__(self, results):
56
+ for key in self.keys:
57
+ img = results[key]
58
+ if len(img.shape) < 3:
59
+ img = np.expand_dims(img, -1)
60
+ results[key] = to_tensor(img.transpose(2, 0, 1))
61
+ return results
62
+
63
+ def __repr__(self):
64
+ return self.__class__.__name__ + f'(keys={self.keys})'
65
+
66
+
67
+ @PIPELINES.register_module()
68
+ class Transpose(object):
69
+
70
+ def __init__(self, keys, order):
71
+ self.keys = keys
72
+ self.order = order
73
+
74
+ def __call__(self, results):
75
+ for key in self.keys:
76
+ results[key] = results[key].transpose(self.order)
77
+ return results
78
+
79
+ def __repr__(self):
80
+ return self.__class__.__name__ + \
81
+ f'(keys={self.keys}, order={self.order})'
82
+
83
+
84
+ @PIPELINES.register_module()
85
+ class ToPIL(object):
86
+
87
+ def __init__(self):
88
+ pass
89
+
90
+ def __call__(self, results):
91
+ results['img'] = Image.fromarray(results['img'])
92
+ return results
93
+
94
+
95
+ @PIPELINES.register_module()
96
+ class ToNumpy(object):
97
+
98
+ def __init__(self):
99
+ pass
100
+
101
+ def __call__(self, results):
102
+ results['img'] = np.array(results['img'], dtype=np.float32)
103
+ return results
104
+
105
+
106
+ @PIPELINES.register_module()
107
+ class Collect(object):
108
+ """
109
+ Collect data from the loader relevant to the specific task.
110
+
111
+ This is usually the last stage of the data loader pipeline. Typically keys
112
+ is set to some subset of "img" and "gt_label".
113
+ """
114
+
115
+ def __init__(self, keys):
116
+ self.keys = keys
117
+
118
+ def __call__(self, results):
119
+ data = {}
120
+ for key in self.keys:
121
+ data[key] = results[key]
122
+ return data
123
+
124
+ def __repr__(self):
125
+ return self.__class__.__name__ + \
126
+ f'(keys={self.keys}, meta_keys={self.meta_keys})'
127
+
128
+
129
+ @PIPELINES.register_module()
130
+ class WrapFieldsToLists(object):
131
+ """Wrap fields of the data dictionary into lists for evaluation.
132
+
133
+ This class can be used as a last step of a test or validation
134
+ pipeline for single image evaluation or inference.
135
+
136
+ Example:
137
+ >>> test_pipeline = [
138
+ >>> dict(type='LoadImageFromFile'),
139
+ >>> dict(type='Normalize',
140
+ mean=[123.675, 116.28, 103.53],
141
+ std=[58.395, 57.12, 57.375],
142
+ to_rgb=True),
143
+ >>> dict(type='ImageToTensor', keys=['img']),
144
+ >>> dict(type='Collect', keys=['img']),
145
+ >>> dict(type='WrapIntoLists')
146
+ >>> ]
147
+ """
148
+
149
+ def __call__(self, results):
150
+ # Wrap dict fields into lists
151
+ for key, val in results.items():
152
+ results[key] = [val]
153
+ return results
154
+
155
+ def __repr__(self):
156
+ return f'{self.__class__.__name__}()'
CAGE_expression_inference-apvit/apvit_mmcls/datasets/pipelines/loading.py ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os.path as osp
2
+
3
+ import mmcv
4
+ import numpy as np
5
+
6
+ from ..builder import PIPELINES
7
+
8
+
9
+ @PIPELINES.register_module()
10
+ class LoadImageFromFile(object):
11
+ """Load an image from file.
12
+
13
+ Required keys are "img_prefix" and "img_info" (a dict that must contain the
14
+ key "filename"). Added or updated keys are "filename", "img", "img_shape",
15
+ "ori_shape" (same as `img_shape`) and "img_norm_cfg" (means=0 and stds=1).
16
+
17
+ Args:
18
+ to_float32 (bool): Whether to convert the loaded image to a float32
19
+ numpy array. If set to False, the loaded image is an uint8 array.
20
+ Defaults to False.
21
+ color_type (str): The flag argument for :func:`mmcv.imfrombytes()`.
22
+ Defaults to 'color'.
23
+ file_client_args (dict): Arguments to instantiate a FileClient.
24
+ See :class:`mmcv.fileio.FileClient` for details.
25
+ Defaults to ``dict(backend='disk')``.
26
+ """
27
+
28
+ def __init__(self,
29
+ to_float32=False,
30
+ color_type='color',
31
+ file_client_args=dict(backend='disk')):
32
+ self.to_float32 = to_float32
33
+ self.color_type = color_type
34
+ self.file_client_args = file_client_args.copy()
35
+ self.file_client = None
36
+
37
+ def __call__(self, results):
38
+ if self.file_client is None:
39
+ self.file_client = mmcv.FileClient(**self.file_client_args)
40
+
41
+ if results['img_prefix'] is not None:
42
+ filename = osp.join(results['img_prefix'],
43
+ results['img_info']['filename'])
44
+ else:
45
+ filename = results['img_info']['filename']
46
+
47
+ img_bytes = self.file_client.get(filename)
48
+ img = mmcv.imfrombytes(img_bytes, flag=self.color_type)
49
+ if self.to_float32:
50
+ img = img.astype(np.float32)
51
+ results['filename'] = filename
52
+ results['img'] = img
53
+ results['img_shape'] = img.shape
54
+ results['ori_shape'] = img.shape
55
+ num_channels = 1 if len(img.shape) < 3 else img.shape[2]
56
+ results['img_norm_cfg'] = dict(
57
+ mean=np.zeros(num_channels, dtype=np.float32),
58
+ std=np.ones(num_channels, dtype=np.float32),
59
+ to_rgb=False)
60
+ return results
61
+
62
+ def __repr__(self):
63
+ repr_str = (f'{self.__class__.__name__}('
64
+ f'to_float32={self.to_float32}, '
65
+ f"color_type='{self.color_type}', "
66
+ f'file_client_args={self.file_client_args})')
67
+ return repr_str
CAGE_expression_inference-apvit/apvit_mmcls/datasets/pipelines/test_time_aug.py ADDED
@@ -0,0 +1,126 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import warnings
2
+
3
+ import mmcv
4
+
5
+ from ..builder import PIPELINES
6
+ from .compose import Compose
7
+
8
+
9
+ @PIPELINES.register_module()
10
+ class MultiScaleFlipAug(object):
11
+ """Test-time augmentation with multiple scales and flipping.
12
+
13
+ An example configuration is as followed:
14
+
15
+ .. code-block::
16
+
17
+ img_scale=(2048, 1024),
18
+ img_ratios=[0.5, 1.0],
19
+ flip=True,
20
+ transforms=[
21
+ dict(type='Resize', keep_ratio=True),
22
+ dict(type='RandomFlip'),
23
+ dict(type='Normalize', **img_norm_cfg),
24
+ dict(type='Pad', size_divisor=32),
25
+ dict(type='ImageToTensor', keys=['img']),
26
+ dict(type='Collect', keys=['img']),
27
+ ]
28
+
29
+ After MultiScaleFLipAug with above configuration, the results are wrapped
30
+ into lists of the same length as followed:
31
+
32
+ .. code-block::
33
+
34
+ dict(
35
+ img=[...],
36
+ img_shape=[...],
37
+ scale=[(1024, 512), (1024, 512), (2048, 1024), (2048, 1024)]
38
+ flip=[False, True, False, True]
39
+ ...
40
+ )
41
+
42
+ Args:
43
+ transforms (list[dict]): Transforms to apply in each augmentation.
44
+ img_scale (tuple | list[tuple]): Images scales for resizing.
45
+ img_ratios (float | list[float]): Image ratios for resizing
46
+ flip (bool): Whether apply flip augmentation. Default: False.
47
+ flip_direction (str | list[str]): Flip augmentation directions,
48
+ options are "horizontal" and "vertical". If flip_direction is list,
49
+ multiple flip augmentations will be applied.
50
+ It has no effect when flip == False. Default: "horizontal".
51
+ """
52
+
53
+ def __init__(self,
54
+ transforms,
55
+ img_scale,
56
+ num=8,
57
+ img_ratios=None,
58
+ flip=False,
59
+ flip_direction='horizontal'):
60
+ self.transforms = Compose(transforms)
61
+ self.num = num
62
+ if img_ratios is not None:
63
+ # mode 1: given a scale and a range of image ratio
64
+ img_ratios = img_ratios if isinstance(img_ratios,
65
+ list) else [img_ratios]
66
+ assert mmcv.is_list_of(img_ratios, float)
67
+ assert isinstance(img_scale, tuple) and len(img_scale) == 2
68
+ self.img_scale = [(int(img_scale[0] * ratio),
69
+ int(img_scale[1] * ratio))
70
+ for ratio in img_ratios]
71
+ else:
72
+ # mode 2: given multiple scales
73
+ self.img_scale = img_scale if isinstance(img_scale,
74
+ list) else [img_scale]
75
+ assert mmcv.is_list_of(self.img_scale, tuple)
76
+ self.flip = flip
77
+ self.flip_direction = flip_direction if isinstance(
78
+ flip_direction, list) else [flip_direction]
79
+ assert mmcv.is_list_of(self.flip_direction, str)
80
+ if not self.flip and self.flip_direction != ['horizontal']:
81
+ warnings.warn(
82
+ 'flip_direction has no effect when flip is set to False')
83
+ if (self.flip
84
+ and not any([t['type'] == 'RandomFlip' for t in transforms])):
85
+ warnings.warn(
86
+ 'flip has no effect when RandomFlip is not in transforms')
87
+
88
+ def __call__(self, results):
89
+ """Call function to apply test time augment transforms on results.
90
+
91
+ Args:
92
+ results (dict): Result dict contains the data to transform.
93
+
94
+ Returns:
95
+ dict[str: list]: The augmented data, where each value is wrapped
96
+ into a list.
97
+ """
98
+
99
+ aug_data = []
100
+ # flip_aug = [False, True] if self.flip else [False]
101
+ # for scale in self.img_scale:
102
+ # for flip in flip_aug:
103
+ # for direction in self.flip_direction:
104
+ # _results = results.copy()
105
+ # _results['scale'] = scale
106
+ # _results['flip'] = flip
107
+ # _results['flip_direction'] = direction
108
+ # data = self.transforms(_results)
109
+ # aug_data.append(data)
110
+ for _ in range(self.num):
111
+ _results = results.copy()
112
+ data = self.transforms(_results)
113
+ aug_data.append(data)
114
+ # list of dict to dict of list
115
+ aug_data_dict = {key: [] for key in aug_data[0]}
116
+ for data in aug_data:
117
+ for key, val in data.items():
118
+ aug_data_dict[key].append(val)
119
+ return aug_data_dict
120
+
121
+ def __repr__(self):
122
+ repr_str = self.__class__.__name__
123
+ repr_str += f'(transforms={self.transforms}, '
124
+ repr_str += f'img_scale={self.img_scale}, flip={self.flip})'
125
+ repr_str += f'flip_direction={self.flip_direction}'
126
+ return repr_str
CAGE_expression_inference-apvit/apvit_mmcls/datasets/pipelines/transforms.py ADDED
@@ -0,0 +1,918 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import inspect
2
+ import math
3
+ import random
4
+ import numbers
5
+ import warnings
6
+ from typing import Tuple, List, Optional
7
+
8
+ import cv2
9
+ import mmcv
10
+ import numpy as np
11
+ from PIL import Image, ImageFilter
12
+
13
+ import torch
14
+ from torch import Tensor
15
+ from torchvision import transforms as _transforms
16
+ import torchvision.transforms.functional as TVF
17
+ from mmcv.utils import build_from_cfg
18
+
19
+ from ..builder import PIPELINES
20
+
21
+ try:
22
+ import albumentations
23
+ from albumentations import Compose
24
+ except ImportError:
25
+ albumentations = None
26
+ Compose = None
27
+
28
+
29
+ @PIPELINES.register_module()
30
+ class RandomAppliedTrans(object):
31
+ """Randomly applied transformations.
32
+
33
+ Args:
34
+ transforms (list[dict]): List of transformations in dictionaries.
35
+ p (float): Probability.
36
+ """
37
+
38
+ def __init__(self, transforms, p=0.5):
39
+ t = [build_from_cfg(t, PIPELINES) for t in transforms]
40
+ self.trans = _transforms.RandomApply(t, p=p)
41
+
42
+ def __call__(self, img):
43
+ return self.trans(img)
44
+
45
+ def __repr__(self):
46
+ repr_str = self.__class__.__name__
47
+ return repr_str
48
+
49
+
50
+ @PIPELINES.register_module()
51
+ class RandomCrop(object):
52
+ """Crop the given Image at a random location.
53
+
54
+ Args:
55
+ size (sequence or int): Desired output size of the crop. If size is an
56
+ int instead of sequence like (h, w), a square crop (size, size) is
57
+ made.
58
+ padding (int or sequence, optional): Optional padding on each border
59
+ of the image. If a sequence of length 4 is provided, it is used to
60
+ pad left, top, right, bottom borders respectively. If a sequence
61
+ of length 2 is provided, it is used to pad left/right, top/bottom
62
+ borders, respectively. Default: None, which means no padding.
63
+ pad_if_needed (boolean): It will pad the image if smaller than the
64
+ desired size to avoid raising an exception. Since cropping is done
65
+ after padding, the padding seems to be done at a random offset.
66
+ Default: False.
67
+ pad_val (Number | Sequence[Number]): Pixel pad_val value for constant
68
+ fill. If a tuple of length 3, it is used to pad_val R, G, B
69
+ channels respectively. Default: 0.
70
+ padding_mode (str): Type of padding. Should be: constant, edge,
71
+ reflect or symmetric. Default: constant.
72
+ -constant: Pads with a constant value, this value is specified
73
+ with pad_val.
74
+ -edge: pads with the last value at the edge of the image.
75
+ -reflect: Pads with reflection of image without repeating the
76
+ last value on the edge. For example, padding [1, 2, 3, 4]
77
+ with 2 elements on both sides in reflect mode will result
78
+ in [3, 2, 1, 2, 3, 4, 3, 2].
79
+ -symmetric: Pads with reflection of image repeating the last
80
+ value on the edge. For example, padding [1, 2, 3, 4] with
81
+ 2 elements on both sides in symmetric mode will result in
82
+ [2, 1, 1, 2, 3, 4, 4, 3].
83
+ """
84
+
85
+ def __init__(self,
86
+ size,
87
+ padding=None,
88
+ pad_if_needed=False,
89
+ pad_val=0,
90
+ padding_mode='constant'):
91
+ if isinstance(size, (tuple, list)):
92
+ self.size = size
93
+ else:
94
+ self.size = (size, size)
95
+ # check padding mode
96
+ assert padding_mode in ['constant', 'edge', 'reflect', 'symmetric']
97
+ self.padding = padding
98
+ self.pad_if_needed = pad_if_needed
99
+ self.pad_val = pad_val
100
+ self.padding_mode = padding_mode
101
+
102
+ @staticmethod
103
+ def get_params(img, output_size):
104
+ """Get parameters for ``crop`` for a random crop.
105
+
106
+ Args:
107
+ img (ndarray): Image to be cropped.
108
+ output_size (tuple): Expected output size of the crop.
109
+
110
+ Returns:
111
+ tuple: Params (xmin, ymin, target_height, target_width) to be
112
+ passed to ``crop`` for random crop.
113
+ """
114
+ height = img.shape[0]
115
+ width = img.shape[1]
116
+ target_height, target_width = output_size
117
+ if width == target_width and height == target_height:
118
+ return 0, 0, height, width
119
+
120
+ xmin = random.randint(0, height - target_height)
121
+ ymin = random.randint(0, width - target_width)
122
+ return xmin, ymin, target_height, target_width
123
+
124
+ def __call__(self, results):
125
+ """
126
+ Args:
127
+ img (ndarray): Image to be cropped.
128
+ """
129
+ for key in results.get('img_fields', ['img']):
130
+ img = results[key]
131
+ if self.padding is not None:
132
+ img = mmcv.impad(
133
+ img, padding=self.padding, pad_val=self.pad_val)
134
+
135
+ # pad the height if needed
136
+ if self.pad_if_needed and img.shape[0] < self.size[0]:
137
+ img = mmcv.impad(
138
+ img,
139
+ padding=(0, self.size[0] - img.shape[0], 0,
140
+ self.size[0] - img.shape[0]),
141
+ pad_val=self.pad_val,
142
+ padding_mode=self.padding_mode)
143
+
144
+ # pad the width if needed
145
+ if self.pad_if_needed and img.shape[1] < self.size[1]:
146
+ img = mmcv.impad(
147
+ img,
148
+ padding=(self.size[1] - img.shape[1], 0,
149
+ self.size[1] - img.shape[1], 0),
150
+ pad_val=self.pad_val,
151
+ padding_mode=self.padding_mode)
152
+
153
+ xmin, ymin, height, width = self.get_params(img, self.size)
154
+ results[key] = mmcv.imcrop(
155
+ img,
156
+ np.array([ymin, xmin, ymin + width - 1, xmin + height - 1]))
157
+ return results
158
+
159
+ def __repr__(self):
160
+ return (self.__class__.__name__ +
161
+ f'(size={self.size}, padding={self.padding})')
162
+
163
+
164
+ @PIPELINES.register_module()
165
+ class RandomResizedCrop(object):
166
+ """Crop the given image to random size and aspect ratio.
167
+
168
+ A crop of random size (default: of 0.08 to 1.0) of the original size and a
169
+ random aspect ratio (default: of 3/4 to 4/3) of the original aspect ratio
170
+ is made. This crop is finally resized to given size.
171
+
172
+ Args:
173
+ size (sequence or int): Desired output size of the crop. If size is an
174
+ int instead of sequence like (h, w), a square crop (size, size) is
175
+ made.
176
+ scale (tuple): Range of the random size of the cropped image compared
177
+ to the original image. Default: (0.08, 1.0).
178
+ ratio (tuple): Range of the random aspect ratio of the cropped image
179
+ compared to the original image. Default: (3. / 4., 4. / 3.).
180
+ interpolation (str): Interpolation method, accepted values are
181
+ 'nearest', 'bilinear', 'bicubic', 'area', 'lanczos'. Default:
182
+ 'bilinear'.
183
+ backend (str): The image resize backend type, accpeted values are
184
+ `cv2` and `pillow`. Default: `cv2`.
185
+ """
186
+
187
+ def __init__(self,
188
+ size,
189
+ scale=(0.08, 1.0),
190
+ ratio=(3. / 4., 4. / 3.),
191
+ interpolation='bilinear',
192
+ backend='cv2'):
193
+ if isinstance(size, (tuple, list)):
194
+ self.size = size
195
+ else:
196
+ self.size = (size, size)
197
+ if (scale[0] > scale[1]) or (ratio[0] > ratio[1]):
198
+ raise ValueError('range should be of kind (min, max). '
199
+ f'But received {scale}')
200
+ if backend not in ['cv2', 'pillow']:
201
+ raise ValueError(f'backend: {backend} is not supported for resize.'
202
+ 'Supported backends are "cv2", "pillow"')
203
+
204
+ self.interpolation = interpolation
205
+ self.scale = scale
206
+ self.ratio = ratio
207
+ self.backend = backend
208
+
209
+ @staticmethod
210
+ def get_params(img, scale, ratio):
211
+ """Get parameters for ``crop`` for a random sized crop.
212
+
213
+ Args:
214
+ img (ndarray): Image to be cropped.
215
+ scale (tuple): Range of the random size of the cropped image
216
+ compared to the original image size.
217
+ ratio (tuple): Range of the random aspect ratio of the cropped
218
+ image compared to the original image area.
219
+
220
+ Returns:
221
+ tuple: Params (xmin, ymin, target_height, target_width) to be
222
+ passed to ``crop`` for a random sized crop.
223
+ """
224
+ height = img.shape[0]
225
+ width = img.shape[1]
226
+ area = height * width
227
+
228
+ for _ in range(10):
229
+ target_area = random.uniform(*scale) * area
230
+ log_ratio = (math.log(ratio[0]), math.log(ratio[1]))
231
+ aspect_ratio = math.exp(random.uniform(*log_ratio))
232
+
233
+ target_width = int(round(math.sqrt(target_area * aspect_ratio)))
234
+ target_height = int(round(math.sqrt(target_area / aspect_ratio)))
235
+
236
+ if 0 < target_width <= width and 0 < target_height <= height:
237
+ xmin = random.randint(0, height - target_height)
238
+ ymin = random.randint(0, width - target_width)
239
+ return xmin, ymin, target_height, target_width
240
+
241
+ # Fallback to central crop
242
+ in_ratio = float(width) / float(height)
243
+ if in_ratio < min(ratio):
244
+ target_width = width
245
+ target_height = int(round(target_width / min(ratio)))
246
+ elif in_ratio > max(ratio):
247
+ target_height = height
248
+ target_width = int(round(target_height * max(ratio)))
249
+ else: # whole image
250
+ target_width = width
251
+ target_height = height
252
+ xmin = (height - target_height) // 2
253
+ ymin = (width - target_width) // 2
254
+ return xmin, ymin, target_height, target_width
255
+
256
+ def __call__(self, results):
257
+ """
258
+ Args:
259
+ img (ndarray): Image to be cropped and resized.
260
+
261
+ Returns:
262
+ ndarray: Randomly cropped and resized image.
263
+ """
264
+ for key in results.get('img_fields', ['img']):
265
+ img = results[key]
266
+ xmin, ymin, target_height, target_width = self.get_params(
267
+ img, self.scale, self.ratio)
268
+ img = mmcv.imcrop(
269
+ img,
270
+ np.array([
271
+ ymin, xmin, ymin + target_width - 1,
272
+ xmin + target_height - 1
273
+ ]))
274
+ results[key] = mmcv.imresize(
275
+ img,
276
+ tuple(self.size[::-1]),
277
+ interpolation=self.interpolation,
278
+ backend=self.backend)
279
+ return results
280
+
281
+ def __repr__(self):
282
+ format_string = self.__class__.__name__ + f'(size={self.size}'
283
+ format_string += f', scale={tuple(round(s, 4) for s in self.scale)}'
284
+ format_string += f', ratio={tuple(round(r, 4) for r in self.ratio)}'
285
+ format_string += f', interpolation={self.interpolation})'
286
+ return format_string
287
+
288
+
289
+ @PIPELINES.register_module()
290
+ class RandomGrayscale(object):
291
+ """Randomly convert image to grayscale with a probability of gray_prob.
292
+
293
+ Args:
294
+ gray_prob (float): Probability that image should be converted to
295
+ grayscale. Default: 0.1.
296
+
297
+ Returns:
298
+ ndarray: Grayscale version of the input image with probability
299
+ gray_prob and unchanged with probability (1-gray_prob).
300
+ - If input image is 1 channel: grayscale version is 1 channel.
301
+ - If input image is 3 channel: grayscale version is 3 channel
302
+ with r == g == b.
303
+
304
+ """
305
+
306
+ def __init__(self, gray_prob=0.1):
307
+ self.gray_prob = gray_prob
308
+
309
+ def __call__(self, results):
310
+ """
311
+ Args:
312
+ img (ndarray): Image to be converted to grayscale.
313
+
314
+ Returns:
315
+ ndarray: Randomly grayscaled image.
316
+ """
317
+ for key in results.get('img_fields', ['img']):
318
+ img = results[key]
319
+ num_output_channels = img.shape[2]
320
+ if random.random() < self.gray_prob:
321
+ if num_output_channels > 1:
322
+ img = mmcv.rgb2gray(img)[:, :, None]
323
+ results[key] = np.dstack(
324
+ [img for _ in range(num_output_channels)])
325
+ return results
326
+ results[key] = img
327
+ return results
328
+
329
+ def __repr__(self):
330
+ return self.__class__.__name__ + f'(gray_prob={self.gray_prob})'
331
+
332
+
333
+ @PIPELINES.register_module()
334
+ class RandomFlip(object):
335
+ """Flip the image randomly.
336
+
337
+ Flip the image randomly based on flip probaility and flip direction.
338
+
339
+ Args:
340
+ flip_prob (float): probability of the image being flipped. Default: 0.5
341
+ direction (str, optional): The flipping direction. Options are
342
+ 'horizontal' and 'vertical'. Default: 'horizontal'.
343
+ """
344
+
345
+ def __init__(self, flip_prob=0.5, direction='horizontal'):
346
+ assert 0 <= flip_prob <= 1
347
+ assert direction in ['horizontal', 'vertical']
348
+ self.flip_prob = flip_prob
349
+ self.direction = direction
350
+
351
+ def __call__(self, results):
352
+ """Call function to flip image.
353
+
354
+ Args:
355
+ results (dict): Result dict from loading pipeline.
356
+
357
+ Returns:
358
+ dict: Flipped results, 'flip', 'flip_direction' keys are added into
359
+ result dict.
360
+ """
361
+ flip = True if np.random.rand() < self.flip_prob else False
362
+ results['flip'] = flip
363
+ results['flip_direction'] = self.direction
364
+ if results['flip']:
365
+ # flip image
366
+ for key in results.get('img_fields', ['img']):
367
+ results[key] = mmcv.imflip(
368
+ results[key], direction=results['flip_direction'])
369
+ return results
370
+
371
+ def __repr__(self):
372
+ return self.__class__.__name__ + f'(flip_prob={self.flip_prob})'
373
+
374
+
375
+ @PIPELINES.register_module()
376
+ class Resize(object):
377
+ """Resize images.
378
+
379
+ Args:
380
+ size (int | tuple): Images scales for resizing (h, w).
381
+ When size is int, the default behavior is to resize an image
382
+ to (size, size). When size is tuple and the second value is -1,
383
+ the short edge of an image is resized to its first value.
384
+ For example, when size is 224, the image is resized to 224x224.
385
+ When size is (224, -1), the short side is resized to 224 and the
386
+ other side is computed based on the short side, maintaining the
387
+ aspect ratio.
388
+ interpolation (str): Interpolation method, accepted values are
389
+ "nearest", "bilinear", "bicubic", "area", "lanczos".
390
+ More details can be found in `mmcv.image.geometric`.
391
+ backend (str): The image resize backend type, accpeted values are
392
+ `cv2` and `pillow`. Default: `cv2`.
393
+ """
394
+
395
+ def __init__(self, size, interpolation='bilinear', backend='cv2'):
396
+ assert isinstance(size, int) or (isinstance(size, tuple)
397
+ and len(size) == 2)
398
+ self.resize_w_short_side = False
399
+ if isinstance(size, int):
400
+ assert size > 0
401
+ size = (size, size)
402
+ else:
403
+ assert size[0] > 0 and (size[1] > 0 or size[1] == -1)
404
+ if size[1] == -1:
405
+ self.resize_w_short_side = True
406
+ assert interpolation in ('nearest', 'bilinear', 'bicubic', 'area',
407
+ 'lanczos')
408
+ if backend not in ['cv2', 'pillow']:
409
+ raise ValueError(f'backend: {backend} is not supported for resize.'
410
+ 'Supported backends are "cv2", "pillow"')
411
+
412
+ self.size = size
413
+ self.interpolation = interpolation
414
+ self.backend = backend
415
+
416
+ def _resize_img(self, results):
417
+ for key in results.get('img_fields', ['img']):
418
+ img = results[key]
419
+ ignore_resize = False
420
+ if self.resize_w_short_side:
421
+ h, w = img.shape[:2]
422
+ short_side = self.size[0]
423
+ if (w <= h and w == short_side) or (h <= w
424
+ and h == short_side):
425
+ ignore_resize = True
426
+ else:
427
+ if w < h:
428
+ width = short_side
429
+ height = int(short_side * h / w)
430
+ else:
431
+ height = short_side
432
+ width = int(short_side * w / h)
433
+ else:
434
+ height, width = self.size
435
+ if not ignore_resize:
436
+ img = mmcv.imresize(
437
+ img,
438
+ size=(width, height),
439
+ interpolation=self.interpolation,
440
+ return_scale=False,
441
+ backend=self.backend)
442
+ results[key] = img
443
+ results['img_shape'] = img.shape
444
+
445
+ def __call__(self, results):
446
+ self._resize_img(results)
447
+ return results
448
+
449
+ def __repr__(self):
450
+ repr_str = self.__class__.__name__
451
+ repr_str += f'(size={self.size}, '
452
+ repr_str += f'interpolation={self.interpolation})'
453
+ return repr_str
454
+
455
+
456
+ @PIPELINES.register_module()
457
+ class CenterCrop(object):
458
+ """Center crop the image.
459
+
460
+ Args:
461
+ crop_size (int | tuple): Expected size after cropping, (h, w).
462
+
463
+ Notes:
464
+ If the image is smaller than the crop size, return the original image
465
+ """
466
+
467
+ def __init__(self, crop_size):
468
+ assert isinstance(crop_size, int) or (isinstance(crop_size, tuple)
469
+ and len(crop_size) == 2)
470
+ if isinstance(crop_size, int):
471
+ crop_size = (crop_size, crop_size)
472
+ assert crop_size[0] > 0 and crop_size[1] > 0
473
+ self.crop_size = crop_size
474
+
475
+ def __call__(self, results):
476
+ crop_height, crop_width = self.crop_size[0], self.crop_size[1]
477
+ for key in results.get('img_fields', ['img']):
478
+ img = results[key]
479
+ # img.shape has length 2 for grayscale, length 3 for color
480
+ img_height, img_width = img.shape[:2]
481
+
482
+ y1 = max(0, int(round((img_height - crop_height) / 2.)))
483
+ x1 = max(0, int(round((img_width - crop_width) / 2.)))
484
+ y2 = min(img_height, y1 + crop_height) - 1
485
+ x2 = min(img_width, x1 + crop_width) - 1
486
+
487
+ # crop the image
488
+ img = mmcv.imcrop(img, bboxes=np.array([x1, y1, x2, y2]))
489
+ img_shape = img.shape
490
+ results[key] = img
491
+ results['img_shape'] = img_shape
492
+
493
+ return results
494
+
495
+ def __repr__(self):
496
+ return self.__class__.__name__ + f'(crop_size={self.crop_size})'
497
+
498
+
499
+ @PIPELINES.register_module()
500
+ class Normalize(object):
501
+ """Normalize the image.
502
+
503
+ Args:
504
+ mean (sequence): Mean values of 3 channels.
505
+ std (sequence): Std values of 3 channels.
506
+ to_rgb (bool): Whether to convert the image from BGR to RGB,
507
+ default is true.
508
+ """
509
+
510
+ def __init__(self, mean, std, to_rgb=True):
511
+ self.mean = np.array(mean, dtype=np.float32)
512
+ self.std = np.array(std, dtype=np.float32)
513
+ self.to_rgb = to_rgb
514
+
515
+ def __call__(self, results):
516
+ for key in results.get('img_fields', ['img']):
517
+ results[key] = mmcv.imnormalize(results[key], self.mean, self.std,
518
+ self.to_rgb)
519
+ results['img_norm_cfg'] = dict(
520
+ mean=self.mean, std=self.std, to_rgb=self.to_rgb)
521
+ return results
522
+
523
+ def __repr__(self):
524
+ repr_str = self.__class__.__name__
525
+ repr_str += f'(mean={list(self.mean)}, '
526
+ repr_str += f'std={list(self.std)}, '
527
+ repr_str += f'to_rgb={self.to_rgb})'
528
+ return repr_str
529
+
530
+
531
+ @PIPELINES.register_module()
532
+ class Albu(object):
533
+ """Albumentation augmentation.
534
+
535
+ Adds custom transformations from Albumentations library.
536
+ Please, visit `https://albumentations.readthedocs.io`
537
+ to get more information.
538
+ An example of ``transforms`` is as followed:
539
+
540
+ .. code-block::
541
+ [
542
+ dict(
543
+ type='ShiftScaleRotate',
544
+ shift_limit=0.0625,
545
+ scale_limit=0.0,
546
+ rotate_limit=0,
547
+ interpolation=1,
548
+ p=0.5),
549
+ dict(
550
+ type='RandomBrightnessContrast',
551
+ brightness_limit=[0.1, 0.3],
552
+ contrast_limit=[0.1, 0.3],
553
+ p=0.2),
554
+ dict(type='ChannelShuffle', p=0.1),
555
+ dict(
556
+ type='OneOf',
557
+ transforms=[
558
+ dict(type='Blur', blur_limit=3, p=1.0),
559
+ dict(type='MedianBlur', blur_limit=3, p=1.0)
560
+ ],
561
+ p=0.1),
562
+ ]
563
+
564
+ Args:
565
+ transforms (list[dict]): A list of albu transformations
566
+ keymap (dict): Contains {'input key':'albumentation-style key'}
567
+ """
568
+
569
+ def __init__(self, transforms, keymap=None, update_pad_shape=False):
570
+ if Compose is None:
571
+ raise RuntimeError('albumentations is not installed')
572
+
573
+ self.transforms = transforms
574
+ self.filter_lost_elements = False
575
+ self.update_pad_shape = update_pad_shape
576
+
577
+ self.aug = Compose([self.albu_builder(t) for t in self.transforms])
578
+
579
+ if not keymap:
580
+ self.keymap_to_albu = {
581
+ 'img': 'image',
582
+ }
583
+ else:
584
+ self.keymap_to_albu = keymap
585
+ self.keymap_back = {v: k for k, v in self.keymap_to_albu.items()}
586
+
587
+ def albu_builder(self, cfg):
588
+ """Import a module from albumentations.
589
+ It inherits some of :func:`build_from_cfg` logic.
590
+ Args:
591
+ cfg (dict): Config dict. It should at least contain the key "type".
592
+ Returns:
593
+ obj: The constructed object.
594
+ """
595
+
596
+ assert isinstance(cfg, dict) and 'type' in cfg
597
+ args = cfg.copy()
598
+
599
+ obj_type = args.pop('type')
600
+ if mmcv.is_str(obj_type):
601
+ if albumentations is None:
602
+ raise RuntimeError('albumentations is not installed')
603
+ obj_cls = getattr(albumentations, obj_type)
604
+ elif inspect.isclass(obj_type):
605
+ obj_cls = obj_type
606
+ else:
607
+ raise TypeError(
608
+ f'type must be a str or valid type, but got {type(obj_type)}')
609
+
610
+ if 'transforms' in args:
611
+ args['transforms'] = [
612
+ self.albu_builder(transform)
613
+ for transform in args['transforms']
614
+ ]
615
+
616
+ return obj_cls(**args)
617
+
618
+ @staticmethod
619
+ def mapper(d, keymap):
620
+ """Dictionary mapper. Renames keys according to keymap provided.
621
+ Args:
622
+ d (dict): old dict
623
+ keymap (dict): {'old_key':'new_key'}
624
+ Returns:
625
+ dict: new dict.
626
+ """
627
+
628
+ updated_dict = {}
629
+ for k, v in zip(d.keys(), d.values()):
630
+ new_k = keymap.get(k, k)
631
+ updated_dict[new_k] = d[k]
632
+ return updated_dict
633
+
634
+ def __call__(self, results):
635
+ # dict to albumentations format
636
+ results = self.mapper(results, self.keymap_to_albu)
637
+
638
+ results = self.aug(**results)
639
+
640
+ if 'gt_labels' in results:
641
+ if isinstance(results['gt_labels'], list):
642
+ results['gt_labels'] = np.array(results['gt_labels'])
643
+ results['gt_labels'] = results['gt_labels'].astype(np.int64)
644
+
645
+ # back to the original format
646
+ results = self.mapper(results, self.keymap_back)
647
+
648
+ # update final shape
649
+ if self.update_pad_shape:
650
+ results['pad_shape'] = results['img'].shape
651
+
652
+ return results
653
+
654
+ def __repr__(self):
655
+ repr_str = self.__class__.__name__ + f'(transforms={self.transforms})'
656
+ return repr_str
657
+
658
+ # custom transforms
659
+ @PIPELINES.register_module()
660
+ class GaussianBlur(object):
661
+
662
+ def __init__(self, sigma_min, sigma_max):
663
+ self.sigma_min = sigma_min
664
+ self.sigma_max = sigma_max
665
+
666
+ def __call__(self, results):
667
+ for key in results.get('img_fields', ['img']):
668
+ img = results[key]
669
+ sigma = np.random.uniform(self.sigma_min, self.sigma_max)
670
+ img = Image.fromarray(img)
671
+ img = img.filter(ImageFilter.GaussianBlur(radius=sigma))
672
+ results[key] = np.array(img).astype('float32')
673
+ return results
674
+
675
+ def __repr__(self):
676
+ repr_str = self.__class__.__name__
677
+ return repr_str
678
+
679
+
680
+ @PIPELINES.register_module()
681
+ class RandomRotate(object):
682
+ """Rotate the image & seg.
683
+
684
+ Args:
685
+ prob (float): The rotation probability.
686
+ degree (float, tuple[float]): Range of degrees to select from. If
687
+ degree is a number instead of tuple like (min, max),
688
+ the range of degree will be (``-degree``, ``+degree``)
689
+ pad_val (float, optional): Padding value of image. Default: 0.
690
+ center (tuple[float], optional): Center point (w, h) of the rotation in
691
+ the source image. If not specified, the center of the image will be
692
+ used. Default: None.
693
+ auto_bound (bool): Whether to adjust the image size to cover the whole
694
+ rotated image. Default: False
695
+ """
696
+
697
+ def __init__(self,
698
+ prob,
699
+ degree,
700
+ pad_val=0,
701
+ center=None,
702
+ auto_bound=False):
703
+ self.prob = prob
704
+ assert prob >= 0 and prob <= 1
705
+ if isinstance(degree, (float, int)):
706
+ assert degree > 0, f'degree {degree} should be positive'
707
+ self.degree = (-degree, degree)
708
+ else:
709
+ self.degree = degree
710
+ assert len(self.degree) == 2, f'degree {self.degree} should be a ' \
711
+ f'tuple of (min, max)'
712
+ self.pal_val = pad_val
713
+ self.center = center
714
+ self.auto_bound = auto_bound
715
+
716
+ def __call__(self, results):
717
+ """Call function to rotate image.
718
+
719
+ Args:
720
+ results (dict): Result dict from loading pipeline.
721
+
722
+ Returns:
723
+ dict: Rotated results.
724
+ """
725
+
726
+ rotate = True if np.random.rand() < self.prob else False
727
+ degree = np.random.uniform(min(*self.degree), max(*self.degree))
728
+ if rotate:
729
+ # rotate image
730
+ for key in results.get('img_fields', ['img']):
731
+ results[key] = mmcv.imrotate(
732
+ results[key],
733
+ angle=degree,
734
+ border_value=self.pal_val,
735
+ center=self.center,
736
+ auto_bound=self.auto_bound)
737
+
738
+ return results
739
+
740
+ def __repr__(self):
741
+ repr_str = self.__class__.__name__
742
+ repr_str += f'(prob={self.prob}, ' \
743
+ f'degree={self.degree}, ' \
744
+ f'pad_val={self.pal_val}, ' \
745
+ f'center={self.center}, ' \
746
+ f'auto_bound={self.auto_bound})'
747
+ return repr_str
748
+
749
+
750
+ @PIPELINES.register_module()
751
+ class RandomErasing:
752
+ """ Randomly selects a rectangle region in an image and erases its pixels.
753
+ 'Random Erasing Data Augmentation' by Zhong et al. See https://arxiv.org/abs/1708.04896
754
+
755
+ Args:
756
+ p: probability that the random erasing operation will be performed.
757
+ scale: range of proportion of erased area against input image.
758
+ ratio: range of aspect ratio of erased area.
759
+ value: erasing value. Default is 0. If a single int, it is used to
760
+ erase all pixels. If a tuple of length 3, it is used to erase
761
+ R, G, B channels respectively.
762
+ If a str of 'random', erasing each pixel with random values.
763
+ inplace: boolean to make this transform inplace. Default set to False.
764
+
765
+ Returns:
766
+ Erased Image.
767
+ """
768
+ def __init__(self, p=0.5, scale=(0.02, 0.33), ratio=(0.3, 3.3), value=0, inplace=False):
769
+ super().__init__()
770
+ if not isinstance(value, (numbers.Number, str, tuple, list)):
771
+ raise TypeError("Argument value should be either a number or str or a sequence")
772
+ if isinstance(value, str) and value != "random":
773
+ raise ValueError("If value is str, it should be 'random'")
774
+ if not isinstance(scale, (tuple, list)):
775
+ raise TypeError("Scale should be a sequence")
776
+ if not isinstance(ratio, (tuple, list)):
777
+ raise TypeError("Ratio should be a sequence")
778
+ if (scale[0] > scale[1]) or (ratio[0] > ratio[1]):
779
+ warnings.warn("Scale and ratio should be of kind (min, max)")
780
+ if scale[0] < 0 or scale[1] > 1:
781
+ raise ValueError("Scale should be between 0 and 1")
782
+ if p < 0 or p > 1:
783
+ raise ValueError("Random erasing probability should be between 0 and 1")
784
+
785
+ self.p = p
786
+ self.scale = scale
787
+ self.ratio = ratio
788
+ self.value = value
789
+ self.inplace = inplace
790
+
791
+ @staticmethod
792
+ def get_params(
793
+ img: Tensor, scale: Tuple[float, float], ratio: Tuple[float, float], value: Optional[List[float]] = None
794
+ ) -> Tuple[int, int, int, int, Tensor]:
795
+ """Get parameters for ``erase`` for a random erasing.
796
+
797
+ Args:
798
+ img (Tensor): Tensor image to be erased.
799
+ scale (tuple or list): range of proportion of erased area against input image.
800
+ ratio (tuple or list): range of aspect ratio of erased area.
801
+ value (list, optional): erasing value. If None, it is interpreted as "random"
802
+ (erasing each pixel with random values). If ``len(value)`` is 1, it is interpreted as a number,
803
+ i.e. ``value[0]``.
804
+
805
+ Returns:
806
+ tuple: params (i, j, h, w, v) to be passed to ``erase`` for random erasing.
807
+ """
808
+ img_c, img_h, img_w = img.shape[-3], img.shape[-2], img.shape[-1]
809
+ area = img_h * img_w
810
+
811
+ for _ in range(10):
812
+ erase_area = area * torch.empty(1).uniform_(scale[0], scale[1]).item()
813
+ aspect_ratio = torch.empty(1).uniform_(ratio[0], ratio[1]).item()
814
+
815
+ h = int(round(math.sqrt(erase_area * aspect_ratio)))
816
+ w = int(round(math.sqrt(erase_area / aspect_ratio)))
817
+ if not (h < img_h and w < img_w):
818
+ continue
819
+
820
+ if value is None:
821
+ v = torch.empty([img_c, h, w], dtype=torch.float32).normal_()
822
+ else:
823
+ v = torch.tensor(value)[:, None, None]
824
+
825
+ i = torch.randint(0, img_h - h + 1, size=(1, )).item()
826
+ j = torch.randint(0, img_w - w + 1, size=(1, )).item()
827
+ return i, j, h, w, v
828
+
829
+ # Return original image
830
+ return 0, 0, img_h, img_w, img
831
+
832
+ def __call__(self, results):
833
+ if torch.rand(1) < self.p:
834
+ for key in results.get('img_fields', ['img']):
835
+ img = results[key]
836
+ img = torch.Tensor(img.transpose([2,0,1]))
837
+ # the next process need C, H, W
838
+
839
+ # cast self.value to script acceptable type
840
+ if isinstance(self.value, (int, float)):
841
+ value = [self.value, ]
842
+ elif isinstance(self.value, str):
843
+ value = None
844
+ elif isinstance(self.value, tuple):
845
+ value = list(self.value)
846
+ else:
847
+ value = self.value
848
+
849
+ if value is not None and not (len(value) in (1, img.shape[-3])):
850
+ raise ValueError(
851
+ "If value is a sequence, it should have either a single value or "
852
+ "{} (number of input channels)".format(img.shape[-3])
853
+ )
854
+
855
+ x, y, h, w, v = self.get_params(img, scale=self.scale, ratio=self.ratio, value=value)
856
+ results[key] = TVF.erase(img, x, y, h, w, v, self.inplace).numpy().transpose([1,2,0])
857
+ return results
858
+
859
+
860
+ @PIPELINES.register_module()
861
+ class ColorJitter:
862
+ def __init__(self, brightness=0, contrast=0, saturation=0, hue=0):
863
+ self.func = _transforms.ColorJitter(brightness, contrast, saturation, hue)
864
+
865
+ def __call__(self, results):
866
+ for key in results.get('img_fields', ['img']):
867
+ img = results[key]
868
+ img = Image.fromarray(img)
869
+ results[key] = np.array(self.func(img))
870
+ return results
871
+
872
+ def __repr__(self):
873
+ return self.func.__repr__()
874
+
875
+
876
+ @PIPELINES.register_module()
877
+ class HistogramEqualization:
878
+
879
+ def __call__(self, results):
880
+ for key in results.get('img_fields', ['img']):
881
+ img = results[key]
882
+ # convert from RGB color-space to YCrCb
883
+ ycrcb_img = cv2.cvtColor(img, cv2.COLOR_BGR2YCrCb)
884
+
885
+ # equalize the histogram of the Y channel
886
+ ycrcb_img[:, :, 0] = cv2.equalizeHist(ycrcb_img[:, :, 0])
887
+
888
+ # convert back to RGB color-space from YCrCb
889
+ equalized_img = cv2.cvtColor(ycrcb_img, cv2.COLOR_YCrCb2BGR)
890
+ results[key] = equalized_img
891
+ return results
892
+
893
+
894
+ @PIPELINES.register_module()
895
+ class TorchNormalize:
896
+ """
897
+ Normalize in torchvision
898
+ """
899
+ def __init__(self, mean, std, inplace=False):
900
+ self.mean = mean
901
+ self.std = std
902
+ self.inplace = inplace
903
+
904
+ def __call__(self, results):
905
+ """
906
+ Args:
907
+ tensor (Tensor): Tensor image of size (C, H, W) to be normalized.
908
+
909
+ Returns:
910
+ Tensor: Normalized Tensor image.
911
+ """
912
+ for key in results.get('img_fields', ['img']):
913
+ img = results[key]
914
+ results[key] = _transforms.functional.normalize(img, self.mean, self.std, self.inplace)
915
+ return results
916
+
917
+ def __repr__(self):
918
+ return self.__class__.__name__ + '(mean={0}, std={1})'.format(self.mean, self.std)
CAGE_expression_inference-apvit/apvit_mmcls/datasets/raf.py ADDED
@@ -0,0 +1,144 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import random
3
+ from typing import Any, Dict
4
+
5
+ import numpy as np
6
+ from mmcls.models.losses import accuracy, f1_score, precision, recall
7
+ from mmcls.models.losses.eval_metrics import class_accuracy
8
+
9
+ from .base_dataset import BaseDataset
10
+ from .builder import DATASETS
11
+
12
+
13
+ def has_file_allowed_extension(filename, extensions):
14
+ """Checks if a file is an allowed extension.
15
+
16
+ Args:
17
+ filename (string): path to a file
18
+
19
+ Returns:
20
+ bool: True if the filename ends with a known image extension
21
+ """
22
+ filename_lower = filename.lower()
23
+ return any(filename_lower.endswith(ext) for ext in extensions)
24
+
25
+
26
+ def find_folders(root):
27
+ """Find classes by folders under a root.
28
+
29
+ Args:
30
+ root (string): root directory of folders
31
+
32
+ Returns:
33
+ folder_to_idx (dict): the map from folder name to class idx
34
+ """
35
+ folders = [
36
+ d for d in os.listdir(root) if os.path.isdir(os.path.join(root, d))
37
+ ]
38
+ folders.sort()
39
+ folder_to_idx = {folders[i]: i for i in range(len(folders))}
40
+ return folder_to_idx
41
+
42
+
43
+ def get_samples(root, folder_to_idx, extensions):
44
+ """Make dataset by walking all images under a root.
45
+
46
+ Args:
47
+ root (string): root directory of folders
48
+ folder_to_idx (dict): the map from class name to class idx
49
+ extensions (tuple): allowed extensions
50
+
51
+ Returns:
52
+ samples (list): a list of tuple where each element is (image, label)
53
+ """
54
+ samples = []
55
+ root = os.path.expanduser(root)
56
+ for folder_name in sorted(os.listdir(root)):
57
+ _dir = os.path.join(root, folder_name)
58
+ if not os.path.isdir(_dir):
59
+ continue
60
+
61
+ for _, _, fns in sorted(os.walk(_dir)):
62
+ for fn in sorted(fns):
63
+ if has_file_allowed_extension(fn, extensions):
64
+ path = os.path.join(folder_name, fn)
65
+ item = (path, folder_to_idx[folder_name])
66
+ samples.append(item)
67
+ return samples
68
+
69
+ # 0 1 2 3 4 5 6 7
70
+ FER_CLASSES = ['Anger', 'Disgust', 'Fear', 'Sadness', 'Happiness', 'Surprise', 'Neutral', 'Contempt']
71
+
72
+ def convert2coarse_label(i:int):
73
+ """The first four are negative"""
74
+ if i <= 3:
75
+ return 0
76
+ return i - 3
77
+
78
+
79
+ def gen_class_map(dataset_class):
80
+ """
81
+ generate the convert map from DATASET_CLASSES to FER_CLASSES
82
+ """
83
+ convert_map = []
84
+ for i in dataset_class:
85
+ convert_map.append(FER_CLASSES.index(i))
86
+ assert sum(convert_map) == sum([i for i in range(len(dataset_class))])
87
+ return convert_map
88
+
89
+ @DATASETS.register_module()
90
+ class RAF(BaseDataset):
91
+
92
+ IMG_EXTENSIONS = ('.jpg', '.jpeg', '.png', '.ppm', '.bmp', '.pgm', '.tif')
93
+ DATASET_CLASSES = [
94
+ 'Surprise',
95
+ 'Fear',
96
+ 'Disgust',
97
+ 'Happiness',
98
+ 'Sadness',
99
+ 'Anger',
100
+ 'Neutral'
101
+ ]
102
+ CLASSES = FER_CLASSES[:7]
103
+
104
+ @staticmethod
105
+ def convert_gt_label(i:int):
106
+ """# dataset -> FER_CLASSES"""
107
+ convert_table = (5, 2, 1, 4, 3, 0, 6)
108
+ assert sum(convert_table) == sum([i for i in range(7)])
109
+ return convert_table[i]
110
+
111
+ def load_annotations(self):
112
+ if self.ann_file is None:
113
+ folder_to_idx = find_folders(self.data_prefix)
114
+ samples = get_samples(
115
+ self.data_prefix,
116
+ folder_to_idx,
117
+ extensions=self.IMG_EXTENSIONS)
118
+ if len(samples) == 0:
119
+ raise (RuntimeError('Found 0 files in subfolders of: '
120
+ f'{self.data_prefix}. '
121
+ 'Supported extensions are: '
122
+ f'{",".join(self.IMG_EXTENSIONS)}'))
123
+
124
+ self.folder_to_idx = folder_to_idx
125
+ elif isinstance(self.ann_file, str):
126
+ with open(self.ann_file) as f:
127
+ samples = [x.strip().split(' ') for x in f.readlines()]
128
+ samples = [[i[0].replace('_aligned', ''), i[1]] for i in samples]
129
+ else:
130
+ raise TypeError('ann_file must be a str or None')
131
+ self.samples = samples
132
+
133
+ data_infos = []
134
+ for filename, gt_label in self.samples:
135
+ info = {'img_prefix': self.data_prefix}
136
+ info['img_info'] = {'filename': filename}
137
+ gt_label = int(gt_label) - 1
138
+ gt_label = self.convert_gt_label(gt_label)
139
+ coarse_label = convert2coarse_label(gt_label)
140
+ info['gt_label'] = np.array(gt_label, dtype=np.int64)
141
+ info['coarse_label'] = np.array(coarse_label, dtype=np.int64)
142
+ data_infos.append(info)
143
+ return data_infos
144
+
CAGE_expression_inference-apvit/apvit_mmcls/datasets/samplers/__init__.py ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ from .distributed_sampler import DistributedSampler
2
+
3
+ __all__ = ['DistributedSampler']
CAGE_expression_inference-apvit/apvit_mmcls/datasets/samplers/distributed_sampler.py ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from torch.utils.data import DistributedSampler as _DistributedSampler
3
+
4
+
5
+ class DistributedSampler(_DistributedSampler):
6
+
7
+ def __init__(self,
8
+ dataset,
9
+ num_replicas=None,
10
+ rank=None,
11
+ shuffle=True,
12
+ round_up=True):
13
+ super().__init__(dataset, num_replicas=num_replicas, rank=rank)
14
+ self.shuffle = shuffle
15
+ self.round_up = round_up
16
+ if self.round_up:
17
+ self.total_size = self.num_samples * self.num_replicas
18
+ else:
19
+ self.total_size = len(self.dataset)
20
+
21
+ def __iter__(self):
22
+ # deterministically shuffle based on epoch
23
+ if self.shuffle:
24
+ g = torch.Generator()
25
+ g.manual_seed(self.epoch)
26
+ indices = torch.randperm(len(self.dataset), generator=g).tolist()
27
+ else:
28
+ indices = torch.arange(len(self.dataset)).tolist()
29
+
30
+ # add extra samples to make it evenly divisible
31
+ if self.round_up:
32
+ indices = (
33
+ indices *
34
+ int(self.total_size / len(indices) + 1))[:self.total_size]
35
+ assert len(indices) == self.total_size
36
+
37
+ # subsample
38
+ indices = indices[self.rank:self.total_size:self.num_replicas]
39
+ if self.round_up:
40
+ assert len(indices) == self.num_samples
41
+
42
+ return iter(indices)
CAGE_expression_inference-apvit/apvit_mmcls/datasets/utils.py ADDED
@@ -0,0 +1,152 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gzip
2
+ import hashlib
3
+ import os
4
+ import os.path
5
+ import shutil
6
+ import tarfile
7
+ import urllib.error
8
+ import urllib.request
9
+ import zipfile
10
+
11
+ __all__ = ['rm_suffix', 'check_integrity', 'download_and_extract_archive']
12
+
13
+
14
+ def rm_suffix(s, suffix=None):
15
+ if suffix is None:
16
+ return s[:s.rfind('.')]
17
+ else:
18
+ return s[:s.rfind(suffix)]
19
+
20
+
21
+ def calculate_md5(fpath, chunk_size=1024 * 1024):
22
+ md5 = hashlib.md5()
23
+ with open(fpath, 'rb') as f:
24
+ for chunk in iter(lambda: f.read(chunk_size), b''):
25
+ md5.update(chunk)
26
+ return md5.hexdigest()
27
+
28
+
29
+ def check_md5(fpath, md5, **kwargs):
30
+ return md5 == calculate_md5(fpath, **kwargs)
31
+
32
+
33
+ def check_integrity(fpath, md5=None):
34
+ if not os.path.isfile(fpath):
35
+ return False
36
+ if md5 is None:
37
+ return True
38
+ return check_md5(fpath, md5)
39
+
40
+
41
+ def download_url_to_file(url, fpath):
42
+ with urllib.request.urlopen(url) as resp, open(fpath, 'wb') as of:
43
+ shutil.copyfileobj(resp, of)
44
+
45
+
46
+ def download_url(url, root, filename=None, md5=None):
47
+ """Download a file from a url and place it in root.
48
+
49
+ Args:
50
+ url (str): URL to download file from.
51
+ root (str): Directory to place downloaded file in.
52
+ filename (str | None): Name to save the file under.
53
+ If filename is None, use the basename of the URL.
54
+ md5 (str | None): MD5 checksum of the download.
55
+ If md5 is None, download without md5 check.
56
+ """
57
+ root = os.path.expanduser(root)
58
+ if not filename:
59
+ filename = os.path.basename(url)
60
+ fpath = os.path.join(root, filename)
61
+
62
+ os.makedirs(root, exist_ok=True)
63
+
64
+ if check_integrity(fpath, md5):
65
+ print(f'Using downloaded and verified file: {fpath}')
66
+ else:
67
+ try:
68
+ print(f'Downloading {url} to {fpath}')
69
+ download_url_to_file(url, fpath)
70
+ except (urllib.error.URLError, IOError) as e:
71
+ if url[:5] == 'https':
72
+ url = url.replace('https:', 'http:')
73
+ print('Failed download. Trying https -> http instead.'
74
+ f' Downloading {url} to {fpath}')
75
+ download_url_to_file(url, fpath)
76
+ else:
77
+ raise e
78
+ # check integrity of downloaded file
79
+ if not check_integrity(fpath, md5):
80
+ raise RuntimeError('File not found or corrupted.')
81
+
82
+
83
+ def _is_tarxz(filename):
84
+ return filename.endswith('.tar.xz')
85
+
86
+
87
+ def _is_tar(filename):
88
+ return filename.endswith('.tar')
89
+
90
+
91
+ def _is_targz(filename):
92
+ return filename.endswith('.tar.gz')
93
+
94
+
95
+ def _is_tgz(filename):
96
+ return filename.endswith('.tgz')
97
+
98
+
99
+ def _is_gzip(filename):
100
+ return filename.endswith('.gz') and not filename.endswith('.tar.gz')
101
+
102
+
103
+ def _is_zip(filename):
104
+ return filename.endswith('.zip')
105
+
106
+
107
+ def extract_archive(from_path, to_path=None, remove_finished=False):
108
+ if to_path is None:
109
+ to_path = os.path.dirname(from_path)
110
+
111
+ if _is_tar(from_path):
112
+ with tarfile.open(from_path, 'r') as tar:
113
+ tar.extractall(path=to_path)
114
+ elif _is_targz(from_path) or _is_tgz(from_path):
115
+ with tarfile.open(from_path, 'r:gz') as tar:
116
+ tar.extractall(path=to_path)
117
+ elif _is_tarxz(from_path):
118
+ with tarfile.open(from_path, 'r:xz') as tar:
119
+ tar.extractall(path=to_path)
120
+ elif _is_gzip(from_path):
121
+ to_path = os.path.join(
122
+ to_path,
123
+ os.path.splitext(os.path.basename(from_path))[0])
124
+ with open(to_path, 'wb') as out_f, gzip.GzipFile(from_path) as zip_f:
125
+ out_f.write(zip_f.read())
126
+ elif _is_zip(from_path):
127
+ with zipfile.ZipFile(from_path, 'r') as z:
128
+ z.extractall(to_path)
129
+ else:
130
+ raise ValueError(f'Extraction of {from_path} not supported')
131
+
132
+ if remove_finished:
133
+ os.remove(from_path)
134
+
135
+
136
+ def download_and_extract_archive(url,
137
+ download_root,
138
+ extract_root=None,
139
+ filename=None,
140
+ md5=None,
141
+ remove_finished=False):
142
+ download_root = os.path.expanduser(download_root)
143
+ if extract_root is None:
144
+ extract_root = download_root
145
+ if not filename:
146
+ filename = os.path.basename(url)
147
+
148
+ download_url(url, download_root, filename, md5)
149
+
150
+ archive = os.path.join(download_root, filename)
151
+ print(f'Extracting {archive} to {extract_root}')
152
+ extract_archive(archive, extract_root, remove_finished)
CAGE_expression_inference-apvit/apvit_mmcls/models/__init__.py ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from .backbones import * # noqa: F401,F403
2
+ from .builder import (BACKBONES, CLASSIFIERS, HEADS, LOSSES, NECKS,
3
+ build_backbone, build_classifier, build_head, build_loss,
4
+ build_neck)
5
+ from .classifiers import * # noqa: F401,F403
6
+ from .heads import * # noqa: F401,F403
7
+ from .losses import * # noqa: F401,F403
8
+ from .necks import * # noqa: F401,F403
9
+
10
+ __all__ = [
11
+ 'BACKBONES', 'HEADS', 'NECKS', 'LOSSES', 'CLASSIFIERS', 'build_backbone',
12
+ 'build_head', 'build_neck', 'build_loss', 'build_classifier'
13
+ ]
CAGE_expression_inference-apvit/apvit_mmcls/models/backbones/__init__.py ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from .alexnet import AlexNet
2
+ from .lenet import LeNet5
3
+ from .mobilenet_v2 import MobileNetV2
4
+ from .mobilenet_v3 import MobileNetv3
5
+ from .regnet import RegNet
6
+ from .resnest import ResNeSt
7
+ from .resnet import ResNet, ResNetV1d
8
+ from .resnet_cifar import ResNet_CIFAR
9
+ from .resnext import ResNeXt
10
+ from .seresnet import SEResNet
11
+ from .seresnext import SEResNeXt
12
+ from .shufflenet_v1 import ShuffleNetV1
13
+ from .shufflenet_v2 import ShuffleNetV2
14
+ from .vgg import VGG
15
+ from .irse import IRSE
16
+ from .irse_nopadding import IRSENoPadding
17
+ from .mobilefacenet import MobileFaceNet
18
+ from ..vit.vit_origin import VisionTransformerOrigin
19
+ from ..vit.vit_siam_merge import PoolingViT
20
+ from .t2t_vit import T2T_ViT, T2T_ViTPooling
21
+ from .iresnet import IResNet
22
+ from .vtff import VTFF, MViT
23
+
24
+ __all__ = [
25
+ 'VTFF', 'MViT',
26
+ 'LeNet5', 'AlexNet', 'VGG', 'RegNet', 'ResNet', 'ResNeXt', 'ResNetV1d',
27
+ 'ResNeSt', 'ResNet_CIFAR', 'SEResNet', 'SEResNeXt', 'ShuffleNetV1',
28
+ 'ShuffleNetV2', 'MobileNetV2', 'MobileNetv3', 'IRSE',
29
+ 'MobileFaceNet',
30
+ 'T2T_ViT', 'T2T_ViTPooling', 'VisionTransformerOrigin', 'PoolingViT',
31
+ 'IRSENoPadding', 'IResNet',
32
+ ]
CAGE_expression_inference-apvit/apvit_mmcls/models/backbones/alexnet.py ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch.nn as nn
2
+
3
+ from ..builder import BACKBONES
4
+ from .base_backbone import BaseBackbone
5
+
6
+
7
+ @BACKBONES.register_module()
8
+ class AlexNet(BaseBackbone):
9
+ """`AlexNet <https://en.wikipedia.org/wiki/AlexNet>`_ backbone.
10
+
11
+ The input for AlexNet is a 224x224 RGB image.
12
+
13
+ Args:
14
+ num_classes (int): number of classes for classification.
15
+ The default value is -1, which uses the backbone as
16
+ a feature extractor without the top classifier.
17
+ """
18
+
19
+ def __init__(self, num_classes=-1):
20
+ super(AlexNet, self).__init__()
21
+ self.num_classes = num_classes
22
+ self.features = nn.Sequential(
23
+ nn.Conv2d(3, 64, kernel_size=11, stride=4, padding=2),
24
+ nn.ReLU(inplace=True),
25
+ nn.MaxPool2d(kernel_size=3, stride=2),
26
+ nn.Conv2d(64, 192, kernel_size=5, padding=2),
27
+ nn.ReLU(inplace=True),
28
+ nn.MaxPool2d(kernel_size=3, stride=2),
29
+ nn.Conv2d(192, 384, kernel_size=3, padding=1),
30
+ nn.ReLU(inplace=True),
31
+ nn.Conv2d(384, 256, kernel_size=3, padding=1),
32
+ nn.ReLU(inplace=True),
33
+ nn.Conv2d(256, 256, kernel_size=3, padding=1),
34
+ nn.ReLU(inplace=True),
35
+ nn.MaxPool2d(kernel_size=3, stride=2),
36
+ )
37
+ if self.num_classes > 0:
38
+ self.classifier = nn.Sequential(
39
+ nn.Dropout(),
40
+ nn.Linear(256 * 6 * 6, 4096),
41
+ nn.ReLU(inplace=True),
42
+ nn.Dropout(),
43
+ nn.Linear(4096, 4096),
44
+ nn.ReLU(inplace=True),
45
+ nn.Linear(4096, num_classes),
46
+ )
47
+
48
+ def forward(self, x):
49
+
50
+ x = self.features(x)
51
+ if self.num_classes > 0:
52
+ x = x.view(x.size(0), 256 * 6 * 6)
53
+ x = self.classifier(x)
54
+
55
+ return x
CAGE_expression_inference-apvit/apvit_mmcls/models/backbones/base_backbone.py ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from abc import ABCMeta, abstractmethod
2
+
3
+ import torch.nn as nn
4
+ from mmcv.runner import load_checkpoint
5
+ from mmcv.utils import get_logger
6
+ # from mmcls.utils import get_root_logger
7
+
8
+
9
+ class BaseBackbone(nn.Module, metaclass=ABCMeta):
10
+ """Base backbone.
11
+
12
+ This class defines the basic functions of a backbone.
13
+ Any backbone that inherits this class should at least
14
+ define its own `forward` function.
15
+
16
+ """
17
+
18
+ def __init__(self):
19
+ super(BaseBackbone, self).__init__()
20
+
21
+ def init_weights(self, pretrained=None):
22
+ """Init backbone weights
23
+
24
+ Args:
25
+ pretrained (str | None): If pretrained is a string, then it
26
+ initializes backbone weights by loading the pretrained
27
+ checkpoint. If pretrained is None, then it follows default
28
+ initializer or customized initializer in subclasses.
29
+ """
30
+ if isinstance(pretrained, str):
31
+ logger = get_logger('mmcv')
32
+ logger.warning(f'{self.__class__.__name__} load pretrain from {pretrained}')
33
+ load_checkpoint(self, pretrained, strict=False, logger=logger, map_location='cpu')
34
+ elif pretrained is None:
35
+ # use default initializer or customized initializer in subclasses
36
+ pass
37
+ else:
38
+ raise TypeError('pretrained must be a str or None.'
39
+ f' But received {type(pretrained)}.')
40
+
41
+ @abstractmethod
42
+ def forward(self, x):
43
+ """Forward computation
44
+
45
+ Args:
46
+ x (tensor | tuple[tensor]): x could be a Torch.tensor or a tuple of
47
+ Torch.tensor, containing input data for forward computation.
48
+ """
49
+ pass
50
+
51
+ def train(self, mode=True):
52
+ """Set module status before forward computation
53
+
54
+ Args:
55
+ mode (bool): Whether it is train_mode or test_mode
56
+ """
57
+ super(BaseBackbone, self).train(mode)
CAGE_expression_inference-apvit/apvit_mmcls/models/backbones/iresnet.py ADDED
@@ -0,0 +1,220 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import warnings
2
+ import torch.nn as nn
3
+ from torch.nn import Linear, Conv2d, BatchNorm1d, BatchNorm2d, PReLU, ReLU, Sigmoid, Dropout, MaxPool2d, \
4
+ AdaptiveAvgPool2d, Sequential, Module
5
+ from collections import namedtuple
6
+ import torch
7
+ from mmcv.runner import load_state_dict
8
+ from mmcls.utils import get_root_logger
9
+
10
+ from ..builder import BACKBONES
11
+ from .base_backbone import BaseBackbone
12
+
13
+ __all__ = ['iresnet18', 'iresnet34', 'iresnet50', 'iresnet100', 'iresnet200']
14
+
15
+
16
+ def conv3x3(in_planes, out_planes, stride=1, groups=1, dilation=1):
17
+ """3x3 convolution with padding"""
18
+ return nn.Conv2d(in_planes,
19
+ out_planes,
20
+ kernel_size=3,
21
+ stride=stride,
22
+ padding=dilation,
23
+ groups=groups,
24
+ bias=False,
25
+ dilation=dilation)
26
+
27
+
28
+ def conv1x1(in_planes, out_planes, stride=1):
29
+ """1x1 convolution"""
30
+ return nn.Conv2d(in_planes,
31
+ out_planes,
32
+ kernel_size=1,
33
+ stride=stride,
34
+ bias=False)
35
+
36
+
37
+ class IBasicBlock(nn.Module):
38
+ expansion = 1
39
+ def __init__(self, inplanes, planes, stride=1, downsample=None,
40
+ groups=1, base_width=64, dilation=1):
41
+ super(IBasicBlock, self).__init__()
42
+ if groups != 1 or base_width != 64:
43
+ raise ValueError('BasicBlock only supports groups=1 and base_width=64')
44
+ if dilation > 1:
45
+ raise NotImplementedError("Dilation > 1 not supported in BasicBlock")
46
+ self.bn1 = nn.BatchNorm2d(inplanes, eps=1e-05,)
47
+ self.conv1 = conv3x3(inplanes, planes)
48
+ self.bn2 = nn.BatchNorm2d(planes, eps=1e-05,)
49
+ self.prelu = nn.PReLU(planes)
50
+ self.conv2 = conv3x3(planes, planes, stride)
51
+ self.bn3 = nn.BatchNorm2d(planes, eps=1e-05,)
52
+ self.downsample = downsample
53
+ self.stride = stride
54
+
55
+ def forward(self, x):
56
+ identity = x
57
+ out = self.bn1(x)
58
+ out = self.conv1(out)
59
+ out = self.bn2(out)
60
+ out = self.prelu(out)
61
+ out = self.conv2(out)
62
+ out = self.bn3(out)
63
+ if self.downsample is not None:
64
+ identity = self.downsample(x)
65
+ out += identity
66
+ return out
67
+
68
+
69
+ layers_map = {
70
+ 18: [2, 2, 2, 2],
71
+ 34: [3, 4, 6, 3],
72
+ 50: [3, 4, 14, 3],
73
+ 100: [3, 13, 30, 3],
74
+ }
75
+
76
+
77
+ @BACKBONES.register_module()
78
+ class IResNet(nn.Module):
79
+ fc_scale = 7 * 7
80
+ def __init__(self,
81
+ depth, block=None, dropout=0, num_features=512, zero_init_residual=False,
82
+ groups=1, width_per_group=64, replace_stride_with_dilation=None, fp16=False, pretrained=None):
83
+ super(IResNet, self).__init__()
84
+ block = IBasicBlock
85
+ layers = layers_map[depth]
86
+ self.fp16 = fp16
87
+ self.inplanes = 64
88
+ self.dilation = 1
89
+ if replace_stride_with_dilation is None:
90
+ replace_stride_with_dilation = [False, False, False]
91
+ if len(replace_stride_with_dilation) != 3:
92
+ raise ValueError("replace_stride_with_dilation should be None "
93
+ "or a 3-element tuple, got {}".format(replace_stride_with_dilation))
94
+ self.groups = groups
95
+ self.base_width = width_per_group
96
+ self.conv1 = nn.Conv2d(3, self.inplanes, kernel_size=3, stride=1, padding=1, bias=False)
97
+ self.bn1 = nn.BatchNorm2d(self.inplanes, eps=1e-05)
98
+ self.prelu = nn.PReLU(self.inplanes)
99
+ self.layer1 = self._make_layer(block, 64, layers[0], stride=2)
100
+ self.layer2 = self._make_layer(block,
101
+ 128,
102
+ layers[1],
103
+ stride=2,
104
+ dilate=replace_stride_with_dilation[0])
105
+ self.layer3 = self._make_layer(block,
106
+ 256,
107
+ layers[2],
108
+ stride=2,
109
+ dilate=replace_stride_with_dilation[1])
110
+ # self.layer4 = self._make_layer(block,
111
+ # 512,
112
+ # layers[3],
113
+ # stride=2,
114
+ # dilate=replace_stride_with_dilation[2])
115
+ # self.bn2 = nn.BatchNorm2d(512 * block.expansion, eps=1e-05,)
116
+ # self.dropout = nn.Dropout(p=dropout, inplace=True)
117
+ # self.fc = nn.Linear(512 * block.expansion * self.fc_scale, num_features)
118
+ # self.features = nn.BatchNorm1d(num_features, eps=1e-05)
119
+ # nn.init.constant_(self.features.weight, 1.0)
120
+ # self.features.weight.requires_grad = False
121
+ if pretrained:
122
+ self.init_weights(pretrained)
123
+ else:
124
+ for m in self.modules():
125
+ if isinstance(m, nn.Conv2d):
126
+ nn.init.normal_(m.weight, 0, 0.1)
127
+ elif isinstance(m, (nn.BatchNorm2d, nn.GroupNorm)):
128
+ nn.init.constant_(m.weight, 1)
129
+ nn.init.constant_(m.bias, 0)
130
+
131
+ if zero_init_residual:
132
+ for m in self.modules():
133
+ if isinstance(m, IBasicBlock):
134
+ nn.init.constant_(m.bn2.weight, 0)
135
+
136
+ def init_weights(self, pretrained):
137
+ logger = get_root_logger()
138
+ logger.warning(f'{self.__class__.__name__} load pretrain from {pretrained}')
139
+ state_dict = torch.load(pretrained, map_location='cpu')
140
+ if 'state_dict' in state_dict:
141
+ state_dict = state_dict['state_dict']
142
+
143
+ load_state_dict(self, state_dict, strict=False, logger=logger)
144
+
145
+
146
+ def _make_layer(self, block, planes, blocks, stride=1, dilate=False):
147
+ downsample = None
148
+ previous_dilation = self.dilation
149
+ if dilate:
150
+ self.dilation *= stride
151
+ stride = 1
152
+ if stride != 1 or self.inplanes != planes * block.expansion:
153
+ downsample = nn.Sequential(
154
+ conv1x1(self.inplanes, planes * block.expansion, stride),
155
+ nn.BatchNorm2d(planes * block.expansion, eps=1e-05, ),
156
+ )
157
+ layers = []
158
+ layers.append(
159
+ block(self.inplanes, planes, stride, downsample, self.groups,
160
+ self.base_width, previous_dilation))
161
+ self.inplanes = planes * block.expansion
162
+ for _ in range(1, blocks):
163
+ layers.append(
164
+ block(self.inplanes,
165
+ planes,
166
+ groups=self.groups,
167
+ base_width=self.base_width,
168
+ dilation=self.dilation))
169
+
170
+ return nn.Sequential(*layers)
171
+
172
+ def forward(self, x):
173
+ # with torch.cuda.amp.autocast(self.fp16):
174
+ x = self.conv1(x)
175
+ x = self.bn1(x)
176
+ x = self.prelu(x)
177
+ x = self.layer1(x)
178
+ x = self.layer2(x)
179
+ x = self.layer3(x)
180
+ return (x, )
181
+ x = self.layer4(x)
182
+ return (x, )
183
+ # x = self.bn2(x)
184
+ # x = torch.flatten(x, 1)
185
+ # x = self.dropout(x)
186
+ # x = self.fc(x.float() if self.fp16 else x)
187
+ # x = self.features(x)
188
+ # return x
189
+
190
+
191
+ def _iresnet(arch, block, layers, pretrained, progress, **kwargs):
192
+ model = IResNet(block, layers, **kwargs)
193
+ if pretrained:
194
+ raise ValueError()
195
+ return model
196
+
197
+
198
+ def iresnet18(pretrained=False, progress=True, **kwargs):
199
+ return _iresnet('iresnet18', IBasicBlock, [2, 2, 2, 2], pretrained,
200
+ progress, **kwargs)
201
+
202
+
203
+ def iresnet34(pretrained=False, progress=True, **kwargs):
204
+ return _iresnet('iresnet34', IBasicBlock, [3, 4, 6, 3], pretrained,
205
+ progress, **kwargs)
206
+
207
+
208
+ def iresnet50(pretrained=False, progress=True, **kwargs):
209
+ return _iresnet('iresnet50', IBasicBlock, [3, 4, 14, 3], pretrained,
210
+ progress, **kwargs)
211
+
212
+
213
+ def iresnet100(pretrained=False, progress=True, **kwargs):
214
+ return _iresnet('iresnet100', IBasicBlock, [3, 13, 30, 3], pretrained,
215
+ progress, **kwargs)
216
+
217
+
218
+ def iresnet200(pretrained=False, progress=True, **kwargs):
219
+ return _iresnet('iresnet200', IBasicBlock, [6, 26, 60, 6], pretrained,
220
+ progress, **kwargs)
CAGE_expression_inference-apvit/apvit_mmcls/models/backbones/irse.py ADDED
@@ -0,0 +1,387 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import warnings
2
+ import torch.nn as nn
3
+ from torch.nn import Linear, Conv2d, BatchNorm1d, BatchNorm2d, PReLU, ReLU, Sigmoid, Dropout, MaxPool2d, \
4
+ AdaptiveAvgPool2d, Sequential, Module
5
+ from collections import namedtuple
6
+ import torch
7
+ from mmcv.runner import load_state_dict
8
+ from mmcls.utils import get_root_logger
9
+
10
+ from ..builder import BACKBONES
11
+ from .base_backbone import BaseBackbone
12
+
13
+ # Support: ['IR_50', 'IR_101', 'IR_152', 'IR_SE_50', 'IR_SE_101', 'IR_SE_152']
14
+
15
+ class ABSPool2d(Module):
16
+ def __init__(self, *args, **kwargs):
17
+ super().__init__()
18
+ self.args = args
19
+ self.kwargs = kwargs
20
+
21
+ def forward(self, x):
22
+ positive = MaxPool2d(*self.args, **self.kwargs)(x)
23
+ negtive = MaxPool2d(*self.args, **self.kwargs)(-x)
24
+ result = torch.where(positive>=negtive, positive, negtive)
25
+ return result
26
+
27
+ pool_layer = MaxPool2d
28
+
29
+ class Flatten(Module):
30
+ def forward(self, input):
31
+ return input.view(input.size(0), -1)
32
+
33
+
34
+ def l2_norm(input, axis=1):
35
+ norm = torch.norm(input, 2, axis, True)
36
+ output = torch.div(input, norm)
37
+
38
+ return output
39
+
40
+
41
+ class SEModule(Module):
42
+ def __init__(self, channels, reduction):
43
+ super(SEModule, self).__init__()
44
+ self.avg_pool = AdaptiveAvgPool2d(1)
45
+ self.fc1 = Conv2d(
46
+ channels, channels // reduction, kernel_size=1, padding=0, bias=False)
47
+
48
+ nn.init.xavier_uniform_(self.fc1.weight.data)
49
+
50
+ self.relu = ReLU(inplace=True)
51
+ self.fc2 = Conv2d(
52
+ channels // reduction, channels, kernel_size=1, padding=0, bias=False)
53
+
54
+ self.sigmoid = Sigmoid()
55
+
56
+ def forward(self, x):
57
+ module_input = x
58
+ x = self.avg_pool(x)
59
+ x = self.fc1(x)
60
+ x = self.relu(x)
61
+ x = self.fc2(x)
62
+ x = self.sigmoid(x)
63
+
64
+ return module_input * x
65
+
66
+
67
+ class bottleneck_IR(Module):
68
+ def __init__(self, in_channel, depth, stride):
69
+ super(bottleneck_IR, self).__init__()
70
+ if in_channel == depth:
71
+ self.shortcut_layer = pool_layer(1, stride)
72
+ else:
73
+ self.shortcut_layer = Sequential(
74
+ Conv2d(in_channel, depth, (1, 1), stride, bias=False),
75
+ BatchNorm2d(depth))
76
+ self.res_layer = Sequential(
77
+ BatchNorm2d(in_channel),
78
+ Conv2d(in_channel, depth, (3, 3), (1, 1), 1, bias=False),
79
+ PReLU(depth),
80
+ Conv2d(depth, depth, (3, 3), stride, 1, bias=False),
81
+ BatchNorm2d(depth))
82
+
83
+ def forward(self, x):
84
+ shortcut = self.shortcut_layer(x)
85
+ res = self.res_layer(x)
86
+
87
+ return res + shortcut
88
+
89
+
90
+ class BasicBlockIR(Module):
91
+ """
92
+ BasicBlock for IRNet, stolen from TFace
93
+ https://github.com/Tencent/TFace/blob/d57fd8d9ce9502240921f0998c57f84afa7eaeaa/torchkit/backbone/model_irse.py#L16
94
+ Add a BatchNorm2d after the first Conv2d
95
+ """
96
+ def __init__(self, in_channel, depth, stride):
97
+ super(BasicBlockIR, self).__init__()
98
+ if in_channel == depth:
99
+ self.shortcut_layer = pool_layer(1, stride)
100
+ else:
101
+ self.shortcut_layer = Sequential(
102
+ Conv2d(in_channel, depth, (1, 1), stride, bias=False),
103
+ BatchNorm2d(depth))
104
+ self.res_layer = Sequential(
105
+ BatchNorm2d(in_channel),
106
+ Conv2d(in_channel, depth, (3, 3), (1, 1), 1, bias=False),
107
+ BatchNorm2d(depth),
108
+ PReLU(depth),
109
+ Conv2d(depth, depth, (3, 3), stride, 1, bias=False),
110
+ BatchNorm2d(depth))
111
+
112
+ def forward(self, x):
113
+ shortcut = self.shortcut_layer(x)
114
+ res = self.res_layer(x)
115
+
116
+ return res + shortcut
117
+
118
+
119
+ class bottleneck_IR_SE(Module):
120
+ def __init__(self, in_channel, depth, stride):
121
+ super(bottleneck_IR_SE, self).__init__()
122
+ if in_channel == depth:
123
+ self.shortcut_layer = pool_layer(1, stride)
124
+ else:
125
+ self.shortcut_layer = Sequential(
126
+ Conv2d(in_channel, depth, (1, 1), stride, bias=False),
127
+ BatchNorm2d(depth))
128
+ self.res_layer = Sequential(
129
+ BatchNorm2d(in_channel),
130
+ Conv2d(in_channel, depth, (3, 3), (1, 1), 1, bias=False),
131
+ PReLU(depth),
132
+ Conv2d(depth, depth, (3, 3), stride, 1, bias=False),
133
+ BatchNorm2d(depth),
134
+ SEModule(depth, 16)
135
+ )
136
+
137
+ def forward(self, x):
138
+ shortcut = self.shortcut_layer(x)
139
+ res = self.res_layer(x)
140
+
141
+ return res + shortcut
142
+
143
+
144
+ class Bottleneck(namedtuple('Block', ['in_channel', 'depth', 'stride'])):
145
+ '''A named tuple describing a ResNet block.'''
146
+
147
+
148
+ def get_block(in_channel, depth, num_units, stride=2):
149
+
150
+ return [Bottleneck(in_channel, depth, stride)] + [Bottleneck(depth, depth, 1) for i in range(num_units - 1)]
151
+
152
+
153
+ def get_blocks(num_layers):
154
+
155
+ if num_layers == 8:
156
+ blocks = [
157
+ get_block(in_channel=64, depth=64, num_units=3),
158
+ ]
159
+ elif num_layers == 16:
160
+ blocks = [
161
+ get_block(in_channel=64, depth=64, num_units=3),
162
+ get_block(in_channel=64, depth=128, num_units=4),
163
+ ]
164
+ elif num_layers == 34:
165
+ blocks = [
166
+ get_block(in_channel=64, depth=64, num_units=3),
167
+ get_block(in_channel=64, depth=128, num_units=4),
168
+ get_block(in_channel=128, depth=256, num_units=6),
169
+ get_block(in_channel=256, depth=512, num_units=3)
170
+ ]
171
+ elif num_layers == 44:
172
+ blocks = [
173
+ get_block(in_channel=64, depth=64, num_units=3),
174
+ get_block(in_channel=64, depth=128, num_units=4),
175
+ get_block(in_channel=128, depth=256, num_units=14),
176
+ ]
177
+ elif num_layers == 50:
178
+ blocks = [
179
+ get_block(in_channel=64, depth=64, num_units=3), # (B, 64, 56, 56)
180
+ get_block(in_channel=64, depth=128, num_units=4), # (B, 128, 28, 28)
181
+ get_block(in_channel=128, depth=256, num_units=14), # (B, 256, 14, 14)
182
+ get_block(in_channel=256, depth=512, num_units=3) # (B, 512, 7, 7)
183
+ ]
184
+ elif num_layers == 100:
185
+ blocks = [
186
+ get_block(in_channel=64, depth=64, num_units=3),
187
+ get_block(in_channel=64, depth=128, num_units=13),
188
+ get_block(in_channel=128, depth=256, num_units=30),
189
+ get_block(in_channel=256, depth=512, num_units=3)
190
+ ]
191
+ elif num_layers == 152:
192
+ blocks = [
193
+ get_block(in_channel=64, depth=64, num_units=3),
194
+ get_block(in_channel=64, depth=128, num_units=8),
195
+ get_block(in_channel=128, depth=256, num_units=36),
196
+ get_block(in_channel=256, depth=512, num_units=3)
197
+ ]
198
+
199
+ return blocks
200
+
201
+
202
+ @BACKBONES.register_module()
203
+ class IRSE(BaseBackbone):
204
+ def __init__(self, input_size, num_layers, mode='ir', with_head=False, pretrained=None, return_index=(0, 1, 2),
205
+ return_type='Tuple'):
206
+ super().__init__()
207
+ assert input_size[0] in [112, 224], "input_size should be [112, 112] or [224, 224]"
208
+ assert num_layers in [0, 8, 16, 34, 44, 50, 100, 152], "num_layers should be 50, 100 or 152"
209
+ assert mode in ['ir', 'ir_se'], "mode should be ir or ir_se"
210
+ assert return_type in ('Tensor', 'Tuple'), 'return_tensor must be Tensor or Tuple'
211
+ if len(return_index) > 1:
212
+ assert return_type == 'Tuple'
213
+ self.num_layers = num_layers
214
+ self.return_index = return_index
215
+ self.return_type = return_type
216
+ if num_layers == 0:
217
+ return
218
+ self.with_head = with_head
219
+ blocks = get_blocks(num_layers)
220
+ if mode == 'ir':
221
+ if num_layers == 34:
222
+ warnings.warn('Using the IR_34 version from TFace')
223
+ unit_module = BasicBlockIR
224
+ else:
225
+ unit_module = bottleneck_IR
226
+ elif mode == 'ir_se':
227
+ unit_module = bottleneck_IR_SE
228
+ self.input_layer = Sequential(Conv2d(3, 64, (3, 3), 1, 1, bias=False),
229
+ BatchNorm2d(64),
230
+ PReLU(64))
231
+ if with_head:
232
+ if input_size[0] == 112:
233
+ self.output_layer = Sequential(BatchNorm2d(512),
234
+ Dropout(),
235
+ Flatten(),
236
+ Linear(512 * 7 * 7, 512),
237
+ BatchNorm1d(512))
238
+ else:
239
+ self.output_layer = Sequential(BatchNorm2d(512),
240
+ Dropout(),
241
+ Flatten(),
242
+ Linear(512 * 14 * 14, 512),
243
+ BatchNorm1d(512))
244
+
245
+ modules = []
246
+ max_stage = max(return_index)
247
+ for block in blocks[:max_stage+1]:
248
+ block_module = []
249
+ for bottleneck in block:
250
+ block_module.append(
251
+ unit_module(bottleneck.in_channel,
252
+ bottleneck.depth,
253
+ bottleneck.stride))
254
+ modules.append(Sequential(*block_module))
255
+ # self.body = Sequential(*modules)
256
+ self.body = nn.ModuleList(modules)
257
+
258
+ self._initialize_weights()
259
+ if pretrained:
260
+ self.init_weights(pretrained)
261
+
262
+ def init_weights(self, pretrained):
263
+ logger = get_root_logger()
264
+ logger.warning(f'{self.__class__.__name__} load pretrain from {pretrained}')
265
+ state_dict = torch.load(pretrained, map_location='cpu')
266
+ if 'state_dict' in state_dict:
267
+ state_dict = state_dict['state_dict']
268
+
269
+ stage_unit_nums = {
270
+ 34: (3, 4, 6, 3),
271
+ 50: (3, 4, 14, 3),
272
+ }
273
+ stage_num = stage_unit_nums[self.num_layers]
274
+
275
+ new_state_dict = dict()
276
+ for k, v in state_dict.items():
277
+ if k.startswith('body.'):
278
+ index = int(k.split('.')[1])
279
+ if 0 <= index < stage_num[0]:
280
+ new_key = k.replace('body.', 'body.0.')
281
+ elif stage_num[0] <= index < sum(stage_num[:2]):
282
+ new_key = f"body.1.{index-sum(stage_num[:1])}.{'.'.join(k.split('.')[2:])}"
283
+ elif sum(stage_num[:2]) <= index < sum(stage_num[:3]):
284
+ new_key = f"body.2.{index-sum(stage_num[:2])}.{'.'.join(k.split('.')[2:])}"
285
+ else:
286
+ new_key = k
287
+ else:
288
+ new_key = k
289
+ new_state_dict[new_key] = v
290
+
291
+ load_state_dict(self, new_state_dict, strict=False, logger=logger)
292
+
293
+ def forward(self, x):
294
+ if self.num_layers == 0:
295
+ return x
296
+ x = self.input_layer(x)
297
+ output = []
298
+ return_index = set(self.return_index)
299
+ for index, m in enumerate(self.body):
300
+ x = m(x)
301
+ if index in return_index:
302
+ output.append(x)
303
+ if self.with_head:
304
+ x = self.output_layer(x)
305
+ if self.return_type == 'Tensor':
306
+ return output[0]
307
+ else:
308
+ return tuple(output)
309
+
310
+ def _initialize_weights(self):
311
+ for m in self.modules():
312
+ if isinstance(m, nn.Conv2d):
313
+ nn.init.xavier_uniform_(m.weight.data)
314
+ if m.bias is not None:
315
+ m.bias.data.zero_()
316
+ elif isinstance(m, nn.BatchNorm2d):
317
+ m.weight.data.fill_(1)
318
+ m.bias.data.zero_()
319
+ elif isinstance(m, nn.BatchNorm1d):
320
+ m.weight.data.fill_(1)
321
+ m.bias.data.zero_()
322
+ elif isinstance(m, nn.Linear):
323
+ nn.init.xavier_uniform_(m.weight.data)
324
+ if m.bias is not None:
325
+ m.bias.data.zero_()
326
+
327
+
328
+ def _freeze_stages(self):
329
+ if self.frozen_blocks > 0:
330
+ print(f'IRSE freeze the first {self.frozen_blocks} blocks, it has {len(self.body)} blocks ')
331
+ self.input_layer.eval()
332
+ print('in freeze', self.input_layer[1].training)
333
+ for param in self.input_layer.parameters():
334
+ param.requires_grad = False
335
+
336
+ for i in range(self.frozen_blocks):
337
+ m = self.body[i]
338
+ m.eval()
339
+ for param in m.parameters():
340
+ param.requires_grad = False
341
+
342
+ def IR_50(input_size):
343
+ """Constructs a ir-50 model.
344
+ """
345
+ model = Backbone(input_size, 50, 'ir')
346
+
347
+ return model
348
+
349
+
350
+ def IR_101(input_size):
351
+ """Constructs a ir-101 model.
352
+ """
353
+ model = Backbone(input_size, 100, 'ir')
354
+
355
+ return model
356
+
357
+
358
+ def IR_152(input_size):
359
+ """Constructs a ir-152 model.
360
+ """
361
+ model = Backbone(input_size, 152, 'ir')
362
+
363
+ return model
364
+
365
+
366
+ def IR_SE_50(input_size):
367
+ """Constructs a ir_se-50 model.
368
+ """
369
+ model = Backbone(input_size, 50, 'ir_se')
370
+
371
+ return model
372
+
373
+
374
+ def IR_SE_101(input_size):
375
+ """Constructs a ir_se-101 model.
376
+ """
377
+ model = Backbone(input_size, 100, 'ir_se')
378
+
379
+ return model
380
+
381
+
382
+ def IR_SE_152(input_size):
383
+ """Constructs a ir_se-152 model.
384
+ """
385
+ model = Backbone(input_size, 152, 'ir_se')
386
+
387
+ return model
CAGE_expression_inference-apvit/apvit_mmcls/models/backbones/irse_nopadding.py ADDED
@@ -0,0 +1,366 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import warnings
2
+ import torch.nn as nn
3
+ from torch.nn import Linear, Conv2d, BatchNorm1d, BatchNorm2d, PReLU, ReLU, Sigmoid, Dropout, MaxPool2d, \
4
+ AdaptiveAvgPool2d, Sequential, Module
5
+ from collections import namedtuple
6
+ import torch
7
+ from mmcv.runner import load_state_dict
8
+ from mmcls.utils import get_root_logger
9
+
10
+ from ..builder import BACKBONES
11
+ from .base_backbone import BaseBackbone
12
+
13
+ # Support: ['IR_50', 'IR_101', 'IR_152', 'IR_SE_50', 'IR_SE_101', 'IR_SE_152']
14
+
15
+ class Flatten(Module):
16
+ def forward(self, input):
17
+ return input.view(input.size(0), -1)
18
+
19
+
20
+ def l2_norm(input, axis=1):
21
+ norm = torch.norm(input, 2, axis, True)
22
+ output = torch.div(input, norm)
23
+
24
+ return output
25
+
26
+
27
+ class SEModule(Module):
28
+ def __init__(self, channels, reduction):
29
+ super(SEModule, self).__init__()
30
+ self.avg_pool = AdaptiveAvgPool2d(1)
31
+ self.fc1 = Conv2d(
32
+ channels, channels // reduction, kernel_size=1, padding=0, bias=False)
33
+
34
+ nn.init.xavier_uniform_(self.fc1.weight.data)
35
+
36
+ self.relu = ReLU(inplace=True)
37
+ self.fc2 = Conv2d(
38
+ channels // reduction, channels, kernel_size=1, padding=0, bias=False)
39
+
40
+ self.sigmoid = Sigmoid()
41
+
42
+ def forward(self, x):
43
+ module_input = x
44
+ x = self.avg_pool(x)
45
+ x = self.fc1(x)
46
+ x = self.relu(x)
47
+ x = self.fc2(x)
48
+ x = self.sigmoid(x)
49
+
50
+ return module_input * x
51
+
52
+
53
+ class bottleneck_IR(Module):
54
+ def __init__(self, in_channel, depth, stride):
55
+ super(bottleneck_IR, self).__init__()
56
+ if in_channel == depth:
57
+ self.shortcut_layer = MaxPool2d(1, stride)
58
+ else:
59
+ self.shortcut_layer = Sequential(
60
+ Conv2d(in_channel, depth, (1, 1), stride, bias=False),
61
+ BatchNorm2d(depth))
62
+ self.res_layer = Sequential(
63
+ BatchNorm2d(in_channel),
64
+ Conv2d(in_channel, depth, (3, 3), (1, 1), 1, bias=False),
65
+ PReLU(depth),
66
+ Conv2d(depth, depth, (3, 3), stride, 1, bias=False),
67
+ BatchNorm2d(depth))
68
+
69
+ def forward(self, x):
70
+ shortcut = self.shortcut_layer(x)
71
+ res = self.res_layer(x)
72
+
73
+ return res + shortcut
74
+
75
+
76
+ class BasicBlockIR(Module):
77
+ """
78
+ BasicBlock for IRNet, stolen from TFace
79
+ https://github.com/Tencent/TFace/blob/d57fd8d9ce9502240921f0998c57f84afa7eaeaa/torchkit/backbone/model_irse.py#L16
80
+ Add a BatchNorm2d after the first Conv2d
81
+ """
82
+ def __init__(self, in_channel, depth, stride):
83
+ super(BasicBlockIR, self).__init__()
84
+ if in_channel == depth:
85
+ self.shortcut_layer = MaxPool2d(1, stride)
86
+ else:
87
+ self.shortcut_layer = Sequential(
88
+ Conv2d(in_channel, depth, (1, 1), stride, bias=False),
89
+ BatchNorm2d(depth))
90
+ self.res_layer = Sequential(
91
+ BatchNorm2d(in_channel),
92
+ Conv2d(in_channel, depth, (3, 3), (1, 1), 0, bias=False),
93
+ BatchNorm2d(depth),
94
+ PReLU(depth),
95
+ Conv2d(depth, depth, (3, 3), stride, 0, bias=False),
96
+ BatchNorm2d(depth))
97
+
98
+ def forward(self, x):
99
+ shortcut = self.shortcut_layer(x)
100
+ res = self.res_layer(x)
101
+
102
+ return res + shortcut
103
+
104
+
105
+ class bottleneck_IR_SE(Module):
106
+ def __init__(self, in_channel, depth, stride):
107
+ super(bottleneck_IR_SE, self).__init__()
108
+ if in_channel == depth:
109
+ self.shortcut_layer = MaxPool2d(1, stride)
110
+ else:
111
+ self.shortcut_layer = Sequential(
112
+ Conv2d(in_channel, depth, (1, 1), stride, bias=False),
113
+ BatchNorm2d(depth))
114
+ self.res_layer = Sequential(
115
+ BatchNorm2d(in_channel),
116
+ Conv2d(in_channel, depth, (3, 3), (1, 1), 0, bias=False),
117
+ PReLU(depth),
118
+ Conv2d(depth, depth, (3, 3), stride, 0, bias=False),
119
+ BatchNorm2d(depth),
120
+ SEModule(depth, 16)
121
+ )
122
+
123
+ def forward(self, x):
124
+ shortcut = self.shortcut_layer(x)
125
+ res = self.res_layer(x)
126
+
127
+ return res + shortcut
128
+
129
+
130
+ class Bottleneck(namedtuple('Block', ['in_channel', 'depth', 'stride'])):
131
+ '''A named tuple describing a ResNet block.'''
132
+
133
+
134
+ def get_block(in_channel, depth, num_units, stride=2):
135
+
136
+ return [Bottleneck(in_channel, depth, stride)] + [Bottleneck(depth, depth, 1) for i in range(num_units - 1)]
137
+
138
+
139
+ def get_blocks(num_layers):
140
+
141
+ if num_layers == 8:
142
+ blocks = [
143
+ get_block(in_channel=64, depth=64, num_units=3),
144
+ ]
145
+ elif num_layers == 16:
146
+ blocks = [
147
+ get_block(in_channel=64, depth=64, num_units=3),
148
+ get_block(in_channel=64, depth=128, num_units=4),
149
+ ]
150
+ elif num_layers == 34:
151
+ blocks = [
152
+ get_block(in_channel=64, depth=64, num_units=3),
153
+ get_block(in_channel=64, depth=128, num_units=4),
154
+ get_block(in_channel=128, depth=256, num_units=6),
155
+ get_block(in_channel=256, depth=512, num_units=3)
156
+ ]
157
+ elif num_layers == 44:
158
+ blocks = [
159
+ get_block(in_channel=64, depth=64, num_units=3),
160
+ get_block(in_channel=64, depth=128, num_units=4),
161
+ get_block(in_channel=128, depth=256, num_units=14),
162
+ ]
163
+ elif num_layers == 50:
164
+ blocks = [
165
+ get_block(in_channel=64, depth=64, num_units=3), # (B, 64, 56, 56)
166
+ get_block(in_channel=64, depth=128, num_units=4), # (B, 128, 28, 28)
167
+ get_block(in_channel=128, depth=256, num_units=14), # (B, 256, 14, 14)
168
+ get_block(in_channel=256, depth=512, num_units=3) # (B, 512, 7, 7)
169
+ ]
170
+ elif num_layers == 100:
171
+ blocks = [
172
+ get_block(in_channel=64, depth=64, num_units=3),
173
+ get_block(in_channel=64, depth=128, num_units=13),
174
+ get_block(in_channel=128, depth=256, num_units=30),
175
+ get_block(in_channel=256, depth=512, num_units=3)
176
+ ]
177
+ elif num_layers == 152:
178
+ blocks = [
179
+ get_block(in_channel=64, depth=64, num_units=3),
180
+ get_block(in_channel=64, depth=128, num_units=8),
181
+ get_block(in_channel=128, depth=256, num_units=36),
182
+ get_block(in_channel=256, depth=512, num_units=3)
183
+ ]
184
+
185
+ return blocks
186
+
187
+
188
+ @BACKBONES.register_module()
189
+ class IRSENoPadding(BaseBackbone):
190
+ def __init__(self, input_size, num_layers, mode='ir', with_head=False, pretrained=None, return_index=(0, 1, 2)):
191
+ super().__init__()
192
+ assert input_size[0] in [112, 224], "input_size should be [112, 112] or [224, 224]"
193
+ assert num_layers in [0, 8, 16, 34, 44, 50, 100, 152], "num_layers should be 50, 100 or 152"
194
+ assert mode in ['ir', 'ir_se'], "mode should be ir or ir_se"
195
+ self.num_layers = num_layers
196
+ self.return_index = return_index
197
+ if num_layers == 0:
198
+ return
199
+ self.with_head = with_head
200
+ blocks = get_blocks(num_layers)
201
+ if mode == 'ir':
202
+ if num_layers == 34:
203
+ warnings.warn('Using the IR_34 version from TFace')
204
+ unit_module = BasicBlockIR
205
+ else:
206
+ unit_module = bottleneck_IR
207
+ elif mode == 'ir_se':
208
+ unit_module = bottleneck_IR_SE
209
+ self.input_layer = Sequential(Conv2d(3, 64, (3, 3), 1, 0, bias=False),
210
+ BatchNorm2d(64),
211
+ PReLU(64))
212
+ if with_head:
213
+ if input_size[0] == 112:
214
+ self.output_layer = Sequential(BatchNorm2d(512),
215
+ Dropout(),
216
+ Flatten(),
217
+ Linear(512 * 7 * 7, 512),
218
+ BatchNorm1d(512))
219
+ else:
220
+ self.output_layer = Sequential(BatchNorm2d(512),
221
+ Dropout(),
222
+ Flatten(),
223
+ Linear(512 * 14 * 14, 512),
224
+ BatchNorm1d(512))
225
+
226
+ modules = []
227
+ max_stage = max(return_index)
228
+ for block in blocks[:max_stage+1]:
229
+ block_module = []
230
+ for bottleneck in block:
231
+ block_module.append(
232
+ unit_module(bottleneck.in_channel,
233
+ bottleneck.depth,
234
+ bottleneck.stride))
235
+ modules.append(Sequential(*block_module))
236
+ # self.body = Sequential(*modules)
237
+ self.body = nn.ModuleList(modules)
238
+
239
+ self._initialize_weights()
240
+ if pretrained:
241
+ self.init_weights(pretrained)
242
+
243
+ def init_weights(self, pretrained):
244
+ logger = get_root_logger()
245
+ logger.warning(f'{self.__class__.__name__} load pretrain from {pretrained}')
246
+ state_dict = torch.load(pretrained, map_location='cpu')
247
+ if 'state_dict' in state_dict:
248
+ state_dict = state_dict['state_dict']
249
+
250
+ stage_unit_nums = {
251
+ 34: (3, 4, 6, 3),
252
+ 50: (3, 4, 14, 3),
253
+ }
254
+ stage_num = stage_unit_nums[self.num_layers]
255
+
256
+ new_state_dict = dict()
257
+ for k, v in state_dict.items():
258
+ if k.startswith('body.'):
259
+ index = int(k.split('.')[1])
260
+ if 0 <= index < stage_num[0]:
261
+ new_key = k.replace('body.', 'body.0.')
262
+ elif stage_num[0] <= index < sum(stage_num[:2]):
263
+ new_key = f"body.1.{index-sum(stage_num[:1])}.{'.'.join(k.split('.')[2:])}"
264
+ elif sum(stage_num[:2]) <= index < sum(stage_num[:3]):
265
+ new_key = f"body.2.{index-sum(stage_num[:2])}.{'.'.join(k.split('.')[2:])}"
266
+ else:
267
+ new_key = k
268
+ else:
269
+ new_key = k
270
+ new_state_dict[new_key] = v
271
+
272
+ load_state_dict(self, new_state_dict, strict=False, logger=logger)
273
+
274
+ def forward(self, x):
275
+ if self.num_layers == 0:
276
+ return x
277
+ x = self.input_layer(x)
278
+ output = []
279
+ return_index = set(self.return_index)
280
+ for index, m in enumerate(self.body):
281
+ x = m(x)
282
+ if index in return_index:
283
+ output.append(x)
284
+ if self.with_head:
285
+ x = self.output_layer(x)
286
+
287
+ return output
288
+
289
+ def _initialize_weights(self):
290
+ for m in self.modules():
291
+ if isinstance(m, nn.Conv2d):
292
+ nn.init.xavier_uniform_(m.weight.data)
293
+ if m.bias is not None:
294
+ m.bias.data.zero_()
295
+ elif isinstance(m, nn.BatchNorm2d):
296
+ m.weight.data.fill_(1)
297
+ m.bias.data.zero_()
298
+ elif isinstance(m, nn.BatchNorm1d):
299
+ m.weight.data.fill_(1)
300
+ m.bias.data.zero_()
301
+ elif isinstance(m, nn.Linear):
302
+ nn.init.xavier_uniform_(m.weight.data)
303
+ if m.bias is not None:
304
+ m.bias.data.zero_()
305
+
306
+
307
+ def _freeze_stages(self):
308
+ if self.frozen_blocks > 0:
309
+ print(f'IRSE freeze the first {self.frozen_blocks} blocks, it has {len(self.body)} blocks ')
310
+ self.input_layer.eval()
311
+ print('in freeze', self.input_layer[1].training)
312
+ for param in self.input_layer.parameters():
313
+ param.requires_grad = False
314
+
315
+ for i in range(self.frozen_blocks):
316
+ m = self.body[i]
317
+ m.eval()
318
+ for param in m.parameters():
319
+ param.requires_grad = False
320
+
321
+ def IR_50(input_size):
322
+ """Constructs a ir-50 model.
323
+ """
324
+ model = Backbone(input_size, 50, 'ir')
325
+
326
+ return model
327
+
328
+
329
+ def IR_101(input_size):
330
+ """Constructs a ir-101 model.
331
+ """
332
+ model = Backbone(input_size, 100, 'ir')
333
+
334
+ return model
335
+
336
+
337
+ def IR_152(input_size):
338
+ """Constructs a ir-152 model.
339
+ """
340
+ model = Backbone(input_size, 152, 'ir')
341
+
342
+ return model
343
+
344
+
345
+ def IR_SE_50(input_size):
346
+ """Constructs a ir_se-50 model.
347
+ """
348
+ model = Backbone(input_size, 50, 'ir_se')
349
+
350
+ return model
351
+
352
+
353
+ def IR_SE_101(input_size):
354
+ """Constructs a ir_se-101 model.
355
+ """
356
+ model = Backbone(input_size, 100, 'ir_se')
357
+
358
+ return model
359
+
360
+
361
+ def IR_SE_152(input_size):
362
+ """Constructs a ir_se-152 model.
363
+ """
364
+ model = Backbone(input_size, 152, 'ir_se')
365
+
366
+ return model
CAGE_expression_inference-apvit/apvit_mmcls/models/backbones/lenet.py ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch.nn as nn
2
+
3
+ from ..builder import BACKBONES
4
+ from .base_backbone import BaseBackbone
5
+
6
+
7
+ @BACKBONES.register_module()
8
+ class LeNet5(BaseBackbone):
9
+ """`LeNet5 <https://en.wikipedia.org/wiki/LeNet>`_ backbone.
10
+
11
+ The input for LeNet-5 is a 32×32 grayscale image.
12
+
13
+ Args:
14
+ num_classes (int): number of classes for classification.
15
+ The default value is -1, which uses the backbone as
16
+ a feature extractor without the top classifier.
17
+ """
18
+
19
+ def __init__(self, num_classes=-1):
20
+ super(LeNet5, self).__init__()
21
+ self.num_classes = num_classes
22
+ self.features = nn.Sequential(
23
+ nn.Conv2d(1, 6, kernel_size=5, stride=1), nn.Tanh(),
24
+ nn.AvgPool2d(kernel_size=2),
25
+ nn.Conv2d(6, 16, kernel_size=5, stride=1), nn.Tanh(),
26
+ nn.AvgPool2d(kernel_size=2),
27
+ nn.Conv2d(16, 120, kernel_size=5, stride=1), nn.Tanh())
28
+ if self.num_classes > 0:
29
+ self.classifier = nn.Sequential(
30
+ nn.Linear(120, 84),
31
+ nn.Tanh(),
32
+ nn.Linear(84, num_classes),
33
+ )
34
+
35
+ def forward(self, x):
36
+
37
+ x = self.features(x)
38
+ if self.num_classes > 0:
39
+ x = self.classifier(x.squeeze())
40
+
41
+ return x
CAGE_expression_inference-apvit/apvit_mmcls/models/backbones/mobilefacenet.py ADDED
@@ -0,0 +1,133 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torch.nn as nn
3
+ from torch.nn import Linear, Conv2d, BatchNorm1d, BatchNorm2d, PReLU, Module, Sequential
4
+
5
+ from ..builder import BACKBONES
6
+ from .base_backbone import BaseBackbone
7
+
8
+
9
+ class Flatten(Module):
10
+ def forward(self, input):
11
+ return input.view(input.size(0), -1)
12
+
13
+
14
+ def l2_norm(input,axis=1):
15
+ norm = torch.norm(input,2,axis,True)
16
+ output = torch.div(input, norm)
17
+ return output
18
+
19
+
20
+ class Conv_block(Module):
21
+ def __init__(self, in_c, out_c, kernel=(1, 1), stride=(1, 1), padding=(0, 0), groups=1):
22
+ super(Conv_block, self).__init__()
23
+ self.conv = Conv2d(in_c, out_channels=out_c, kernel_size=kernel, groups=groups, stride=stride, padding=padding, bias=False)
24
+ self.bn = BatchNorm2d(out_c)
25
+ self.prelu = PReLU(out_c)
26
+ def forward(self, x):
27
+ x = self.conv(x)
28
+ x = self.bn(x)
29
+ x = self.prelu(x)
30
+ return x
31
+
32
+ class Linear_block(Module):
33
+ def __init__(self, in_c, out_c, kernel=(1, 1), stride=(1, 1), padding=(0, 0), groups=1):
34
+ super(Linear_block, self).__init__()
35
+ self.conv = Conv2d(in_c, out_channels=out_c, kernel_size=kernel, groups=groups, stride=stride, padding=padding, bias=False)
36
+ self.bn = BatchNorm2d(out_c)
37
+ def forward(self, x):
38
+ x = self.conv(x)
39
+ x = self.bn(x)
40
+ return x
41
+
42
+ class Depth_Wise(Module):
43
+ def __init__(self, in_c, out_c, residual = False, kernel=(3, 3), stride=(2, 2), padding=(1, 1), groups=1):
44
+ super(Depth_Wise, self).__init__()
45
+ self.conv = Conv_block(in_c, out_c=groups, kernel=(1, 1), padding=(0, 0), stride=(1, 1))
46
+ self.conv_dw = Conv_block(groups, groups, groups=groups, kernel=kernel, padding=padding, stride=stride)
47
+ self.project = Linear_block(groups, out_c, kernel=(1, 1), padding=(0, 0), stride=(1, 1))
48
+ self.residual = residual
49
+ def forward(self, x):
50
+ short_cut = None
51
+ if self.residual:
52
+ short_cut = x
53
+ x = self.conv(x)
54
+ x = self.conv_dw(x)
55
+ x = self.project(x)
56
+ if self.residual:
57
+ output = short_cut + x
58
+ else:
59
+ output = x
60
+ return output
61
+
62
+ class Residual(Module):
63
+ def __init__(self, c, num_block, groups, kernel=(3, 3), stride=(1, 1), padding=(1, 1)):
64
+ super(Residual, self).__init__()
65
+ modules = []
66
+ for _ in range(num_block):
67
+ modules.append(Depth_Wise(c, c, residual=True, kernel=kernel, padding=padding, stride=stride, groups=groups))
68
+ self.model = Sequential(*modules)
69
+ def forward(self, x):
70
+ return self.model(x)
71
+
72
+
73
+ @BACKBONES.register_module()
74
+ class MobileFaceNet(BaseBackbone):
75
+ """`MobileFaceNet <https://github.com/TreB1eN/InsightFace_Pytorch>`_ backbone.
76
+
77
+ The input for MobileFaceNet is a 224x224 RGB image.
78
+
79
+ Args:
80
+ num_classes (int): number of classes for classification.
81
+ The default value is -1, which uses the backbone as
82
+ a feature extractor without the top classifier.
83
+ """
84
+ def __init__(self, return_stages=[2], pretrained=None):
85
+ super().__init__()
86
+ self.conv1 = Conv_block(3, 64, kernel=(3, 3), stride=(2, 2), padding=(1, 1))
87
+
88
+ self.conv2_dw = Conv_block(64, 64, kernel=(3, 3), stride=(1, 1), padding=(1, 1), groups=64)
89
+
90
+ self.conv_23 = Depth_Wise(64, 64, kernel=(3, 3), stride=(2, 2), padding=(1, 1), groups=128)
91
+ self.conv_3 = Residual(64, num_block=4, groups=128, kernel=(3, 3), stride=(1, 1), padding=(1, 1))
92
+
93
+ self.conv_34 = Depth_Wise(64, 128, kernel=(3, 3), stride=(2, 2), padding=(1, 1), groups=256)
94
+ self.conv_4 = Residual(128, num_block=6, groups=256, kernel=(3, 3), stride=(1, 1), padding=(1, 1))
95
+
96
+ # self.conv_45 = Depth_Wise(128, 128, kernel=(3, 3), stride=(2, 2), padding=(1, 1), groups=512)
97
+ # self.conv_5 = Residual(128, num_block=2, groups=256, kernel=(3, 3), stride=(1, 1), padding=(1, 1))
98
+
99
+ # self.conv_6_sep = Conv_block(128, 512, kernel=(1, 1), stride=(1, 1), padding=(0, 0))
100
+ # self.conv_6_dw = Linear_block(512, 512, groups=512, kernel=(7,7), stride=(1, 1), padding=(0, 0))
101
+ # self.conv_6_flatten = Flatten()
102
+ # self.linear = Linear(512, embedding_size, bias=False)
103
+ # self.bn = BatchNorm1d(embedding_size)
104
+ self.return_stages = set(return_stages)
105
+ if pretrained:
106
+ self.init_weights(pretrained)
107
+
108
+ def forward(self, x):
109
+ output = []
110
+ out = self.conv1(x)
111
+ out = self.conv2_dw(out)
112
+ if 0 in self.return_stages:
113
+ output.append(out)
114
+
115
+ out = self.conv_23(out)
116
+ out = self.conv_3(out)
117
+ if 1 in self.return_stages:
118
+ output.append(out)
119
+
120
+ out = self.conv_34(out)
121
+ out = self.conv_4(out)
122
+ if 2 in self.return_stages:
123
+ output.append(out)
124
+ # out = self.conv_45(out)
125
+ # out = self.conv_5(out)
126
+ # out = self.conv_6_sep(out)
127
+ # out = self.conv_6_dw(out)
128
+ # out = self.conv_6_flatten(out)
129
+ # out = self.linear(out)
130
+ # out = self.bn(out)
131
+ # print(out.shape)
132
+ # return out
133
+ return output
CAGE_expression_inference-apvit/apvit_mmcls/models/backbones/mobilenet_v2.py ADDED
@@ -0,0 +1,273 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import logging
2
+
3
+ import torch.nn as nn
4
+ import torch.utils.checkpoint as cp
5
+ from mmcv.cnn import ConvModule, constant_init, kaiming_init
6
+ from mmcv.runner import load_checkpoint
7
+ from torch.nn.modules.batchnorm import _BatchNorm
8
+
9
+ from mmcls.models.utils import make_divisible
10
+ from ..builder import BACKBONES
11
+ from .base_backbone import BaseBackbone
12
+
13
+
14
+ class InvertedResidual(nn.Module):
15
+ """InvertedResidual block for MobileNetV2.
16
+
17
+ Args:
18
+ in_channels (int): The input channels of the InvertedResidual block.
19
+ out_channels (int): The output channels of the InvertedResidual block.
20
+ stride (int): Stride of the middle (first) 3x3 convolution.
21
+ expand_ratio (int): adjusts number of channels of the hidden layer
22
+ in InvertedResidual by this amount.
23
+ conv_cfg (dict): Config dict for convolution layer.
24
+ Default: None, which means using conv2d.
25
+ norm_cfg (dict): Config dict for normalization layer.
26
+ Default: dict(type='BN').
27
+ act_cfg (dict): Config dict for activation layer.
28
+ Default: dict(type='ReLU6').
29
+ with_cp (bool): Use checkpoint or not. Using checkpoint will save some
30
+ memory while slowing down the training speed. Default: False.
31
+
32
+ Returns:
33
+ Tensor: The output tensor
34
+ """
35
+
36
+ def __init__(self,
37
+ in_channels,
38
+ out_channels,
39
+ stride,
40
+ expand_ratio,
41
+ conv_cfg=None,
42
+ norm_cfg=dict(type='BN'),
43
+ act_cfg=dict(type='ReLU6'),
44
+ with_cp=False):
45
+ super(InvertedResidual, self).__init__()
46
+ self.stride = stride
47
+ assert stride in [1, 2], f'stride must in [1, 2]. ' \
48
+ f'But received {stride}.'
49
+ self.with_cp = with_cp
50
+ self.use_res_connect = self.stride == 1 and in_channels == out_channels
51
+ hidden_dim = int(round(in_channels * expand_ratio))
52
+
53
+ layers = []
54
+ if expand_ratio != 1:
55
+ layers.append(
56
+ ConvModule(
57
+ in_channels=in_channels,
58
+ out_channels=hidden_dim,
59
+ kernel_size=1,
60
+ conv_cfg=conv_cfg,
61
+ norm_cfg=norm_cfg,
62
+ act_cfg=act_cfg))
63
+ layers.extend([
64
+ ConvModule(
65
+ in_channels=hidden_dim,
66
+ out_channels=hidden_dim,
67
+ kernel_size=3,
68
+ stride=stride,
69
+ padding=1,
70
+ groups=hidden_dim,
71
+ conv_cfg=conv_cfg,
72
+ norm_cfg=norm_cfg,
73
+ act_cfg=act_cfg),
74
+ ConvModule(
75
+ in_channels=hidden_dim,
76
+ out_channels=out_channels,
77
+ kernel_size=1,
78
+ conv_cfg=conv_cfg,
79
+ norm_cfg=norm_cfg,
80
+ act_cfg=None)
81
+ ])
82
+ self.conv = nn.Sequential(*layers)
83
+
84
+ def forward(self, x):
85
+
86
+ def _inner_forward(x):
87
+ if self.use_res_connect:
88
+ return x + self.conv(x)
89
+ else:
90
+ return self.conv(x)
91
+
92
+ if self.with_cp and x.requires_grad:
93
+ out = cp.checkpoint(_inner_forward, x)
94
+ else:
95
+ out = _inner_forward(x)
96
+
97
+ return out
98
+
99
+
100
+ @BACKBONES.register_module()
101
+ class MobileNetV2(BaseBackbone):
102
+ """MobileNetV2 backbone.
103
+
104
+ Args:
105
+ widen_factor (float): Width multiplier, multiply number of
106
+ channels in each layer by this amount. Default: 1.0.
107
+ out_indices (None or Sequence[int]): Output from which stages.
108
+ Default: (7, ).
109
+ frozen_stages (int): Stages to be frozen (all param fixed).
110
+ Default: -1, which means not freezing any parameters.
111
+ conv_cfg (dict): Config dict for convolution layer.
112
+ Default: None, which means using conv2d.
113
+ norm_cfg (dict): Config dict for normalization layer.
114
+ Default: dict(type='BN').
115
+ act_cfg (dict): Config dict for activation layer.
116
+ Default: dict(type='ReLU6').
117
+ norm_eval (bool): Whether to set norm layers to eval mode, namely,
118
+ freeze running stats (mean and var). Note: Effect on Batch Norm
119
+ and its variants only. Default: False.
120
+ with_cp (bool): Use checkpoint or not. Using checkpoint will save some
121
+ memory while slowing down the training speed. Default: False.
122
+ """
123
+
124
+ # Parameters to build layers. 4 parameters are needed to construct a
125
+ # layer, from left to right: expand_ratio, channel, num_blocks, stride.
126
+ arch_settings = [[1, 16, 1, 1], [6, 24, 2, 2], [6, 32, 3, 2],
127
+ [6, 64, 4, 2], [6, 96, 3, 1], [6, 160, 3, 2],
128
+ [6, 320, 1, 1]]
129
+
130
+ def __init__(self,
131
+ widen_factor=1.,
132
+ out_indices=(7, ),
133
+ frozen_stages=-1,
134
+ conv_cfg=None,
135
+ norm_cfg=dict(type='BN'),
136
+ act_cfg=dict(type='ReLU6'),
137
+ norm_eval=False,
138
+ with_cp=False):
139
+ super(MobileNetV2, self).__init__()
140
+ self.widen_factor = widen_factor
141
+ self.out_indices = out_indices
142
+ for index in out_indices:
143
+ if index not in range(0, 8):
144
+ raise ValueError('the item in out_indices must in '
145
+ f'range(0, 8). But received {index}')
146
+
147
+ if frozen_stages not in range(-1, 8):
148
+ raise ValueError('frozen_stages must be in range(-1, 8). '
149
+ f'But received {frozen_stages}')
150
+ self.out_indices = out_indices
151
+ self.frozen_stages = frozen_stages
152
+ self.conv_cfg = conv_cfg
153
+ self.norm_cfg = norm_cfg
154
+ self.act_cfg = act_cfg
155
+ self.norm_eval = norm_eval
156
+ self.with_cp = with_cp
157
+
158
+ self.in_channels = make_divisible(32 * widen_factor, 8)
159
+
160
+ self.conv1 = ConvModule(
161
+ in_channels=3,
162
+ out_channels=self.in_channels,
163
+ kernel_size=3,
164
+ stride=2,
165
+ padding=1,
166
+ conv_cfg=self.conv_cfg,
167
+ norm_cfg=self.norm_cfg,
168
+ act_cfg=self.act_cfg)
169
+
170
+ self.layers = []
171
+
172
+ for i, layer_cfg in enumerate(self.arch_settings):
173
+ expand_ratio, channel, num_blocks, stride = layer_cfg
174
+ out_channels = make_divisible(channel * widen_factor, 8)
175
+ inverted_res_layer = self.make_layer(
176
+ out_channels=out_channels,
177
+ num_blocks=num_blocks,
178
+ stride=stride,
179
+ expand_ratio=expand_ratio)
180
+ layer_name = f'layer{i + 1}'
181
+ self.add_module(layer_name, inverted_res_layer)
182
+ self.layers.append(layer_name)
183
+
184
+ if widen_factor > 1.0:
185
+ self.out_channel = int(1280 * widen_factor)
186
+ else:
187
+ self.out_channel = 1280
188
+
189
+ layer = ConvModule(
190
+ in_channels=self.in_channels,
191
+ out_channels=self.out_channel,
192
+ kernel_size=1,
193
+ stride=1,
194
+ padding=0,
195
+ conv_cfg=self.conv_cfg,
196
+ norm_cfg=self.norm_cfg,
197
+ act_cfg=self.act_cfg)
198
+ self.add_module('conv2', layer)
199
+ self.layers.append('conv2')
200
+
201
+ def make_layer(self, out_channels, num_blocks, stride, expand_ratio):
202
+ """ Stack InvertedResidual blocks to build a layer for MobileNetV2.
203
+
204
+ Args:
205
+ out_channels (int): out_channels of block.
206
+ num_blocks (int): number of blocks.
207
+ stride (int): stride of the first block. Default: 1
208
+ expand_ratio (int): Expand the number of channels of the
209
+ hidden layer in InvertedResidual by this ratio. Default: 6.
210
+ """
211
+ layers = []
212
+ for i in range(num_blocks):
213
+ if i >= 1:
214
+ stride = 1
215
+ layers.append(
216
+ InvertedResidual(
217
+ self.in_channels,
218
+ out_channels,
219
+ stride,
220
+ expand_ratio=expand_ratio,
221
+ conv_cfg=self.conv_cfg,
222
+ norm_cfg=self.norm_cfg,
223
+ act_cfg=self.act_cfg,
224
+ with_cp=self.with_cp))
225
+ self.in_channels = out_channels
226
+
227
+ return nn.Sequential(*layers)
228
+
229
+ def init_weights(self, pretrained=None):
230
+ if isinstance(pretrained, str):
231
+ logger = logging.getLogger()
232
+ load_checkpoint(self, pretrained, strict=False, logger=logger)
233
+ elif pretrained is None:
234
+ for m in self.modules():
235
+ if isinstance(m, nn.Conv2d):
236
+ kaiming_init(m)
237
+ elif isinstance(m, (_BatchNorm, nn.GroupNorm)):
238
+ constant_init(m, 1)
239
+ else:
240
+ raise TypeError('pretrained must be a str or None')
241
+
242
+ def forward(self, x):
243
+ x = self.conv1(x)
244
+
245
+ outs = []
246
+ for i, layer_name in enumerate(self.layers):
247
+ layer = getattr(self, layer_name)
248
+ x = layer(x)
249
+ if i in self.out_indices:
250
+ outs.append(x)
251
+
252
+ if len(outs) == 1:
253
+ return outs[0]
254
+ else:
255
+ return tuple(outs)
256
+
257
+ def _freeze_stages(self):
258
+ if self.frozen_stages >= 0:
259
+ for param in self.conv1.parameters():
260
+ param.requires_grad = False
261
+ for i in range(1, self.frozen_stages + 1):
262
+ layer = getattr(self, f'layer{i}')
263
+ layer.eval()
264
+ for param in layer.parameters():
265
+ param.requires_grad = False
266
+
267
+ def train(self, mode=True):
268
+ super(MobileNetV2, self).train(mode)
269
+ self._freeze_stages()
270
+ if mode and self.norm_eval:
271
+ for m in self.modules():
272
+ if isinstance(m, _BatchNorm):
273
+ m.eval()
CAGE_expression_inference-apvit/apvit_mmcls/models/backbones/mobilenet_v3.py ADDED
@@ -0,0 +1,186 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import logging
2
+
3
+ import torch.nn as nn
4
+ from mmcv.cnn import ConvModule, constant_init, kaiming_init
5
+ from mmcv.runner import load_checkpoint
6
+ from torch.nn.modules.batchnorm import _BatchNorm
7
+
8
+ from ..builder import BACKBONES
9
+ from ..utils import InvertedResidual
10
+ from .base_backbone import BaseBackbone
11
+
12
+
13
+ @BACKBONES.register_module()
14
+ class MobileNetv3(BaseBackbone):
15
+ """ MobileNetv3 backbone
16
+
17
+ Args:
18
+ arch (str): Architechture of mobilnetv3, from {small, big}.
19
+ Default: small.
20
+ conv_cfg (dict): Config dict for convolution layer.
21
+ Default: None, which means using conv2d.
22
+ norm_cfg (dict): Config dict for normalization layer.
23
+ Default: dict(type='BN').
24
+ out_indices (None or Sequence[int]): Output from which stages.
25
+ Default: (10, ), which means output tensors from final stage.
26
+ frozen_stages (int): Stages to be frozen (all param fixed).
27
+ Defualt: -1, which means not freezing any parameters.
28
+ norm_eval (bool): Whether to set norm layers to eval mode, namely,
29
+ freeze running stats (mean and var). Note: Effect on Batch Norm
30
+ and its variants only. Default: False.
31
+ with_cp (bool): Use checkpoint or not. Using checkpoint will save
32
+ some memory while slowing down the training speed.
33
+ Defualt: False.
34
+ """
35
+ # Parameters to build each block:
36
+ # [kernel size, mid channels, out channels, with_se, act type, stride]
37
+ arch_settings = {
38
+ 'small': [[3, 16, 16, True, 'ReLU', 2],
39
+ [3, 72, 24, False, 'ReLU', 2],
40
+ [3, 88, 24, False, 'ReLU', 1],
41
+ [5, 96, 40, True, 'HSwish', 2],
42
+ [5, 240, 40, True, 'HSwish', 1],
43
+ [5, 240, 40, True, 'HSwish', 1],
44
+ [5, 120, 48, True, 'HSwish', 1],
45
+ [5, 144, 48, True, 'HSwish', 1],
46
+ [5, 288, 96, True, 'HSwish', 2],
47
+ [5, 576, 96, True, 'HSwish', 1],
48
+ [5, 576, 96, True, 'HSwish', 1]],
49
+ 'big': [[3, 16, 16, False, 'ReLU', 1],
50
+ [3, 64, 24, False, 'ReLU', 2],
51
+ [3, 72, 24, False, 'ReLU', 1],
52
+ [5, 72, 40, True, 'ReLU', 2],
53
+ [5, 120, 40, True, 'ReLU', 1],
54
+ [5, 120, 40, True, 'ReLU', 1],
55
+ [3, 240, 80, False, 'HSwish', 2],
56
+ [3, 200, 80, False, 'HSwish', 1],
57
+ [3, 184, 80, False, 'HSwish', 1],
58
+ [3, 184, 80, False, 'HSwish', 1],
59
+ [3, 480, 112, True, 'HSwish', 1],
60
+ [3, 672, 112, True, 'HSwish', 1],
61
+ [5, 672, 160, True, 'HSwish', 1],
62
+ [5, 672, 160, True, 'HSwish', 2],
63
+ [5, 960, 160, True, 'HSwish', 1]]
64
+ } # yapf: disable
65
+
66
+ def __init__(self,
67
+ arch='small',
68
+ conv_cfg=None,
69
+ norm_cfg=dict(type='BN'),
70
+ out_indices=(10, ),
71
+ frozen_stages=-1,
72
+ norm_eval=False,
73
+ with_cp=False):
74
+ super(MobileNetv3, self).__init__()
75
+ assert arch in self.arch_settings
76
+ for index in out_indices:
77
+ if index not in range(0, len(self.arch_settings[arch])):
78
+ raise ValueError('the item in out_indices must in '
79
+ f'range(0, {len(self.arch_settings[arch])}). '
80
+ f'But received {index}')
81
+
82
+ if frozen_stages not in range(-1, len(self.arch_settings[arch])):
83
+ raise ValueError('frozen_stages must be in range(-1, '
84
+ f'{len(self.arch_settings[arch])}). '
85
+ f'But received {frozen_stages}')
86
+ self.out_indices = out_indices
87
+ self.frozen_stages = frozen_stages
88
+ self.arch = arch
89
+ self.conv_cfg = conv_cfg
90
+ self.norm_cfg = norm_cfg
91
+ self.out_indices = out_indices
92
+ self.frozen_stages = frozen_stages
93
+ self.norm_eval = norm_eval
94
+ self.with_cp = with_cp
95
+
96
+ self.in_channels = 16
97
+ self.conv1 = ConvModule(
98
+ in_channels=3,
99
+ out_channels=self.in_channels,
100
+ kernel_size=3,
101
+ stride=2,
102
+ padding=1,
103
+ conv_cfg=conv_cfg,
104
+ norm_cfg=norm_cfg,
105
+ act_cfg=dict(type='HSwish'))
106
+
107
+ self.layers = self._make_layer()
108
+ self.feat_dim = self.arch_settings[arch][-1][2]
109
+
110
+ def _make_layer(self):
111
+ layers = []
112
+ layer_setting = self.arch_settings[self.arch]
113
+ for i, params in enumerate(layer_setting):
114
+ (kernel_size, mid_channels, out_channels, with_se, act,
115
+ stride) = params
116
+ if with_se:
117
+ se_cfg = dict(
118
+ channels=mid_channels,
119
+ ratio=4,
120
+ act_cfg=(dict(type='ReLU'), dict(type='HSigmoid')))
121
+ else:
122
+ se_cfg = None
123
+
124
+ layer = InvertedResidual(
125
+ in_channels=self.in_channels,
126
+ out_channels=out_channels,
127
+ mid_channels=mid_channels,
128
+ kernel_size=kernel_size,
129
+ stride=stride,
130
+ se_cfg=se_cfg,
131
+ with_expand_conv=True,
132
+ conv_cfg=self.conv_cfg,
133
+ norm_cfg=self.norm_cfg,
134
+ act_cfg=dict(type=act),
135
+ with_cp=self.with_cp)
136
+ self.in_channels = out_channels
137
+ layer_name = 'layer{}'.format(i + 1)
138
+ self.add_module(layer_name, layer)
139
+ layers.append(layer_name)
140
+ return layers
141
+
142
+ def init_weights(self, pretrained=None):
143
+ if isinstance(pretrained, str):
144
+ logger = logging.getLogger()
145
+ load_checkpoint(self, pretrained, strict=False, logger=logger)
146
+ elif pretrained is None:
147
+ for m in self.modules():
148
+ if isinstance(m, nn.Conv2d):
149
+ kaiming_init(m)
150
+ elif isinstance(m, nn.BatchNorm2d):
151
+ constant_init(m, 1)
152
+ else:
153
+ raise TypeError('pretrained must be a str or None')
154
+
155
+ def forward(self, x):
156
+ x = self.conv1(x)
157
+
158
+ outs = []
159
+ for i, layer_name in enumerate(self.layers):
160
+ layer = getattr(self, layer_name)
161
+ x = layer(x)
162
+ if i in self.out_indices:
163
+ outs.append(x)
164
+
165
+ if len(outs) == 1:
166
+ return outs[0]
167
+ else:
168
+ return tuple(outs)
169
+
170
+ def _freeze_stages(self):
171
+ if self.frozen_stages >= 0:
172
+ for param in self.conv1.parameters():
173
+ param.requires_grad = False
174
+ for i in range(1, self.frozen_stages + 1):
175
+ layer = getattr(self, f'layer{i}')
176
+ layer.eval()
177
+ for param in layer.parameters():
178
+ param.requires_grad = False
179
+
180
+ def train(self, mode=True):
181
+ super(MobileNetv3, self).train(mode)
182
+ self._freeze_stages()
183
+ if mode and self.norm_eval:
184
+ for m in self.modules():
185
+ if isinstance(m, _BatchNorm):
186
+ m.eval()
CAGE_expression_inference-apvit/apvit_mmcls/models/backbones/modules/t2t.py ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import math
2
+ import torch
3
+ from torch import nn
4
+
5
+
6
+ class Token_performer(nn.Module):
7
+ def __init__(self, dim, in_dim, head_cnt=1, kernel_ratio=0.5, dp1=0.1, dp2 = 0.1):
8
+ super().__init__()
9
+ self.emb = in_dim * head_cnt # we use 1, so it is no need here
10
+ self.kqv = nn.Linear(dim, 3 * self.emb)
11
+ self.dp = nn.Dropout(dp1)
12
+ self.proj = nn.Linear(self.emb, self.emb)
13
+ self.head_cnt = head_cnt
14
+ self.norm1 = nn.LayerNorm(dim)
15
+ self.norm2 = nn.LayerNorm(self.emb)
16
+ self.epsilon = 1e-8 # for stable in division
17
+
18
+ self.mlp = nn.Sequential(
19
+ nn.Linear(self.emb, 1 * self.emb),
20
+ nn.GELU(),
21
+ nn.Linear(1 * self.emb, self.emb),
22
+ nn.Dropout(dp2),
23
+ )
24
+
25
+ self.m = int(self.emb * kernel_ratio)
26
+ self.w = torch.randn(self.m, self.emb)
27
+ self.w = nn.Parameter(nn.init.orthogonal_(self.w) * math.sqrt(self.m), requires_grad=False)
28
+
29
+ def prm_exp(self, x):
30
+ # part of the function is borrow from https://github.com/lucidrains/performer-pytorch
31
+ # and Simo Ryu (https://github.com/cloneofsimo)
32
+ # ==== positive random features for gaussian kernels ====
33
+ # x = (B, T, hs)
34
+ # w = (m, hs)
35
+ # return : x : B, T, m
36
+ # SM(x, y) = E_w[exp(w^T x - |x|/2) exp(w^T y - |y|/2)]
37
+ # therefore return exp(w^Tx - |x|/2)/sqrt(m)
38
+ xd = ((x * x).sum(dim=-1, keepdim=True)).repeat(1, 1, self.m) / 2
39
+ wtx = torch.einsum('bti,mi->btm', x.float(), self.w)
40
+
41
+ return torch.exp(wtx - xd) / math.sqrt(self.m)
42
+
43
+ def single_attn(self, x):
44
+ k, q, v = torch.split(self.kqv(x), self.emb, dim=-1)
45
+ kp, qp = self.prm_exp(k), self.prm_exp(q) # (B, T, m), (B, T, m)
46
+ D = torch.einsum('bti,bi->bt', qp, kp.sum(dim=1)).unsqueeze(dim=2) # (B, T, m) * (B, m) -> (B, T, 1)
47
+ kptv = torch.einsum('bin,bim->bnm', v.float(), kp) # (B, emb, m)
48
+ y = torch.einsum('bti,bni->btn', qp, kptv) / (D.repeat(1, 1, self.emb) + self.epsilon) # (B, T, emb)/Diag
49
+ # skip connection
50
+ y = v + self.dp(self.proj(y)) # same as token_transformer in T2T layer, use v as skip connection
51
+
52
+ return y
53
+
54
+ def forward(self, x):
55
+ x = self.single_attn(self.norm1(x))
56
+ x = x + self.mlp(self.norm2(x))
57
+ return x
CAGE_expression_inference-apvit/apvit_mmcls/models/backbones/modules/vit.py ADDED
@@ -0,0 +1,197 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from torch import nn
3
+ from mmcls.models.vit.layers import DropPath
4
+
5
+
6
+ class Mlp(nn.Module):
7
+ def __init__(self, in_features, hidden_features=None, out_features=None, act_layer=nn.GELU, drop=0.):
8
+ super().__init__()
9
+ out_features = out_features or in_features
10
+ hidden_features = hidden_features or in_features
11
+ self.fc1 = nn.Linear(in_features, hidden_features)
12
+ self.act = act_layer()
13
+ self.fc2 = nn.Linear(hidden_features, out_features)
14
+ self.drop = nn.Dropout(drop)
15
+
16
+ def forward(self, x):
17
+ x = self.fc1(x)
18
+ x = self.act(x)
19
+ x = self.drop(x)
20
+ x = self.fc2(x)
21
+ x = self.drop(x)
22
+ return x
23
+
24
+
25
+ class Attention(nn.Module):
26
+ def __init__(self, dim, num_heads=8, qkv_bias=False, qk_scale=None, attn_drop=0., proj_drop=0.):
27
+ super().__init__()
28
+ self.num_heads = num_heads
29
+ head_dim = dim // num_heads
30
+ # NOTE scale factor was wrong in my original version, can set manually to be compat with prev weights
31
+ self.scale = qk_scale or head_dim ** -0.5
32
+
33
+ self.qkv = nn.Linear(dim, dim * 3, bias=qkv_bias)
34
+ self.attn_drop = nn.Dropout(attn_drop)
35
+ self.proj = nn.Linear(dim, dim)
36
+ self.proj_drop = nn.Dropout(proj_drop)
37
+
38
+ def forward(self, x):
39
+ B, N, C = x.shape
40
+ qkv = self.qkv(x).reshape(B, N, 3, self.num_heads, C // self.num_heads)
41
+
42
+ qkv = qkv.permute(2, 0, 3, 1, 4)
43
+ q, k, v = qkv[0], qkv[1], qkv[2] # make torchscript happy (cannot use tensor as tuple)
44
+
45
+ attn = (q @ k.transpose(-2, -1)) * self.scale # [B, head_num, token_num, token_num]
46
+
47
+ attn = attn.softmax(dim=-1)
48
+ attn = self.attn_drop(attn)
49
+
50
+ x = (attn @ v).transpose(1, 2).reshape(B, N, C)
51
+ x = self.proj(x)
52
+ x = self.proj_drop(x)
53
+ return x
54
+
55
+
56
+ class HeadFusionAttention(nn.Module):
57
+ """
58
+ fuse front head output add current head input as current input
59
+ Origin: head2_output = f(head2_input)
60
+ Fuse: head2_output = f(head1_output + head2_input)
61
+ """
62
+ def __init__(self, dim, num_heads=8, qkv_bias=False, qk_scale=None, attn_drop=0., proj_drop=0.):
63
+ super().__init__()
64
+ self.num_heads = num_heads
65
+ head_dim = dim // num_heads
66
+ # NOTE scale factor was wrong in my original version, can set manually to be compat with prev weights
67
+ self.scale = qk_scale or head_dim ** -0.5
68
+
69
+ # self.qkv = nn.Linear(dim, dim * 3, bias=qkv_bias)
70
+ self.group_number = 4 # 每个group内部并行计算
71
+ self.qkv = nn.ModuleList([nn.Linear(dim//self.group_number, (dim//self.group_number)*3, bias=qkv_bias) for _ in range(self.group_number)])
72
+ self.attn_drop = nn.Dropout(attn_drop)
73
+ self.proj = nn.Linear(dim, dim)
74
+ self.proj_drop = nn.Dropout(proj_drop)
75
+
76
+ def forward(self, x):
77
+ B, N, C = x.shape
78
+ # H = self.num_heads
79
+ # dim = C // self.num_heads
80
+ g = self.group_number
81
+ g_dim = C // self.group_number
82
+ x = x.reshape((B, N, g, g_dim))
83
+
84
+ outputs = []
85
+ head_x = torch.zeros((B, N, g_dim), device=x.device)
86
+ for i in range(g):
87
+ # self-attention
88
+ current_x = x[:, :, i]
89
+ current_x = current_x + head_x
90
+ qkv = self.qkv[i](current_x).reshape(B, N, 3, g_dim)
91
+ qkv = qkv.permute(2, 0, 1, 3) # [3, B, N, dim]
92
+ q, k, v = qkv[0], qkv[1], qkv[2]
93
+ attn = (q @ k.transpose(-2, -1)) * self.scale # [B, N, N]
94
+ attn = attn.softmax(dim=-1)
95
+ attn = self.attn_drop(attn)
96
+ head_x = (attn @ v) # [B, N, d]
97
+ outputs.append(head_x)
98
+ x = torch.cat(outputs, dim=-1)
99
+
100
+ x = self.proj(x)
101
+ x = self.proj_drop(x)
102
+ return x
103
+
104
+
105
+ class HeadFusionAttentionV2(nn.Module):
106
+ """
107
+ V2: one branch is origin, onther is modified
108
+ fuse front head output add current head input as current input
109
+ Origin: head2_output = f(head2_input)
110
+ Fuse: head2_output = f(head1_output + head2_input)
111
+ """
112
+ def __init__(self, dim, num_heads=8, qkv_bias=False, qk_scale=None, attn_drop=0., proj_drop=0.):
113
+ super().__init__()
114
+ self.num_heads = num_heads
115
+ head_dim = dim // num_heads
116
+ # NOTE scale factor was wrong in my original version, can set manually to be compat with prev weights
117
+ self.scale = qk_scale or head_dim ** -0.5
118
+
119
+ # self.qkv = nn.Linear(dim, dim * 3, bias=qkv_bias)
120
+ self.group_number = 2 # 每个group内部并行计算.
121
+ self.qkv = nn.Linear(dim, dim * 3, bias=qkv_bias)
122
+ self.qkv2 = nn.ModuleList([nn.Linear(dim//self.group_number, (dim//self.group_number)*3, bias=qkv_bias) for _ in range(self.group_number)])
123
+ self.attn_drop = nn.Dropout(attn_drop)
124
+ self.proj = nn.Linear(dim, dim)
125
+ self.proj_drop = nn.Dropout(proj_drop)
126
+
127
+ def forward(self, x):
128
+ # original
129
+ B, N, C = x.shape
130
+ qkv = self.qkv(x).reshape(B, N, 3, self.num_heads, C // self.num_heads)
131
+
132
+ qkv = qkv.permute(2, 0, 3, 1, 4)
133
+ q, k, v = qkv[0], qkv[1], qkv[2] # make torchscript happy (cannot use tensor as tuple)
134
+
135
+ attn = (q @ k.transpose(-2, -1)) * self.scale # [B, head_num, token_num, token_num]
136
+
137
+ attn = attn.softmax(dim=-1)
138
+ attn = self.attn_drop(attn)
139
+
140
+ origin = (attn @ v) # [B, H, N, dim]
141
+
142
+ # modify
143
+ g = self.group_number
144
+ g_dim = C // self.group_number
145
+ x = x.reshape((B, N, g, g_dim))
146
+ n = self.num_heads // g # head number per group
147
+
148
+ origin = origin.transpose(1, 2).reshape((B, N, g, g_dim))
149
+
150
+ outputs = []
151
+ head_x = torch.zeros((B, N, g_dim), device=x.device)
152
+ for i in range(g):
153
+ # self-attention
154
+ current_x = x[:, :, i]
155
+ current_x = current_x + head_x
156
+ qkv = self.qkv2[i](current_x).reshape(B, N, 3, g_dim)
157
+ qkv = qkv.permute(2, 0, 1, 3) # [3, B, N, dim]
158
+ q, k, v = qkv[0], qkv[1], qkv[2]
159
+ attn = (q @ k.transpose(-2, -1)) * self.scale # [B, N, N]
160
+ attn = attn.softmax(dim=-1)
161
+ attn = self.attn_drop(attn)
162
+ head_x = (attn @ v) # [B, N, d]
163
+ outputs.append(head_x + origin[:, :, i])
164
+ x = torch.cat(outputs, dim=-1)
165
+
166
+ x = self.proj(x)
167
+ x = self.proj_drop(x)
168
+ return x
169
+
170
+
171
+
172
+
173
+
174
+ class Block(nn.Module):
175
+ def __init__(self, dim, num_heads, mlp_ratio=4., qkv_bias=False, qk_scale=None, drop=0., attn_drop=0.,
176
+ drop_path=0., act_layer=nn.GELU, norm_layer=nn.LayerNorm, head_fusion=False,
177
+ ):
178
+ super().__init__()
179
+ self.norm1 = norm_layer(dim)
180
+ if head_fusion:
181
+ self.attn = HeadFusionAttentionV2(
182
+ dim, num_heads=num_heads, qkv_bias=qkv_bias, qk_scale=qk_scale, attn_drop=attn_drop, proj_drop=drop)
183
+ else:
184
+ self.attn = Attention(
185
+ dim, num_heads=num_heads, qkv_bias=qkv_bias, qk_scale=qk_scale, attn_drop=attn_drop, proj_drop=drop)
186
+ # NOTE: drop path for stochastic depth, we shall see if this is better than dropout here
187
+ self.drop_path = DropPath(drop_path) if drop_path > 0. else nn.Identity()
188
+ self.norm2 = norm_layer(dim)
189
+ mlp_hidden_dim = int(dim * mlp_ratio)
190
+ self.mlp = Mlp(in_features=dim, hidden_features=mlp_hidden_dim, act_layer=act_layer, drop=drop)
191
+
192
+ def forward(self, x):
193
+ feature = self.attn(self.norm1(x))
194
+ x = x + self.drop_path(feature)
195
+ x = x + self.drop_path(self.mlp(self.norm2(x)))
196
+ return x
197
+
CAGE_expression_inference-apvit/apvit_mmcls/models/backbones/modules/vit_pooling.py ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from torch import nn
3
+ from .vit import Mlp
4
+ from mmcls.models.utils import top_pool
5
+ from mmcls.models.vit.layers import DropPath
6
+
7
+
8
+ class PoolingAttention(nn.Module):
9
+ def __init__(self, dim, num_heads=8, qkv_bias=False, qk_scale=None, attn_drop=0., proj_drop=0.,
10
+ pool_config=None):
11
+ super().__init__()
12
+ self.num_heads = num_heads
13
+ self.dim = dim
14
+ head_dim = dim // num_heads
15
+ # NOTE scale factor was wrong in my original version, can set manually to be compat with prev weights
16
+ self.scale = qk_scale or head_dim ** -0.5
17
+
18
+ self.qkv = nn.Linear(dim, dim * 3, bias=qkv_bias)
19
+ self.attn_drop = nn.Dropout(attn_drop)
20
+ self.proj = nn.Linear(dim, dim)
21
+ self.proj_drop = nn.Dropout(proj_drop)
22
+ self.pool_config = pool_config
23
+
24
+
25
+ def forward(self, x):
26
+ B, N, C = x.shape
27
+ qkv = self.qkv(x).reshape(B, N, 3, self.num_heads, C // self.num_heads)
28
+ qkv = qkv.permute(2, 0, 3, 1, 4)
29
+ q, k, v = qkv[0], qkv[1], qkv[2] # make torchscript happy (cannot use tensor as tuple)
30
+
31
+ attn = (q @ k.transpose(-2, -1)) * self.scale # [B, head_num, token_num, token_num]
32
+
33
+ if self.pool_config:
34
+ attn_method = self.pool_config.get('attn_method')
35
+ if attn_method == 'SUM_ABS_1':
36
+ attn_weight = attn[:, :, 0, :].transpose(-1, -2) # [B, token_num, head_num]
37
+ attn_weight = torch.sum(torch.abs(attn_weight), dim=-1).unsqueeze(-1)
38
+ elif attn_method == 'SUM':
39
+ attn_weight = attn[:, :, 0, :].transpose(-1, -2) # [B, token_num, head_num]
40
+ attn_weight = torch.sum(attn_weight, dim=-1).unsqueeze(-1)
41
+ elif attn_method == 'MAX':
42
+ attn_weight = attn[:, :, 0, :].transpose(-1, -2)
43
+ attn_weight = torch.max(attn_weight, dim=-1)[0].unsqueeze(-1)
44
+ else:
45
+ raise ValueError('Invalid attn_method: %s' % attn_method)
46
+
47
+ # attn_weight = torch.rand(attn_weight.shape, device=attn_weight.device)
48
+ keep_index = top_pool(attn_weight, dim=self.dim, **self.pool_config)
49
+ else:
50
+ keep_index = None
51
+
52
+ attn = attn.softmax(dim=-1)
53
+ attn = self.attn_drop(attn)
54
+
55
+ x = (attn @ v).transpose(1, 2).reshape(B, N, C)
56
+ x = self.proj(x)
57
+ x = self.proj_drop(x)
58
+ return x, keep_index
59
+
60
+
61
+ class PoolingBlock(nn.Module):
62
+
63
+ def __init__(self, dim=0, num_heads=0, mlp_ratio=4., qkv_bias=False, qk_scale=None, drop=0., attn_drop=0.,
64
+ drop_path=0., act_layer=nn.GELU, norm_layer=nn.LayerNorm, pool_config=None, **kwargs):
65
+ super().__init__()
66
+ self.norm1 = norm_layer(dim)
67
+ self.attn = PoolingAttention(
68
+ dim, num_heads=num_heads, qkv_bias=qkv_bias, qk_scale=qk_scale, attn_drop=attn_drop, proj_drop=drop,
69
+ pool_config=pool_config)
70
+ # NOTE: drop path for stochastic depth, we shall see if this is better than dropout here
71
+ self.drop_path = DropPath(drop_path) if drop_path > 0. else nn.Identity()
72
+ self.norm2 = norm_layer(dim)
73
+ mlp_hidden_dim = int(dim * mlp_ratio)
74
+ self.mlp = Mlp(in_features=dim, hidden_features=mlp_hidden_dim, act_layer=act_layer, drop=drop)
75
+
76
+ def forward(self, x):
77
+ feature, keep_index = self.attn(self.norm1(x))
78
+ x = x + self.drop_path(feature)
79
+ if keep_index is not None:
80
+ if len(keep_index) != x.shape[1]:
81
+ x = x.gather(dim=1, index=keep_index)
82
+ # pooled_x = []
83
+ # for i in range(keep_index.shape[0]):
84
+ # pooled_x.append(x[i, keep_index[i, :, 0]])
85
+ # x = torch.stack(pooled_x)
86
+ # assert torch.all(torch.eq(quick_x, x))
87
+
88
+ x = x + self.drop_path(self.mlp(self.norm2(x)))
89
+ return x