TomLEE2026 commited on
Commit
0bfcee2
·
verified ·
1 Parent(s): 7f53726

Upload 200 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. code/.DS_Store +0 -0
  2. code/configs/base/dataloader.yml +39 -0
  3. code/configs/base/deim.yml +48 -0
  4. code/configs/base/dfine_hgnetv2.yml +90 -0
  5. code/configs/base/optimizer.yml +35 -0
  6. code/configs/base/rt_deim.yml +49 -0
  7. code/configs/base/rt_optimizer.yml +37 -0
  8. code/configs/base/rtdetrv2_r50vd.yml +90 -0
  9. code/configs/dataset/coco_detection.yml +41 -0
  10. code/configs/dataset/crowdhuman_detection.yml +41 -0
  11. code/configs/dataset/custom_detection.yml +41 -0
  12. code/configs/dataset/obj365_detection.yml +41 -0
  13. code/configs/dataset/voc_detection.yml +40 -0
  14. code/configs/deim_dfine/deim_hgnetv2_l_coco.yml +37 -0
  15. code/configs/deim_dfine/deim_hgnetv2_m_coco.yml +39 -0
  16. code/configs/deim_dfine/deim_hgnetv2_n_coco.yml +44 -0
  17. code/configs/deim_dfine/deim_hgnetv2_s_coco.yml +39 -0
  18. code/configs/deim_dfine/deim_hgnetv2_x_coco.yml +37 -0
  19. code/configs/deim_dfine/dfine_hgnetv2_l_coco.yml +44 -0
  20. code/configs/deim_dfine/dfine_hgnetv2_m_coco.yml +60 -0
  21. code/configs/deim_dfine/dfine_hgnetv2_n_coco.yml +82 -0
  22. code/configs/deim_dfine/dfine_hgnetv2_s_coco.yml +61 -0
  23. code/configs/deim_dfine/dfine_hgnetv2_x_coco.yml +56 -0
  24. code/configs/deim_dfine/object365/deim_hgnetv2_x_obj2coco_24e.yml +50 -0
  25. code/configs/deim_dfine/object365/dfine_hgnetv2_x_obj2coco.yml +57 -0
  26. code/configs/deim_rtdetrv2/deim_r101vd_60e_coco.yml +36 -0
  27. code/configs/deim_rtdetrv2/deim_r18vd_120e_coco.yml +32 -0
  28. code/configs/deim_rtdetrv2/deim_r34vd_120e_coco.yml +36 -0
  29. code/configs/deim_rtdetrv2/deim_r50vd_60e_coco.yml +35 -0
  30. code/configs/deim_rtdetrv2/deim_r50vd_m_60e_coco.yml +39 -0
  31. code/configs/deim_rtdetrv2/rtdetrv2_r101vd_6x_coco.yml +40 -0
  32. code/configs/deim_rtdetrv2/rtdetrv2_r18vd_120e_coco.yml +44 -0
  33. code/configs/deim_rtdetrv2/rtdetrv2_r34vd_120e_coco.yml +57 -0
  34. code/configs/deim_rtdetrv2/rtdetrv2_r50vd_6x_coco.yml +25 -0
  35. code/configs/deim_rtdetrv2/rtdetrv2_r50vd_m_7x_coco.yml +43 -0
  36. code/configs/runtime.yml +20 -0
  37. code/engine/__init__.py +16 -0
  38. code/engine/backbone/__init__.py +20 -0
  39. code/engine/backbone/common.py +116 -0
  40. code/engine/backbone/csp_darknet.py +179 -0
  41. code/engine/backbone/csp_resnet.py +277 -0
  42. code/engine/backbone/hgnetv2.py +543 -0
  43. code/engine/backbone/presnet.py +259 -0
  44. code/engine/backbone/test_resnet.py +80 -0
  45. code/engine/backbone/timm_model.py +69 -0
  46. code/engine/backbone/torchvision_model.py +49 -0
  47. code/engine/backbone/utils.py +54 -0
  48. code/engine/core/__init__.py +9 -0
  49. code/engine/core/_config.py +299 -0
  50. code/engine/core/workspace.py +180 -0
code/.DS_Store ADDED
Binary file (6.15 kB). View file
 
code/configs/base/dataloader.yml ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ train_dataloader:
3
+ dataset:
4
+ transforms:
5
+ ops:
6
+ - {type: RandomPhotometricDistort, p: 0.5}
7
+ - {type: RandomZoomOut, fill: 0}
8
+ - {type: RandomIoUCrop, p: 0.8}
9
+ - {type: SanitizeBoundingBoxes, min_size: 1}
10
+ - {type: RandomHorizontalFlip}
11
+ - {type: Resize, size: [640, 640], }
12
+ - {type: SanitizeBoundingBoxes, min_size: 1}
13
+ - {type: ConvertPILImage, dtype: 'float32', scale: True}
14
+ - {type: ConvertBoxes, fmt: 'cxcywh', normalize: True}
15
+ policy:
16
+ name: stop_epoch
17
+ epoch: 72 # epoch in [71, ~) stop `ops`
18
+ ops: ['Mosaic', 'RandomPhotometricDistort', 'RandomZoomOut', 'RandomIoUCrop']
19
+
20
+ collate_fn:
21
+ type: BatchImageCollateFunction
22
+ base_size: 640
23
+ base_size_repeat: 3
24
+ stop_epoch: 72 # epoch in [72, ~) stop `multiscales`
25
+
26
+ shuffle: True
27
+ total_batch_size: 32 # total batch size equals to 32 (4 * 8)
28
+ num_workers: 4
29
+
30
+
31
+ val_dataloader:
32
+ dataset:
33
+ transforms:
34
+ ops:
35
+ - {type: Resize, size: [640, 640], }
36
+ - {type: ConvertPILImage, dtype: 'float32', scale: True}
37
+ shuffle: False
38
+ total_batch_size: 64
39
+ num_workers: 4
code/configs/base/deim.yml ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Dense O2O
2
+ train_dataloader:
3
+ dataset:
4
+ transforms:
5
+ ops:
6
+ - {type: Mosaic, output_size: 320, rotation_range: 10, translation_range: [0.1, 0.1], scaling_range: [0.5, 1.5],
7
+ probability: 1.0, fill_value: 0, use_cache: False, max_cached_images: 50, random_pop: True}
8
+ - {type: RandomPhotometricDistort, p: 0.5}
9
+ - {type: RandomZoomOut, fill: 0}
10
+ - {type: RandomIoUCrop, p: 0.8}
11
+ - {type: SanitizeBoundingBoxes, min_size: 1}
12
+ - {type: RandomHorizontalFlip}
13
+ - {type: Resize, size: [640, 640], }
14
+ - {type: SanitizeBoundingBoxes, min_size: 1}
15
+ - {type: ConvertPILImage, dtype: 'float32', scale: True}
16
+ - {type: ConvertBoxes, fmt: 'cxcywh', normalize: True}
17
+ policy:
18
+ epoch: [4, 29, 50] # list
19
+ ops: ['Mosaic', 'RandomPhotometricDistort', 'RandomZoomOut', 'RandomIoUCrop']
20
+ mosaic_prob: 0.5
21
+
22
+ collate_fn:
23
+ mixup_prob: 0.5
24
+ mixup_epochs: [4, 29]
25
+ stop_epoch: 50 # epoch in [72, ~) stop `multiscales`
26
+
27
+ # Unfreezing BN
28
+ HGNetv2:
29
+ freeze_at: -1 # 0 default
30
+ freeze_norm: False # True default
31
+
32
+ # Activation
33
+ DFINETransformer:
34
+ activation: silu
35
+ mlp_act: silu
36
+
37
+ ## Our LR-Scheduler
38
+ lrsheduler: flatcosine
39
+ lr_gamma: 0.5
40
+ warmup_iter: 2000
41
+ flat_epoch: 29 # 4 + epoch // 2, e.g., 40 = 4 + 72 / 2
42
+ no_aug_epoch: 8
43
+
44
+ ## Our Loss
45
+ DEIMCriterion:
46
+ weight_dict: {loss_mal: 1, loss_bbox: 5, loss_giou: 2, loss_fgl: 0.15, loss_ddf: 1.5}
47
+ losses: ['mal', 'boxes', 'local']
48
+ gamma: 1.5
code/configs/base/dfine_hgnetv2.yml ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ task: detection
2
+
3
+ model: DEIM
4
+ criterion: DEIMCriterion
5
+ postprocessor: PostProcessor
6
+
7
+ use_focal_loss: True
8
+ eval_spatial_size: [640, 640] # h w
9
+ checkpoint_freq: 4 # save freq
10
+
11
+ DEIM:
12
+ backbone: HGNetv2
13
+ encoder: HybridEncoder
14
+ decoder: DFINETransformer
15
+
16
+ # Add, default for step lr scheduler
17
+ lrsheduler: flatcosine
18
+ lr_gamma: 1
19
+ warmup_iter: 500
20
+ flat_epoch: 4000000
21
+ no_aug_epoch: 0
22
+
23
+ HGNetv2:
24
+ pretrained: True
25
+ local_model_dir: ../RT-DETR-main/D-FINE/weight/hgnetv2/
26
+
27
+ HybridEncoder:
28
+ in_channels: [512, 1024, 2048]
29
+ feat_strides: [8, 16, 32]
30
+
31
+ # intra
32
+ hidden_dim: 256
33
+ use_encoder_idx: [2]
34
+ num_encoder_layers: 1
35
+ nhead: 8
36
+ dim_feedforward: 1024
37
+ dropout: 0.
38
+ enc_act: 'gelu'
39
+
40
+ # cross
41
+ expansion: 1.0
42
+ depth_mult: 1
43
+ act: 'silu'
44
+
45
+
46
+ DFINETransformer:
47
+ feat_channels: [256, 256, 256]
48
+ feat_strides: [8, 16, 32]
49
+ hidden_dim: 256
50
+ num_levels: 3
51
+
52
+ num_layers: 6
53
+ eval_idx: -1
54
+ num_queries: 300
55
+
56
+ num_denoising: 100
57
+ label_noise_ratio: 0.5
58
+ box_noise_scale: 1.0
59
+
60
+ # NEW
61
+ reg_max: 32
62
+ reg_scale: 4
63
+
64
+ # Auxiliary decoder layers dimension scaling
65
+ # "eg. If num_layers: 6 eval_idx: -4,
66
+ # then layer 3, 4, 5 are auxiliary decoder layers."
67
+ layer_scale: 1 # 2
68
+
69
+
70
+ num_points: [3, 6, 3] # [4, 4, 4] [3, 6, 3]
71
+ cross_attn_method: default # default, discrete
72
+ query_select_method: default # default, agnostic
73
+
74
+
75
+ PostProcessor:
76
+ num_top_queries: 300
77
+
78
+
79
+ DEIMCriterion:
80
+ weight_dict: {loss_vfl: 1, loss_bbox: 5, loss_giou: 2, loss_fgl: 0.15, loss_ddf: 1.5}
81
+ losses: ['vfl', 'boxes', 'local']
82
+ alpha: 0.75
83
+ gamma: 2.0
84
+ reg_max: 32
85
+
86
+ matcher:
87
+ type: HungarianMatcher
88
+ weight_dict: {cost_class: 2, cost_bbox: 5, cost_giou: 2}
89
+ alpha: 0.25
90
+ gamma: 2.0
code/configs/base/optimizer.yml ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ use_amp: True
2
+ use_ema: True
3
+ ema:
4
+ type: ModelEMA
5
+ decay: 0.9999
6
+ warmups: 1000
7
+ start: 0
8
+
9
+ epoches: 72
10
+ clip_max_norm: 0.1
11
+
12
+
13
+ optimizer:
14
+ type: AdamW
15
+ params:
16
+ -
17
+ params: '^(?=.*backbone)(?!.*norm).*$'
18
+ lr: 0.0000125
19
+ -
20
+ params: '^(?=.*(?:encoder|decoder))(?=.*(?:norm|bn)).*$'
21
+ weight_decay: 0.
22
+
23
+ lr: 0.00025
24
+ betas: [0.9, 0.999]
25
+ weight_decay: 0.000125
26
+
27
+
28
+ lr_scheduler:
29
+ type: MultiStepLR
30
+ milestones: [500]
31
+ gamma: 0.1
32
+
33
+ lr_warmup_scheduler:
34
+ type: LinearWarmup
35
+ warmup_duration: 500
code/configs/base/rt_deim.yml ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Dense O2O
2
+ train_dataloader:
3
+ dataset:
4
+ transforms:
5
+ ops:
6
+ - {type: Mosaic, output_size: 320, rotation_range: 10, translation_range: [0.1, 0.1], scaling_range: [0.5, 1.5],
7
+ probability: 1.0, fill_value: 0, use_cache: False, max_cached_images: 50, random_pop: True}
8
+ - {type: RandomPhotometricDistort, p: 0.5}
9
+ - {type: RandomZoomOut, fill: 0}
10
+ - {type: RandomIoUCrop, p: 0.8}
11
+ - {type: SanitizeBoundingBoxes, min_size: 1}
12
+ - {type: RandomHorizontalFlip}
13
+ - {type: Resize, size: [640, 640], }
14
+ - {type: SanitizeBoundingBoxes, min_size: 1}
15
+ - {type: ConvertPILImage, dtype: 'float32', scale: True}
16
+ - {type: ConvertBoxes, fmt: 'cxcywh', normalize: True}
17
+ policy:
18
+ epoch: [4, 29, 50] # list
19
+ ops: ['Mosaic', 'RandomPhotometricDistort', 'RandomZoomOut', 'RandomIoUCrop']
20
+ mosaic_prob: 0.5
21
+
22
+ collate_fn:
23
+ mixup_prob: 0.5
24
+ mixup_epochs: [4, 29]
25
+ stop_epoch: 50 # epoch in [72, ~) stop `multiscales`
26
+
27
+ # Unfreezing BN
28
+ PResNet:
29
+ freeze_at: -1 # default 0
30
+ freeze_norm: False # default True
31
+
32
+ # Activation
33
+ RTDETRTransformerv2:
34
+ query_pos_method: as_reg
35
+ activation: silu
36
+ mlp_act: silu
37
+
38
+ ## Our LR-Scheduler
39
+ lrsheduler: flatcosine
40
+ lr_gamma: 0.5
41
+ warmup_iter: 2000
42
+ flat_epoch: 29 # 4 + epoch // 2, e.g., 40 = 4 + 72 / 2
43
+ no_aug_epoch: 8
44
+
45
+ ## Our Loss
46
+ DEIMCriterion:
47
+ weight_dict: {loss_mal: 1, loss_bbox: 5, loss_giou: 2}
48
+ losses: ['mal', 'boxes', ]
49
+ gamma: 1.5
code/configs/base/rt_optimizer.yml ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ use_amp: True
2
+ use_ema: True
3
+ ema:
4
+ type: ModelEMA
5
+ decay: 0.9999
6
+ warmups: 2000
7
+ start: 0
8
+
9
+ epoches: 72
10
+ clip_max_norm: 0.1
11
+
12
+ train_dataloader:
13
+ total_batch_size: 16
14
+
15
+ optimizer:
16
+ type: AdamW
17
+ params:
18
+ -
19
+ params: '^(?=.*backbone)(?!.*norm).*$'
20
+ lr: 0.00001
21
+ -
22
+ params: '^(?=.*(?:encoder|decoder))(?=.*(?:norm|bn)).*$'
23
+ weight_decay: 0.
24
+
25
+ lr: 0.0001
26
+ betas: [0.9, 0.999]
27
+ weight_decay: 0.0001
28
+
29
+ lr_scheduler:
30
+ type: MultiStepLR
31
+ milestones: [1000]
32
+ gamma: 0.1
33
+
34
+
35
+ lr_warmup_scheduler:
36
+ type: LinearWarmup
37
+ warmup_duration: 2000
code/configs/base/rtdetrv2_r50vd.yml ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ task: detection
2
+
3
+ model: DEIM
4
+ criterion: DEIMCriterion
5
+ postprocessor: PostProcessor
6
+
7
+ use_focal_loss: True
8
+ eval_spatial_size: [640, 640] # h w
9
+ checkpoint_freq: 4 # save freq
10
+
11
+ DEIM:
12
+ backbone: PResNet
13
+ encoder: HybridEncoder
14
+ decoder: RTDETRTransformerv2
15
+
16
+
17
+ # Add, default for step lr scheduler
18
+ lrsheduler: flatcosine
19
+ lr_gamma: 1
20
+ warmup_iter: 2000
21
+ flat_epoch: 4000000
22
+ no_aug_epoch: 0
23
+
24
+ PResNet:
25
+ depth: 50
26
+ variant: d
27
+ freeze_at: 0
28
+ return_idx: [1, 2, 3]
29
+ num_stages: 4
30
+ freeze_norm: True
31
+ pretrained: True
32
+ local_model_dir: ../RT-DETR-main/rtdetrv2_pytorch/INK1k/
33
+
34
+
35
+ HybridEncoder:
36
+ in_channels: [512, 1024, 2048]
37
+ feat_strides: [8, 16, 32]
38
+
39
+ # intra
40
+ hidden_dim: 256
41
+ use_encoder_idx: [2]
42
+ num_encoder_layers: 1
43
+ nhead: 8
44
+ dim_feedforward: 1024
45
+ dropout: 0.
46
+ enc_act: 'gelu'
47
+
48
+ # cross
49
+ expansion: 1.0
50
+ depth_mult: 1
51
+ act: 'silu'
52
+ version: rt_detrv2 # pay attention to this
53
+
54
+
55
+ RTDETRTransformerv2:
56
+ feat_channels: [256, 256, 256]
57
+ feat_strides: [8, 16, 32]
58
+ hidden_dim: 256
59
+ num_levels: 3
60
+
61
+ num_layers: 6
62
+ num_queries: 300
63
+
64
+ num_denoising: 100
65
+ label_noise_ratio: 0.5
66
+ box_noise_scale: 1.0 # 1.0 0.4
67
+
68
+ eval_idx: -1
69
+
70
+ # NEW, can be chosen
71
+ num_points: [4, 4, 4] # [3,3,3] [2,2,2]
72
+ cross_attn_method: default # default, discrete
73
+ query_select_method: default # default, agnostic
74
+
75
+
76
+ PostProcessor:
77
+ num_top_queries: 300
78
+
79
+ DEIMCriterion:
80
+ weight_dict: {loss_vfl: 1, loss_bbox: 5, loss_giou: 2,}
81
+ losses: ['vfl', 'boxes', ]
82
+ alpha: 0.75
83
+ gamma: 2.0
84
+ use_uni_set: False
85
+
86
+ matcher:
87
+ type: HungarianMatcher
88
+ weight_dict: {cost_class: 2, cost_bbox: 5, cost_giou: 2}
89
+ alpha: 0.25
90
+ gamma: 2.0
code/configs/dataset/coco_detection.yml ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ task: detection
2
+
3
+ evaluator:
4
+ type: CocoEvaluator
5
+ iou_types: ['bbox', ]
6
+
7
+ num_classes: 80
8
+ remap_mscoco_category: True
9
+
10
+ train_dataloader:
11
+ type: DataLoader
12
+ dataset:
13
+ type: CocoDetection
14
+ img_folder: /datassd/COCO/train2017/
15
+ ann_file: /datassd/COCO/annotations/instances_train2017.json
16
+ return_masks: False
17
+ transforms:
18
+ type: Compose
19
+ ops: ~
20
+ shuffle: True
21
+ num_workers: 4
22
+ drop_last: True
23
+ collate_fn:
24
+ type: BatchImageCollateFunction
25
+
26
+
27
+ val_dataloader:
28
+ type: DataLoader
29
+ dataset:
30
+ type: CocoDetection
31
+ img_folder: /datassd/COCO/val2017/
32
+ ann_file: /datassd/COCO/annotations/instances_val2017.json
33
+ return_masks: False
34
+ transforms:
35
+ type: Compose
36
+ ops: ~
37
+ shuffle: False
38
+ num_workers: 4
39
+ drop_last: False
40
+ collate_fn:
41
+ type: BatchImageCollateFunction
code/configs/dataset/crowdhuman_detection.yml ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ task: detection
2
+
3
+ evaluator:
4
+ type: CocoEvaluator
5
+ iou_types: ['bbox', ]
6
+
7
+ num_classes: 2 # your dataset classes
8
+ remap_mscoco_category: False
9
+
10
+ train_dataloader:
11
+ type: DataLoader
12
+ dataset:
13
+ type: CocoDetection
14
+ img_folder: /datassd/coco/crowd_human_coco/CrowdHuman_train
15
+ ann_file: /datassd/coco/crowd_human_coco/Chuman-train.json
16
+ return_masks: False
17
+ transforms:
18
+ type: Compose
19
+ ops: ~
20
+ shuffle: True
21
+ num_workers: 4
22
+ drop_last: True
23
+ collate_fn:
24
+ type: BatchImageCollateFunction
25
+
26
+
27
+ val_dataloader:
28
+ type: DataLoader
29
+ dataset:
30
+ type: CocoDetection
31
+ img_folder: /datassd/coco/crowd_human_coco/CrowdHuman_val
32
+ ann_file: /datassd/coco/crowd_human_coco/Chuman-val.json
33
+ return_masks: False
34
+ transforms:
35
+ type: Compose
36
+ ops: ~
37
+ shuffle: False
38
+ num_workers: 4
39
+ drop_last: False
40
+ collate_fn:
41
+ type: BatchImageCollateFunction
code/configs/dataset/custom_detection.yml ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ task: detection
2
+
3
+ evaluator:
4
+ type: CocoEvaluator
5
+ iou_types: ['bbox', ]
6
+
7
+ num_classes: 777 # your dataset classes
8
+ remap_mscoco_category: False
9
+
10
+ train_dataloader:
11
+ type: DataLoader
12
+ dataset:
13
+ type: CocoDetection
14
+ img_folder: /data/yourdataset/train
15
+ ann_file: /data/yourdataset/train/train.json
16
+ return_masks: False
17
+ transforms:
18
+ type: Compose
19
+ ops: ~
20
+ shuffle: True
21
+ num_workers: 4
22
+ drop_last: True
23
+ collate_fn:
24
+ type: BatchImageCollateFunction
25
+
26
+
27
+ val_dataloader:
28
+ type: DataLoader
29
+ dataset:
30
+ type: CocoDetection
31
+ img_folder: /data/yourdataset/val
32
+ ann_file: /data/yourdataset/val/val.json
33
+ return_masks: False
34
+ transforms:
35
+ type: Compose
36
+ ops: ~
37
+ shuffle: False
38
+ num_workers: 4
39
+ drop_last: False
40
+ collate_fn:
41
+ type: BatchImageCollateFunction
code/configs/dataset/obj365_detection.yml ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ task: detection
2
+
3
+ evaluator:
4
+ type: CocoEvaluator
5
+ iou_types: ['bbox', ]
6
+
7
+ num_classes: 366
8
+ remap_mscoco_category: False
9
+
10
+ train_dataloader:
11
+ type: DataLoader
12
+ dataset:
13
+ type: CocoDetection
14
+ img_folder: /home/Dataset/objects365/train
15
+ ann_file: /home/Dataset/objects365/train/new_zhiyuan_objv2_train_resized640.json
16
+ return_masks: False
17
+ transforms:
18
+ type: Compose
19
+ ops: ~
20
+ shuffle: True
21
+ num_workers: 4
22
+ drop_last: True
23
+ collate_fn:
24
+ type: BatchImageCollateFunction
25
+
26
+
27
+ val_dataloader:
28
+ type: DataLoader
29
+ dataset:
30
+ type: CocoDetection
31
+ img_folder: /home/Dataset/objects365/val
32
+ ann_file: /home/Dataset/objects365/val/new_zhiyuan_objv2_val_resized640.json
33
+ return_masks: False
34
+ transforms:
35
+ type: Compose
36
+ ops: ~
37
+ shuffle: False
38
+ num_workers: 4
39
+ drop_last: False
40
+ collate_fn:
41
+ type: BatchImageCollateFunction
code/configs/dataset/voc_detection.yml ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ task: detection
2
+
3
+ evaluator:
4
+ type: CocoEvaluator
5
+ iou_types: ['bbox', ]
6
+
7
+ num_classes: 20
8
+
9
+ train_dataloader:
10
+ type: DataLoader
11
+ dataset:
12
+ type: VOCDetection
13
+ root: ./dataset/voc/
14
+ ann_file: trainval.txt
15
+ label_file: label_list.txt
16
+ transforms:
17
+ type: Compose
18
+ ops: ~
19
+ shuffle: True
20
+ num_workers: 4
21
+ drop_last: True
22
+ collate_fn:
23
+ type: BatchImageCollateFunction
24
+
25
+
26
+ val_dataloader:
27
+ type: DataLoader
28
+ dataset:
29
+ type: VOCDetection
30
+ root: ./dataset/voc/
31
+ ann_file: test.txt
32
+ label_file: label_list.txt
33
+ transforms:
34
+ type: Compose
35
+ ops: ~
36
+ shuffle: False
37
+ num_workers: 4
38
+ drop_last: False
39
+ collate_fn:
40
+ type: BatchImageCollateFunction
code/configs/deim_dfine/deim_hgnetv2_l_coco.yml ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ __include__: [
2
+ './dfine_hgnetv2_l_coco.yml',
3
+ '../base/deim.yml'
4
+ ]
5
+
6
+ output_dir: ./outputs/deim_hgnetv2_l_coco
7
+
8
+ optimizer:
9
+ type: AdamW
10
+ params:
11
+ -
12
+ params: '^(?=.*backbone)(?!.*norm|bn).*$'
13
+ lr: 0.000025
14
+ -
15
+ params: '^(?=.*(?:encoder|decoder))(?=.*(?:norm|bn)).*$'
16
+ weight_decay: 0.
17
+
18
+ lr: 0.0005
19
+ betas: [0.9, 0.999]
20
+ weight_decay: 0.000125
21
+
22
+ # Increase to search for the optimal ema
23
+ epoches: 58 # 72 + 2n
24
+
25
+ ## Our LR-Scheduler
26
+ flat_epoch: 29 # 4 + epoch // 2, e.g., 40 = 4 + 72 / 2
27
+ no_aug_epoch: 8
28
+
29
+ train_dataloader:
30
+ dataset:
31
+ transforms:
32
+ policy:
33
+ epoch: [4, 29, 50] # list
34
+
35
+ collate_fn:
36
+ mixup_epochs: [4, 29]
37
+ stop_epoch: 50
code/configs/deim_dfine/deim_hgnetv2_m_coco.yml ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ __include__: [
2
+ './dfine_hgnetv2_m_coco.yml',
3
+ '../base/deim.yml'
4
+ ]
5
+
6
+ output_dir: ./outputs/deim_hgnetv2_m_coco
7
+
8
+ optimizer:
9
+ type: AdamW
10
+ params:
11
+ -
12
+ params: '^(?=.*backbone)(?!.*bn).*$'
13
+ lr: 0.00004
14
+ -
15
+ params: '^(?=.*(?:norm|bn)).*$'
16
+ weight_decay: 0.
17
+
18
+ lr: 0.0004
19
+ betas: [0.9, 0.999]
20
+ weight_decay: 0.0001
21
+
22
+
23
+ # Increase to search for the optimal ema
24
+ epoches: 102 # 120 + 4n
25
+
26
+ ## Our LR-Scheduler
27
+ flat_epoch: 49 # 4 + epoch // 2, e.g., 40 = 4 + 72 / 2
28
+ no_aug_epoch: 12
29
+
30
+ ## Our DataAug
31
+ train_dataloader:
32
+ dataset:
33
+ transforms:
34
+ policy:
35
+ epoch: [4, 49, 90] # list
36
+
37
+ collate_fn:
38
+ mixup_epochs: [4, 49]
39
+ stop_epoch: 90
code/configs/deim_dfine/deim_hgnetv2_n_coco.yml ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ __include__: [
2
+ './dfine_hgnetv2_n_coco.yml',
3
+ '../base/deim.yml'
4
+ ]
5
+
6
+ output_dir: ./deim_outputs/deim_hgnetv2_n_coco
7
+
8
+ optimizer:
9
+ type: AdamW
10
+ params:
11
+ -
12
+ params: '^(?=.*backbone)(?!.*norm|bn).*$'
13
+ lr: 0.0004
14
+ -
15
+ params: '^(?=.*backbone)(?=.*norm|bn).*$'
16
+ lr: 0.0004
17
+ weight_decay: 0.
18
+ -
19
+ params: '^(?=.*(?:encoder|decoder))(?=.*(?:norm|bn|bias)).*$'
20
+ weight_decay: 0.
21
+
22
+ lr: 0.0008
23
+ betas: [0.9, 0.999]
24
+ weight_decay: 0.0001
25
+
26
+ # Increase to search for the optimal ema
27
+ epoches: 160 # 148 + 12
28
+
29
+ ## Our LR-Scheduler
30
+ flat_epoch: 7800 # 4 + epoch // 2, e.g., 40 = 4 + 72 / 2
31
+ no_aug_epoch: 12
32
+ lr_gamma: 1.0
33
+
34
+ ## Our DataAug
35
+ train_dataloader:
36
+ dataset:
37
+ transforms:
38
+ policy:
39
+ epoch: [4, 78, 148] # list
40
+
41
+ collate_fn:
42
+ mixup_epochs: [4, 78]
43
+ stop_epoch: 148
44
+ base_size_repeat: ~
code/configs/deim_dfine/deim_hgnetv2_s_coco.yml ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ __include__: [
2
+ './dfine_hgnetv2_s_coco.yml',
3
+ '../base/deim.yml'
4
+ ]
5
+
6
+ output_dir: ./outputs/deim_hgnetv2_s_coco
7
+
8
+ optimizer:
9
+ type: AdamW
10
+ params:
11
+ -
12
+ params: '^(?=.*backbone)(?!.*bn).*$'
13
+ lr: 0.0002
14
+ -
15
+ params: '^(?=.*(?:norm|bn)).*$' # except bias
16
+ weight_decay: 0.
17
+
18
+ lr: 0.0004
19
+ betas: [0.9, 0.999]
20
+ weight_decay: 0.0001
21
+
22
+
23
+ # Increase to search for the optimal ema
24
+ epoches: 132 # 120 + 4n
25
+
26
+ ## Our LR-Scheduler
27
+ flat_epoch: 64 # 4 + epoch // 2, e.g., 40 = 4 + 72 / 2
28
+ no_aug_epoch: 12
29
+
30
+ ## Our DataAug
31
+ train_dataloader:
32
+ dataset:
33
+ transforms:
34
+ policy:
35
+ epoch: [4, 64, 120] # list
36
+
37
+ collate_fn:
38
+ mixup_epochs: [4, 64]
39
+ stop_epoch: 120
code/configs/deim_dfine/deim_hgnetv2_x_coco.yml ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ __include__: [
2
+ './dfine_hgnetv2_x_coco.yml',
3
+ '../base/deim.yml'
4
+ ]
5
+
6
+ output_dir: ./outputs/deim_hgnetv2_x_coco
7
+
8
+ optimizer:
9
+ type: AdamW
10
+ params:
11
+ -
12
+ params: '^(?=.*backbone)(?!.*norm|bn).*$'
13
+ lr: 0.000005
14
+ -
15
+ params: '^(?=.*(?:encoder|decoder))(?=.*(?:norm|bn)).*$'
16
+ weight_decay: 0.
17
+
18
+ lr: 0.0005
19
+ betas: [0.9, 0.999]
20
+ weight_decay: 0.000125
21
+
22
+ # Increase to search for the optimal ema
23
+ epoches: 58 # 72 + 2n
24
+
25
+ ## Our LR-Scheduler
26
+ flat_epoch: 29 # 4 + epoch // 2, e.g., 40 = 4 + 72 / 2
27
+ no_aug_epoch: 8
28
+
29
+ train_dataloader:
30
+ dataset:
31
+ transforms:
32
+ policy:
33
+ epoch: [4, 29, 50] # list
34
+
35
+ collate_fn:
36
+ mixup_epochs: [4, 29]
37
+ stop_epoch: 50
code/configs/deim_dfine/dfine_hgnetv2_l_coco.yml ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ __include__: [
2
+ '../dataset/coco_detection.yml',
3
+ '../runtime.yml',
4
+ '../base/dataloader.yml',
5
+ '../base/optimizer.yml',
6
+ '../base/dfine_hgnetv2.yml',
7
+ ]
8
+
9
+ output_dir: ./outputs/dfine_hgnetv2_l_coco
10
+
11
+
12
+ HGNetv2:
13
+ name: 'B4'
14
+ return_idx: [1, 2, 3]
15
+ freeze_stem_only: True
16
+ freeze_at: 0
17
+ freeze_norm: True
18
+
19
+ optimizer:
20
+ type: AdamW
21
+ params:
22
+ -
23
+ params: '^(?=.*backbone)(?!.*norm|bn).*$'
24
+ lr: 0.0000125
25
+ -
26
+ params: '^(?=.*(?:encoder|decoder))(?=.*(?:norm|bn)).*$'
27
+ weight_decay: 0.
28
+
29
+ lr: 0.00025
30
+ betas: [0.9, 0.999]
31
+ weight_decay: 0.000125
32
+
33
+
34
+ # Increase to search for the optimal ema
35
+ epoches: 80 # 72 + 2n
36
+ train_dataloader:
37
+ dataset:
38
+ transforms:
39
+ policy:
40
+ epoch: 72
41
+ collate_fn:
42
+ stop_epoch: 72
43
+ ema_restart_decay: 0.9999
44
+ base_size_repeat: 4
code/configs/deim_dfine/dfine_hgnetv2_m_coco.yml ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ __include__: [
2
+ '../dataset/coco_detection.yml',
3
+ '../runtime.yml',
4
+ '../base/dataloader.yml',
5
+ '../base/optimizer.yml',
6
+ '../base/dfine_hgnetv2.yml',
7
+ ]
8
+
9
+ output_dir: ./output/dfine_hgnetv2_m_coco
10
+
11
+
12
+ DEIM:
13
+ backbone: HGNetv2
14
+
15
+ HGNetv2:
16
+ name: 'B2'
17
+ return_idx: [1, 2, 3]
18
+ freeze_at: -1
19
+ freeze_norm: False
20
+ use_lab: True
21
+
22
+ DFINETransformer:
23
+ num_layers: 4 # 5 6
24
+ eval_idx: -1 # -2 -3
25
+
26
+ HybridEncoder:
27
+ in_channels: [384, 768, 1536]
28
+ hidden_dim: 256
29
+ depth_mult: 0.67
30
+
31
+ optimizer:
32
+ type: AdamW
33
+ params:
34
+ -
35
+ params: '^(?=.*backbone)(?!.*norm|bn).*$'
36
+ lr: 0.00002
37
+ -
38
+ params: '^(?=.*backbone)(?=.*norm|bn).*$'
39
+ lr: 0.00002
40
+ weight_decay: 0.
41
+ -
42
+ params: '^(?=.*(?:encoder|decoder))(?=.*(?:norm|bn|bias)).*$'
43
+ weight_decay: 0.
44
+
45
+ lr: 0.0002
46
+ betas: [0.9, 0.999]
47
+ weight_decay: 0.0001
48
+
49
+
50
+ # Increase to search for the optimal ema
51
+ epoches: 132 # 120 + 4n
52
+ train_dataloader:
53
+ dataset:
54
+ transforms:
55
+ policy:
56
+ epoch: 120
57
+ collate_fn:
58
+ stop_epoch: 120
59
+ ema_restart_decay: 0.9999
60
+ base_size_repeat: 6
code/configs/deim_dfine/dfine_hgnetv2_n_coco.yml ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ __include__: [
2
+ '../dataset/coco_detection.yml',
3
+ '../runtime.yml',
4
+ '../base/dataloader.yml',
5
+ '../base/optimizer.yml',
6
+ '../base/dfine_hgnetv2.yml',
7
+ ]
8
+
9
+ output_dir: ./output/dfine_hgnetv2_n_coco
10
+
11
+
12
+ DEIM:
13
+ backbone: HGNetv2
14
+
15
+ HGNetv2:
16
+ name: 'B0'
17
+ return_idx: [2, 3]
18
+ freeze_at: -1
19
+ freeze_norm: False
20
+ use_lab: True
21
+
22
+
23
+ HybridEncoder:
24
+ in_channels: [512, 1024]
25
+ feat_strides: [16, 32]
26
+
27
+ # intra
28
+ hidden_dim: 128
29
+ use_encoder_idx: [1]
30
+ dim_feedforward: 512
31
+
32
+ # cross
33
+ expansion: 0.34
34
+ depth_mult: 0.5
35
+
36
+
37
+ DFINETransformer:
38
+ feat_channels: [128, 128]
39
+ feat_strides: [16, 32]
40
+ hidden_dim: 128
41
+ dim_feedforward: 512
42
+ num_levels: 2
43
+
44
+ num_layers: 3
45
+ eval_idx: -1
46
+
47
+ num_points: [6, 6]
48
+
49
+ optimizer:
50
+ type: AdamW
51
+ params:
52
+ -
53
+ params: '^(?=.*backbone)(?!.*norm|bn).*$'
54
+ lr: 0.0004
55
+ -
56
+ params: '^(?=.*backbone)(?=.*norm|bn).*$'
57
+ lr: 0.0004
58
+ weight_decay: 0.
59
+ -
60
+ params: '^(?=.*(?:encoder|decoder))(?=.*(?:norm|bn|bias)).*$'
61
+ weight_decay: 0.
62
+
63
+ lr: 0.0008
64
+ betas: [0.9, 0.999]
65
+ weight_decay: 0.0001
66
+
67
+
68
+ # Increase to search for the optimal ema
69
+ epoches: 160 # 148 + 4n
70
+ train_dataloader:
71
+ total_batch_size: 128
72
+ dataset:
73
+ transforms:
74
+ policy:
75
+ epoch: 148
76
+ collate_fn:
77
+ stop_epoch: 148
78
+ ema_restart_decay: 0.9999
79
+ base_size_repeat: ~
80
+
81
+ val_dataloader:
82
+ total_batch_size: 256
code/configs/deim_dfine/dfine_hgnetv2_s_coco.yml ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ __include__: [
2
+ '../dataset/coco_detection.yml',
3
+ '../runtime.yml',
4
+ '../base/dataloader.yml',
5
+ '../base/optimizer.yml',
6
+ '../base/dfine_hgnetv2.yml',
7
+ ]
8
+
9
+ output_dir: ./output/dfine_hgnetv2_s_coco
10
+
11
+
12
+ DEIM:
13
+ backbone: HGNetv2
14
+
15
+ HGNetv2:
16
+ name: 'B0'
17
+ return_idx: [1, 2, 3]
18
+ freeze_at: -1
19
+ freeze_norm: False
20
+ use_lab: True
21
+
22
+ DFINETransformer:
23
+ num_layers: 3 # 4 5 6
24
+ eval_idx: -1 # -2 -3 -4
25
+
26
+ HybridEncoder:
27
+ in_channels: [256, 512, 1024]
28
+ hidden_dim: 256
29
+ depth_mult: 0.34
30
+ expansion: 0.5
31
+
32
+ optimizer:
33
+ type: AdamW
34
+ params:
35
+ -
36
+ params: '^(?=.*backbone)(?!.*norm|bn).*$'
37
+ lr: 0.0001
38
+ -
39
+ params: '^(?=.*backbone)(?=.*norm|bn).*$'
40
+ lr: 0.0001
41
+ weight_decay: 0.
42
+ -
43
+ params: '^(?=.*(?:encoder|decoder))(?=.*(?:norm|bn|bias)).*$'
44
+ weight_decay: 0.
45
+
46
+ lr: 0.0002
47
+ betas: [0.9, 0.999]
48
+ weight_decay: 0.0001
49
+
50
+
51
+ # Increase to search for the optimal ema
52
+ epoches: 132 # 120 + 4n
53
+ train_dataloader:
54
+ dataset:
55
+ transforms:
56
+ policy:
57
+ epoch: 120
58
+ collate_fn:
59
+ stop_epoch: 120
60
+ ema_restart_decay: 0.9999
61
+ base_size_repeat: 20
code/configs/deim_dfine/dfine_hgnetv2_x_coco.yml ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ __include__: [
2
+ '../dataset/coco_detection.yml',
3
+ '../runtime.yml',
4
+ '../base/dataloader.yml',
5
+ '../base/optimizer.yml',
6
+ '../base/dfine_hgnetv2.yml',
7
+ ]
8
+
9
+ output_dir: ./output/dfine_hgnetv2_x_coco
10
+
11
+
12
+ DEIM:
13
+ backbone: HGNetv2
14
+
15
+ HGNetv2:
16
+ name: 'B5'
17
+ return_idx: [1, 2, 3]
18
+ freeze_stem_only: True
19
+ freeze_at: 0
20
+ freeze_norm: True
21
+
22
+ HybridEncoder:
23
+ # intra
24
+ hidden_dim: 384
25
+ dim_feedforward: 2048
26
+
27
+ DFINETransformer:
28
+ feat_channels: [384, 384, 384]
29
+ reg_scale: 8
30
+
31
+ optimizer:
32
+ type: AdamW
33
+ params:
34
+ -
35
+ params: '^(?=.*backbone)(?!.*norm|bn).*$'
36
+ lr: 0.0000025
37
+ -
38
+ params: '^(?=.*(?:encoder|decoder))(?=.*(?:norm|bn)).*$'
39
+ weight_decay: 0.
40
+
41
+ lr: 0.00025
42
+ betas: [0.9, 0.999]
43
+ weight_decay: 0.000125
44
+
45
+
46
+ # Increase to search for the optimal ema
47
+ epoches: 80 # 72 + 2n
48
+ train_dataloader:
49
+ dataset:
50
+ transforms:
51
+ policy:
52
+ epoch: 72
53
+ collate_fn:
54
+ stop_epoch: 72
55
+ ema_restart_decay: 0.9998
56
+ base_size_repeat: 3
code/configs/deim_dfine/object365/deim_hgnetv2_x_obj2coco_24e.yml ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ __include__: [
2
+ './dfine_hgnetv2_x_obj2coco.yml',
3
+ '../../base/deim.yml'
4
+ ]
5
+
6
+ output_dir: ./deim_outputs/deim_hgnetv2_x_obj2coco_24e
7
+
8
+ HGNetv2:
9
+ freeze_at: 0 # 0 default
10
+ freeze_norm: True # True default
11
+
12
+ # Activation
13
+ DFINETransformer:
14
+ activation: relu
15
+ mlp_act: relu
16
+
17
+ optimizer:
18
+ type: AdamW
19
+ params:
20
+ -
21
+ params: '^(?=.*backbone)(?!.*norm|bn).*$'
22
+ lr: 0.0000025
23
+ -
24
+ params: '^(?=.*(?:encoder|decoder))(?=.*(?:norm|bn)).*$'
25
+ weight_decay: 0.
26
+
27
+ lr: 0.00025
28
+ betas: [0.9, 0.999]
29
+ weight_decay: 0.000125
30
+
31
+ # Increase to search for the optimal ema
32
+ epoches: 24 # 72 + 2n
33
+
34
+ ## Our LR-Scheduler
35
+ lrsheduler: flatcosine
36
+ lr_gamma: 1
37
+ warmup_iter: 0 # 0
38
+ flat_epoch: 12000 # 4 + epoch // 2, e.g., 40 = 4 + 72 / 2
39
+ no_aug_epoch: 4
40
+
41
+ ## Our DataAug
42
+ train_dataloader:
43
+ dataset:
44
+ transforms:
45
+ policy:
46
+ epoch: [2, 12, 20] # list
47
+
48
+ collate_fn:
49
+ mixup_epochs: [2, 12]
50
+ stop_epoch: 20
code/configs/deim_dfine/object365/dfine_hgnetv2_x_obj2coco.yml ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ __include__: [
2
+ '../../dataset/coco_detection.yml',
3
+ '../../runtime.yml',
4
+ '../../base/dataloader.yml',
5
+ '../../base/optimizer.yml',
6
+ '../../base/dfine_hgnetv2.yml',
7
+ ]
8
+
9
+ output_dir: ./outputs/dfine_hgnetv2_x_obj2coco
10
+
11
+ HGNetv2:
12
+ name: 'B5'
13
+ return_idx: [1, 2, 3]
14
+ freeze_stem_only: True
15
+ freeze_at: 0
16
+ freeze_norm: True
17
+
18
+ HybridEncoder:
19
+ # intra
20
+ hidden_dim: 384
21
+ dim_feedforward: 2048
22
+
23
+ DFINETransformer:
24
+ feat_channels: [384, 384, 384]
25
+ reg_scale: 8
26
+
27
+ optimizer:
28
+ type: AdamW
29
+ params:
30
+ -
31
+ params: '^(?=.*backbone)(?!.*norm|bn).*$'
32
+ lr: 0.0000025
33
+ -
34
+ params: '^(?=.*(?:encoder|decoder))(?=.*(?:norm|bn)).*$'
35
+ weight_decay: 0.
36
+
37
+ lr: 0.00025
38
+ betas: [0.9, 0.999]
39
+ weight_decay: 0.000125
40
+
41
+
42
+ epoches: 36 # Early stop
43
+ train_dataloader:
44
+ dataset:
45
+ transforms:
46
+ policy:
47
+ epoch: 30
48
+ collate_fn:
49
+ stop_epoch: 30
50
+ ema_restart_decay: 0.9999
51
+ base_size_repeat: 3
52
+
53
+ ema:
54
+ warmups: 0
55
+
56
+ lr_warmup_scheduler:
57
+ warmup_duration: 0
code/configs/deim_rtdetrv2/deim_r101vd_60e_coco.yml ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ __include__: [
2
+ './rtdetrv2_r101vd_6x_coco.yml',
3
+ '../base/rt_deim.yml',
4
+ ]
5
+
6
+ output_dir: ./outputs/deim_rtdetrv2_r101vd_60e_coco
7
+
8
+ optimizer:
9
+ type: AdamW
10
+ params:
11
+ -
12
+ params: '^(?=.*backbone)(?!.*norm).*$'
13
+ lr: 0.000002
14
+ -
15
+ params: '^(?=.*(?:norm|bn)).*$'
16
+ weight_decay: 0.
17
+
18
+ lr: 0.0002
19
+ betas: [0.9, 0.999]
20
+ weight_decay: 0.0001
21
+
22
+
23
+ # change part
24
+ epoches: 60
25
+ flat_epoch: 34 # 4 + 60 / 2
26
+ no_aug_epoch: 2
27
+
28
+ train_dataloader:
29
+ dataset:
30
+ transforms:
31
+ policy:
32
+ epoch: [4, 34, 58] # list
33
+
34
+ collate_fn:
35
+ mixup_epochs: [4, 34]
36
+ stop_epoch: 58
code/configs/deim_rtdetrv2/deim_r18vd_120e_coco.yml ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ __include__: [
2
+ './rtdetrv2_r18vd_120e_coco.yml',
3
+ '../base/rt_deim.yml',
4
+ ]
5
+
6
+ output_dir: ./output/deim_rtdetrv2_r18vd_120e_coco
7
+
8
+ optimizer:
9
+ type: AdamW
10
+ params:
11
+ -
12
+ params: '^(?=.*(?:norm|bn)).*$'
13
+ weight_decay: 0.
14
+
15
+ lr: 0.0002
16
+ betas: [0.9, 0.999]
17
+ weight_decay: 0.0001
18
+
19
+ # change part
20
+ epoches: 120
21
+ flat_epoch: 64 # 4 + 120 / 2
22
+ no_aug_epoch: 3
23
+
24
+ train_dataloader:
25
+ dataset:
26
+ transforms:
27
+ policy:
28
+ epoch: [4, 64, 117] # list
29
+
30
+ collate_fn:
31
+ mixup_epochs: [4, 64]
32
+ stop_epoch: 117
code/configs/deim_rtdetrv2/deim_r34vd_120e_coco.yml ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ __include__: [
2
+ './rtdetrv2_r34vd_120e_coco.yml',
3
+ '../base/rt_deim.yml',
4
+ ]
5
+
6
+ output_dir: ./outputs/deim_rtdetrv2_r34vd_120e_coco
7
+
8
+ optimizer:
9
+ type: AdamW
10
+ params:
11
+ -
12
+ params: '^(?=.*backbone)(?!.*norm).*$'
13
+ lr: 0.0001
14
+ -
15
+ params: '^(?=.*(?:norm|bn)).*$'
16
+ weight_decay: 0.
17
+
18
+ lr: 0.0002
19
+ betas: [0.9, 0.999]
20
+ weight_decay: 0.0001
21
+
22
+
23
+ # change part
24
+ epoches: 120
25
+ flat_epoch: 64
26
+ no_aug_epoch: 3
27
+
28
+ train_dataloader:
29
+ dataset:
30
+ transforms:
31
+ policy:
32
+ epoch: [4, 64, 117] # list
33
+
34
+ collate_fn:
35
+ mixup_epochs: [4, 64]
36
+ stop_epoch: 117
code/configs/deim_rtdetrv2/deim_r50vd_60e_coco.yml ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ __include__: [
2
+ './rtdetrv2_r50vd_6x_coco.yml',
3
+ '../base/rt_deim.yml',
4
+ ]
5
+
6
+ output_dir: ./outputs/deim_rtdetrv2_r50vd_60e_coco
7
+
8
+ optimizer:
9
+ type: AdamW
10
+ params:
11
+ -
12
+ params: '^(?=.*backbone)(?!.*norm).*$'
13
+ lr: 0.00002
14
+ -
15
+ params: '^(?=.*(?:norm|bn)).*$'
16
+ weight_decay: 0.
17
+
18
+ lr: 0.0002
19
+ betas: [0.9, 0.999]
20
+ weight_decay: 0.0001
21
+
22
+ # change part
23
+ epoches: 60
24
+ flat_epoch: 34 # 4 + 60 / 2
25
+ no_aug_epoch: 2
26
+
27
+ train_dataloader:
28
+ dataset:
29
+ transforms:
30
+ policy:
31
+ epoch: [4, 34, 58] # list
32
+
33
+ collate_fn:
34
+ mixup_epochs: [4, 34]
35
+ stop_epoch: 58
code/configs/deim_rtdetrv2/deim_r50vd_m_60e_coco.yml ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ __include__: [
2
+ './rtdetrv2_r50vd_m_7x_coco.yml',
3
+ '../base/rt_deim.yml',
4
+ ]
5
+
6
+ output_dir: ./outputs/deim_rtdetrv2_r50vd_m_60e_coco
7
+
8
+ RTDETRTransformerv2:
9
+ eval_idx: 2 # use 3th decoder layer to eval
10
+ num_layers: 3
11
+
12
+ optimizer:
13
+ type: AdamW
14
+ params:
15
+ -
16
+ params: '^(?=.*backbone)(?!.*norm).*$'
17
+ lr: 0.00002
18
+ -
19
+ params: '^(?=.*(?:norm|bn)).*$'
20
+ weight_decay: 0.
21
+
22
+ lr: 0.0002
23
+ betas: [0.9, 0.999]
24
+ weight_decay: 0.0001
25
+
26
+ # change part
27
+ epoches: 60
28
+ flat_epoch: 34 # 4 + 60 / 2
29
+ no_aug_epoch: 2
30
+
31
+ train_dataloader:
32
+ dataset:
33
+ transforms:
34
+ policy:
35
+ epoch: [4, 34, 58] # list
36
+
37
+ collate_fn:
38
+ mixup_epochs: [4, 34]
39
+ stop_epoch: 58
code/configs/deim_rtdetrv2/rtdetrv2_r101vd_6x_coco.yml ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ __include__: [
2
+ '../dataset/coco_detection.yml',
3
+ '../runtime.yml',
4
+ '../base/dataloader.yml',
5
+ '../base/rt_optimizer.yml',
6
+ '../base/rtdetrv2_r50vd.yml',
7
+ ]
8
+
9
+
10
+ output_dir: ./outputs/rtdetrv2_r101vd_6x_coco
11
+
12
+
13
+ PResNet:
14
+ depth: 101
15
+
16
+
17
+ HybridEncoder:
18
+ # intra
19
+ hidden_dim: 384
20
+ dim_feedforward: 2048
21
+
22
+
23
+ RTDETRTransformerv2:
24
+ feat_channels: [384, 384, 384]
25
+
26
+
27
+ optimizer:
28
+ type: AdamW
29
+ params:
30
+ -
31
+ params: '^(?=.*backbone)(?!.*norm|bn).*$'
32
+ lr: 0.000001
33
+ -
34
+ params: '^(?=.*(?:encoder|decoder))(?=.*(?:norm|bn)).*$' # only encoder + decoder norm
35
+ weight_decay: 0.
36
+
37
+ lr: 0.0001
38
+ betas: [0.9, 0.999]
39
+ weight_decay: 0.0001
40
+
code/configs/deim_rtdetrv2/rtdetrv2_r18vd_120e_coco.yml ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ __include__: [
2
+ '../dataset/coco_detection.yml',
3
+ '../runtime.yml',
4
+ '../base/dataloader.yml',
5
+ '../base/rt_optimizer.yml',
6
+ '../base/rtdetrv2_r50vd.yml',
7
+ ]
8
+
9
+
10
+ output_dir: ./output/rtdetrv2_r18vd_120e_coco
11
+
12
+
13
+ PResNet:
14
+ depth: 18
15
+ freeze_at: -1
16
+ freeze_norm: False
17
+ pretrained: True
18
+
19
+ HybridEncoder:
20
+ in_channels: [128, 256, 512]
21
+ hidden_dim: 256
22
+ expansion: 0.5
23
+
24
+ RTDETRTransformerv2:
25
+ num_layers: 3
26
+
27
+
28
+ epoches: 120
29
+
30
+ optimizer:
31
+ type: AdamW
32
+ params:
33
+ -
34
+ params: '^(?=.*(?:norm|bn)).*$'
35
+ weight_decay: 0.
36
+
37
+
38
+ train_dataloader:
39
+ dataset:
40
+ transforms:
41
+ policy:
42
+ epoch: 117
43
+ collate_fn:
44
+ scales: ~
code/configs/deim_rtdetrv2/rtdetrv2_r34vd_120e_coco.yml ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ __include__: [
2
+ '../dataset/coco_detection.yml',
3
+ '../runtime.yml',
4
+ '../base/dataloader.yml',
5
+ '../base/rt_optimizer.yml',
6
+ '../base/rtdetrv2_r50vd.yml',
7
+ ]
8
+
9
+
10
+ output_dir: ./outputs/rtdetrv2_r34vd_120e_coco
11
+
12
+
13
+ PResNet:
14
+ depth: 34
15
+ freeze_at: -1
16
+ freeze_norm: False
17
+ pretrained: True
18
+
19
+
20
+ HybridEncoder:
21
+ in_channels: [128, 256, 512]
22
+ hidden_dim: 256
23
+ expansion: 0.5
24
+
25
+
26
+ RTDETRTransformerv2:
27
+ num_layers: 4
28
+
29
+
30
+ epoches: 120
31
+
32
+ optimizer:
33
+ type: AdamW
34
+ params:
35
+ -
36
+ params: '^(?=.*backbone)(?!.*norm|bn).*$'
37
+ lr: 0.00005
38
+ -
39
+ params: '^(?=.*backbone)(?=.*norm|bn).*$'
40
+ lr: 0.00005
41
+ weight_decay: 0.
42
+ -
43
+ params: '^(?=.*(?:encoder|decoder))(?=.*(?:norm|bn|bias)).*$'
44
+ weight_decay: 0.
45
+
46
+ lr: 0.0001
47
+ betas: [0.9, 0.999]
48
+ weight_decay: 0.0001
49
+
50
+
51
+ train_dataloader:
52
+ dataset:
53
+ transforms:
54
+ policy:
55
+ epoch: 117
56
+ collate_fn:
57
+ stop_epoch: 117
code/configs/deim_rtdetrv2/rtdetrv2_r50vd_6x_coco.yml ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ __include__: [
2
+ '../dataset/coco_detection.yml',
3
+ '../runtime.yml',
4
+ '../base/dataloader.yml',
5
+ '../base/rt_optimizer.yml',
6
+ '../base/rtdetrv2_r50vd.yml',
7
+ ]
8
+
9
+
10
+ output_dir: ./outputs/rtdetrv2_r50vd_6x_coco
11
+
12
+
13
+ optimizer:
14
+ type: AdamW
15
+ params:
16
+ -
17
+ params: '^(?=.*backbone)(?!.*norm).*$'
18
+ lr: 0.00001
19
+ -
20
+ params: '^(?=.*(?:encoder|decoder))(?=.*(?:norm|bn)).*$'
21
+ weight_decay: 0.
22
+
23
+ lr: 0.0001
24
+ betas: [0.9, 0.999]
25
+ weight_decay: 0.0001
code/configs/deim_rtdetrv2/rtdetrv2_r50vd_m_7x_coco.yml ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ __include__: [
2
+ '../dataset/coco_detection.yml',
3
+ '../runtime.yml',
4
+ '../base/dataloader.yml',
5
+ '../base/rt_optimizer.yml',
6
+ '../base/rtdetrv2_r50vd.yml',
7
+ ]
8
+
9
+ output_dir: ./outputs/rtdetrv2_r50vd_m_6x_coco
10
+
11
+
12
+ HybridEncoder:
13
+ expansion: 0.5
14
+
15
+
16
+ RTDETRTransformerv2:
17
+ eval_idx: 2 # use 3th decoder layer to eval
18
+
19
+
20
+ epoches: 84
21
+
22
+ optimizer:
23
+ type: AdamW
24
+ params:
25
+ -
26
+ params: '^(?=.*backbone)(?!.*norm).*$'
27
+ lr: 0.00001
28
+ -
29
+ params: '^(?=.*(?:encoder|decoder))(?=.*(?:norm|bn)).*$'
30
+ weight_decay: 0.
31
+
32
+ lr: 0.0001
33
+ betas: [0.9, 0.999]
34
+ weight_decay: 0.0001
35
+
36
+
37
+ train_dataloader:
38
+ dataset:
39
+ transforms:
40
+ policy:
41
+ epoch: 81
42
+ collate_fn:
43
+ stop_epoch: 81
code/configs/runtime.yml ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ print_freq: 100
2
+ output_dir: './logs'
3
+ checkpoint_freq: 12
4
+
5
+
6
+ sync_bn: True
7
+ find_unused_parameters: False
8
+
9
+
10
+ use_amp: False
11
+ scaler:
12
+ type: GradScaler
13
+ enabled: True
14
+
15
+
16
+ use_ema: False
17
+ ema:
18
+ type: ModelEMA
19
+ decay: 0.9999
20
+ warmups: 1000
code/engine/__init__.py ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Copyright (c) 2024 The DEIM Authors. All Rights Reserved.
3
+ """
4
+
5
+ # for register purpose
6
+ from . import optim
7
+ from . import data
8
+ from . import deim
9
+
10
+ from .backbone import *
11
+
12
+ from .backbone import (
13
+ get_activation,
14
+ FrozenBatchNorm2d,
15
+ freeze_batch_norm2d,
16
+ )
code/engine/backbone/__init__.py ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Copied from RT-DETR (https://github.com/lyuwenyu/RT-DETR)
3
+ Copyright(c) 2023 lyuwenyu. All Rights Reserved.
4
+ """
5
+
6
+ from .common import (
7
+ get_activation,
8
+ FrozenBatchNorm2d,
9
+ freeze_batch_norm2d,
10
+ )
11
+ from .presnet import PResNet
12
+ from .test_resnet import MResNet
13
+
14
+ from .timm_model import TimmModel
15
+ from .torchvision_model import TorchVisionModel
16
+
17
+ from .csp_resnet import CSPResNet
18
+ from .csp_darknet import CSPDarkNet, CSPPAN
19
+
20
+ from .hgnetv2 import HGNetv2
code/engine/backbone/common.py ADDED
@@ -0,0 +1,116 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Copied from RT-DETR (https://github.com/lyuwenyu/RT-DETR)
3
+ Copyright(c) 2023 lyuwenyu. All Rights Reserved.
4
+ """
5
+
6
+ import torch
7
+ import torch.nn as nn
8
+
9
+
10
+ class ConvNormLayer(nn.Module):
11
+ def __init__(self, ch_in, ch_out, kernel_size, stride, padding=None, bias=False, act=None):
12
+ super().__init__()
13
+ self.conv = nn.Conv2d(
14
+ ch_in,
15
+ ch_out,
16
+ kernel_size,
17
+ stride,
18
+ padding=(kernel_size-1)//2 if padding is None else padding,
19
+ bias=bias)
20
+ self.norm = nn.BatchNorm2d(ch_out)
21
+ self.act = nn.Identity() if act is None else get_activation(act)
22
+
23
+ def forward(self, x):
24
+ return self.act(self.norm(self.conv(x)))
25
+
26
+
27
+ class FrozenBatchNorm2d(nn.Module):
28
+ """copy and modified from https://github.com/facebookresearch/detr/blob/master/models/backbone.py
29
+ BatchNorm2d where the batch statistics and the affine parameters are fixed.
30
+ Copy-paste from torchvision.misc.ops with added eps before rqsrt,
31
+ without which any other models than torchvision.models.resnet[18,34,50,101]
32
+ produce nans.
33
+ """
34
+ def __init__(self, num_features, eps=1e-5):
35
+ super(FrozenBatchNorm2d, self).__init__()
36
+ n = num_features
37
+ self.register_buffer("weight", torch.ones(n))
38
+ self.register_buffer("bias", torch.zeros(n))
39
+ self.register_buffer("running_mean", torch.zeros(n))
40
+ self.register_buffer("running_var", torch.ones(n))
41
+ self.eps = eps
42
+ self.num_features = n
43
+
44
+ def _load_from_state_dict(self, state_dict, prefix, local_metadata, strict,
45
+ missing_keys, unexpected_keys, error_msgs):
46
+ num_batches_tracked_key = prefix + 'num_batches_tracked'
47
+ if num_batches_tracked_key in state_dict:
48
+ del state_dict[num_batches_tracked_key]
49
+
50
+ super(FrozenBatchNorm2d, self)._load_from_state_dict(
51
+ state_dict, prefix, local_metadata, strict,
52
+ missing_keys, unexpected_keys, error_msgs)
53
+
54
+ def forward(self, x):
55
+ # move reshapes to the beginning
56
+ # to make it fuser-friendly
57
+ w = self.weight.reshape(1, -1, 1, 1)
58
+ b = self.bias.reshape(1, -1, 1, 1)
59
+ rv = self.running_var.reshape(1, -1, 1, 1)
60
+ rm = self.running_mean.reshape(1, -1, 1, 1)
61
+ scale = w * (rv + self.eps).rsqrt()
62
+ bias = b - rm * scale
63
+ return x * scale + bias
64
+
65
+ def extra_repr(self):
66
+ return (
67
+ "{num_features}, eps={eps}".format(**self.__dict__)
68
+ )
69
+
70
+ def freeze_batch_norm2d(module: nn.Module) -> nn.Module:
71
+ if isinstance(module, nn.BatchNorm2d):
72
+ module = FrozenBatchNorm2d(module.num_features)
73
+ else:
74
+ for name, child in module.named_children():
75
+ _child = freeze_batch_norm2d(child)
76
+ if _child is not child:
77
+ setattr(module, name, _child)
78
+ return module
79
+
80
+
81
+ def get_activation(act: str, inplace: bool=True):
82
+ """get activation
83
+ """
84
+ if act is None:
85
+ return nn.Identity()
86
+
87
+ elif isinstance(act, nn.Module):
88
+ return act
89
+
90
+ act = act.lower()
91
+
92
+ if act == 'silu' or act == 'swish':
93
+ m = nn.SiLU()
94
+
95
+ elif act == 'relu':
96
+ m = nn.ReLU()
97
+
98
+ elif act == 'leaky_relu':
99
+ m = nn.LeakyReLU()
100
+
101
+ elif act == 'silu':
102
+ m = nn.SiLU()
103
+
104
+ elif act == 'gelu':
105
+ m = nn.GELU()
106
+
107
+ elif act == 'hardsigmoid':
108
+ m = nn.Hardsigmoid()
109
+
110
+ else:
111
+ raise RuntimeError('')
112
+
113
+ if hasattr(m, 'inplace'):
114
+ m.inplace = inplace
115
+
116
+ return m
code/engine/backbone/csp_darknet.py ADDED
@@ -0,0 +1,179 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Copied from RT-DETR (https://github.com/lyuwenyu/RT-DETR)
3
+ Copyright(c) 2023 lyuwenyu. All Rights Reserved.
4
+ """
5
+
6
+ import torch
7
+ import torch.nn as nn
8
+ import torch.nn.functional as F
9
+
10
+ import math
11
+ import warnings
12
+
13
+ from .common import get_activation
14
+ from ..core import register
15
+
16
+
17
+ def autopad(k, p=None):
18
+ if p is None:
19
+ p = k // 2 if isinstance(k, int) else [x // 2 for x in k]
20
+ return p
21
+
22
+ def make_divisible(c, d):
23
+ return math.ceil(c / d) * d
24
+
25
+
26
+ class Conv(nn.Module):
27
+ def __init__(self, cin, cout, k=1, s=1, p=None, g=1, act='silu') -> None:
28
+ super().__init__()
29
+ self.conv = nn.Conv2d(cin, cout, k, s, autopad(k, p), groups=g, bias=False)
30
+ self.bn = nn.BatchNorm2d(cout)
31
+ self.act = get_activation(act, inplace=True)
32
+
33
+ def forward(self, x):
34
+ return self.act(self.bn(self.conv(x)))
35
+
36
+
37
+ class Bottleneck(nn.Module):
38
+ # Standard bottleneck
39
+ def __init__(self, c1, c2, shortcut=True, g=1, e=0.5, act='silu'):
40
+ super().__init__()
41
+ c_ = int(c2 * e) # hidden channels
42
+ self.cv1 = Conv(c1, c_, 1, 1, act=act)
43
+ self.cv2 = Conv(c_, c2, 3, 1, g=g, act=act)
44
+ self.add = shortcut and c1 == c2
45
+
46
+ def forward(self, x):
47
+ return x + self.cv2(self.cv1(x)) if self.add else self.cv2(self.cv1(x))
48
+
49
+
50
+ class C3(nn.Module):
51
+ # CSP Bottleneck with 3 convolutions
52
+ def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5, act='silu'): # ch_in, ch_out, number, shortcut, groups, expansion
53
+ super().__init__()
54
+ c_ = int(c2 * e) # hidden channels
55
+ self.cv1 = Conv(c1, c_, 1, 1, act=act)
56
+ self.cv2 = Conv(c1, c_, 1, 1, act=act)
57
+ self.m = nn.Sequential(*(Bottleneck(c_, c_, shortcut, g, e=1.0, act=act) for _ in range(n)))
58
+ self.cv3 = Conv(2 * c_, c2, 1, act=act)
59
+
60
+ def forward(self, x):
61
+ return self.cv3(torch.cat((self.m(self.cv1(x)), self.cv2(x)), dim=1))
62
+
63
+
64
+ class SPPF(nn.Module):
65
+ # Spatial Pyramid Pooling - Fast (SPPF) layer for YOLOv5 by Glenn Jocher
66
+ def __init__(self, c1, c2, k=5, act='silu'): # equivalent to SPP(k=(5, 9, 13))
67
+ super().__init__()
68
+ c_ = c1 // 2 # hidden channels
69
+ self.cv1 = Conv(c1, c_, 1, 1, act=act)
70
+ self.cv2 = Conv(c_ * 4, c2, 1, 1, act=act)
71
+ self.m = nn.MaxPool2d(kernel_size=k, stride=1, padding=k // 2)
72
+
73
+ def forward(self, x):
74
+ x = self.cv1(x)
75
+ with warnings.catch_warnings():
76
+ warnings.simplefilter('ignore') # suppress torch 1.9.0 max_pool2d() warning
77
+ y1 = self.m(x)
78
+ y2 = self.m(y1)
79
+ return self.cv2(torch.cat([x, y1, y2, self.m(y2)], 1))
80
+
81
+
82
+ @register()
83
+ class CSPDarkNet(nn.Module):
84
+ __share__ = ['depth_multi', 'width_multi']
85
+
86
+ def __init__(self, in_channels=3, width_multi=1.0, depth_multi=1.0, return_idx=[2, 3, -1], act='silu', ) -> None:
87
+ super().__init__()
88
+
89
+ channels = [64, 128, 256, 512, 1024]
90
+ channels = [make_divisible(c * width_multi, 8) for c in channels]
91
+
92
+ depths = [3, 6, 9, 3]
93
+ depths = [max(round(d * depth_multi), 1) for d in depths]
94
+
95
+ self.layers = nn.ModuleList([Conv(in_channels, channels[0], 6, 2, 2, act=act)])
96
+ for i, (c, d) in enumerate(zip(channels, depths), 1):
97
+ layer = nn.Sequential(*[Conv(c, channels[i], 3, 2, act=act), C3(channels[i], channels[i], n=d, act=act)])
98
+ self.layers.append(layer)
99
+
100
+ self.layers.append(SPPF(channels[-1], channels[-1], k=5, act=act))
101
+
102
+ self.return_idx = return_idx
103
+ self.out_channels = [channels[i] for i in self.return_idx]
104
+ self.strides = [[2, 4, 8, 16, 32][i] for i in self.return_idx]
105
+ self.depths = depths
106
+ self.act = act
107
+
108
+ def forward(self, x):
109
+ outputs = []
110
+ for _, m in enumerate(self.layers):
111
+ x = m(x)
112
+ outputs.append(x)
113
+
114
+ return [outputs[i] for i in self.return_idx]
115
+
116
+
117
+ @register()
118
+ class CSPPAN(nn.Module):
119
+ """
120
+ P5 ---> 1x1 ---------------------------------> concat --> c3 --> det
121
+ | up | conv /2
122
+ P4 ---> concat ---> c3 ---> 1x1 --> concat ---> c3 -----------> det
123
+ | up | conv /2
124
+ P3 -----------------------> concat ---> c3 ---------------------> det
125
+ """
126
+ __share__ = ['depth_multi', ]
127
+
128
+ def __init__(self, in_channels=[256, 512, 1024], depth_multi=1., act='silu') -> None:
129
+ super().__init__()
130
+ depth = max(round(3 * depth_multi), 1)
131
+
132
+ self.out_channels = in_channels
133
+ self.fpn_stems = nn.ModuleList([Conv(cin, cout, 1, 1, act=act) for cin, cout in zip(in_channels[::-1], in_channels[::-1][1:])])
134
+ self.fpn_csps = nn.ModuleList([C3(cin, cout, depth, False, act=act) for cin, cout in zip(in_channels[::-1], in_channels[::-1][1:])])
135
+
136
+ self.pan_stems = nn.ModuleList([Conv(c, c, 3, 2, act=act) for c in in_channels[:-1]])
137
+ self.pan_csps = nn.ModuleList([C3(c, c, depth, False, act=act) for c in in_channels[1:]])
138
+
139
+ def forward(self, feats):
140
+ fpn_feats = []
141
+ for i, feat in enumerate(feats[::-1]):
142
+ if i == 0:
143
+ feat = self.fpn_stems[i](feat)
144
+ fpn_feats.append(feat)
145
+ else:
146
+ _feat = F.interpolate(fpn_feats[-1], scale_factor=2, mode='nearest')
147
+ feat = torch.concat([_feat, feat], dim=1)
148
+ feat = self.fpn_csps[i-1](feat)
149
+ if i < len(self.fpn_stems):
150
+ feat = self.fpn_stems[i](feat)
151
+ fpn_feats.append(feat)
152
+
153
+ pan_feats = []
154
+ for i, feat in enumerate(fpn_feats[::-1]):
155
+ if i == 0:
156
+ pan_feats.append(feat)
157
+ else:
158
+ _feat = self.pan_stems[i-1](pan_feats[-1])
159
+ feat = torch.concat([_feat, feat], dim=1)
160
+ feat = self.pan_csps[i-1](feat)
161
+ pan_feats.append(feat)
162
+
163
+ return pan_feats
164
+
165
+
166
+ if __name__ == '__main__':
167
+
168
+ data = torch.rand(1, 3, 320, 640)
169
+
170
+ width_multi = 0.75
171
+ depth_multi = 0.33
172
+
173
+ m = CSPDarkNet(3, width_multi=width_multi, depth_multi=depth_multi, act='silu')
174
+ outputs = m(data)
175
+ print([o.shape for o in outputs])
176
+
177
+ m = CSPPAN(in_channels=m.out_channels, depth_multi=depth_multi, act='silu')
178
+ outputs = m(outputs)
179
+ print([o.shape for o in outputs])
code/engine/backbone/csp_resnet.py ADDED
@@ -0,0 +1,277 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ https://github.com/PaddlePaddle/PaddleDetection/blob/release/2.6/ppdet/modeling/backbones/cspresnet.py
3
+
4
+ Copyright(c) 2023 lyuwenyu. All Rights Reserved.
5
+ """
6
+
7
+ import torch
8
+ import torch.nn as nn
9
+ import torch.nn.functional as F
10
+ from collections import OrderedDict
11
+
12
+ from .common import get_activation
13
+
14
+ from ..core import register
15
+
16
+ __all__ = ['CSPResNet']
17
+
18
+
19
+ donwload_url = {
20
+ 's': 'https://github.com/lyuwenyu/storage/releases/download/v0.1/CSPResNetb_s_pretrained_from_paddle.pth',
21
+ 'm': 'https://github.com/lyuwenyu/storage/releases/download/v0.1/CSPResNetb_m_pretrained_from_paddle.pth',
22
+ 'l': 'https://github.com/lyuwenyu/storage/releases/download/v0.1/CSPResNetb_l_pretrained_from_paddle.pth',
23
+ 'x': 'https://github.com/lyuwenyu/storage/releases/download/v0.1/CSPResNetb_x_pretrained_from_paddle.pth',
24
+ }
25
+
26
+
27
+ class ConvBNLayer(nn.Module):
28
+ def __init__(self, ch_in, ch_out, filter_size=3, stride=1, groups=1, padding=0, act=None):
29
+ super().__init__()
30
+ self.conv = nn.Conv2d(ch_in, ch_out, filter_size, stride, padding, groups=groups, bias=False)
31
+ self.bn = nn.BatchNorm2d(ch_out)
32
+ self.act = get_activation(act)
33
+
34
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
35
+ x = self.conv(x)
36
+ x = self.bn(x)
37
+ x = self.act(x)
38
+ return x
39
+
40
+ class RepVggBlock(nn.Module):
41
+ def __init__(self, ch_in, ch_out, act='relu', alpha: bool=False):
42
+ super().__init__()
43
+ self.ch_in = ch_in
44
+ self.ch_out = ch_out
45
+ self.conv1 = ConvBNLayer(
46
+ ch_in, ch_out, 3, stride=1, padding=1, act=None)
47
+ self.conv2 = ConvBNLayer(
48
+ ch_in, ch_out, 1, stride=1, padding=0, act=None)
49
+ self.act = get_activation(act)
50
+
51
+ if alpha:
52
+ self.alpha = nn.Parameter(torch.ones(1, ))
53
+ else:
54
+ self.alpha = None
55
+
56
+ def forward(self, x):
57
+ if hasattr(self, 'conv'):
58
+ y = self.conv(x)
59
+ else:
60
+ if self.alpha:
61
+ y = self.conv1(x) + self.alpha * self.conv2(x)
62
+ else:
63
+ y = self.conv1(x) + self.conv2(x)
64
+ y = self.act(y)
65
+ return y
66
+
67
+ def convert_to_deploy(self):
68
+ if not hasattr(self, 'conv'):
69
+ self.conv = nn.Conv2d(self.ch_in, self.ch_out, 3, 1, padding=1)
70
+
71
+ kernel, bias = self.get_equivalent_kernel_bias()
72
+ self.conv.weight.data = kernel
73
+ self.conv.bias.data = bias
74
+
75
+ def get_equivalent_kernel_bias(self):
76
+ kernel3x3, bias3x3 = self._fuse_bn_tensor(self.conv1)
77
+ kernel1x1, bias1x1 = self._fuse_bn_tensor(self.conv2)
78
+
79
+ if self.alpha:
80
+ return kernel3x3 + self.alpha * self._pad_1x1_to_3x3_tensor(
81
+ kernel1x1), bias3x3 + self.alpha * bias1x1
82
+ else:
83
+ return kernel3x3 + self._pad_1x1_to_3x3_tensor(
84
+ kernel1x1), bias3x3 + bias1x1
85
+
86
+ def _pad_1x1_to_3x3_tensor(self, kernel1x1):
87
+ if kernel1x1 is None:
88
+ return 0
89
+ else:
90
+ return F.pad(kernel1x1, [1, 1, 1, 1])
91
+
92
+ def _fuse_bn_tensor(self, branch: ConvBNLayer):
93
+ if branch is None:
94
+ return 0, 0
95
+ kernel = branch.conv.weight
96
+ running_mean = branch.norm.running_mean
97
+ running_var = branch.norm.running_var
98
+ gamma = branch.norm.weight
99
+ beta = branch.norm.bias
100
+ eps = branch.norm.eps
101
+ std = (running_var + eps).sqrt()
102
+ t = (gamma / std).reshape(-1, 1, 1, 1)
103
+ return kernel * t, beta - running_mean * gamma / std
104
+
105
+
106
+ class BasicBlock(nn.Module):
107
+ def __init__(self,
108
+ ch_in,
109
+ ch_out,
110
+ act='relu',
111
+ shortcut=True,
112
+ use_alpha=False):
113
+ super().__init__()
114
+ assert ch_in == ch_out
115
+ self.conv1 = ConvBNLayer(ch_in, ch_out, 3, stride=1, padding=1, act=act)
116
+ self.conv2 = RepVggBlock(ch_out, ch_out, act=act, alpha=use_alpha)
117
+ self.shortcut = shortcut
118
+
119
+ def forward(self, x):
120
+ y = self.conv1(x)
121
+ y = self.conv2(y)
122
+ if self.shortcut:
123
+ return x + y
124
+ else:
125
+ return y
126
+
127
+
128
+ class EffectiveSELayer(nn.Module):
129
+ """ Effective Squeeze-Excitation
130
+ From `CenterMask : Real-Time Anchor-Free Instance Segmentation` - https://arxiv.org/abs/1911.06667
131
+ """
132
+
133
+ def __init__(self, channels, act='hardsigmoid'):
134
+ super(EffectiveSELayer, self).__init__()
135
+ self.fc = nn.Conv2d(channels, channels, kernel_size=1, padding=0)
136
+ self.act = get_activation(act)
137
+
138
+ def forward(self, x: torch.Tensor):
139
+ x_se = x.mean((2, 3), keepdim=True)
140
+ x_se = self.fc(x_se)
141
+ x_se = self.act(x_se)
142
+ return x * x_se
143
+
144
+
145
+ class CSPResStage(nn.Module):
146
+ def __init__(self,
147
+ block_fn,
148
+ ch_in,
149
+ ch_out,
150
+ n,
151
+ stride,
152
+ act='relu',
153
+ attn='eca',
154
+ use_alpha=False):
155
+ super().__init__()
156
+ ch_mid = (ch_in + ch_out) // 2
157
+ if stride == 2:
158
+ self.conv_down = ConvBNLayer(
159
+ ch_in, ch_mid, 3, stride=2, padding=1, act=act)
160
+ else:
161
+ self.conv_down = None
162
+ self.conv1 = ConvBNLayer(ch_mid, ch_mid // 2, 1, act=act)
163
+ self.conv2 = ConvBNLayer(ch_mid, ch_mid // 2, 1, act=act)
164
+ self.blocks = nn.Sequential(*[
165
+ block_fn(
166
+ ch_mid // 2,
167
+ ch_mid // 2,
168
+ act=act,
169
+ shortcut=True,
170
+ use_alpha=use_alpha) for i in range(n)
171
+ ])
172
+ if attn:
173
+ self.attn = EffectiveSELayer(ch_mid, act='hardsigmoid')
174
+ else:
175
+ self.attn = None
176
+
177
+ self.conv3 = ConvBNLayer(ch_mid, ch_out, 1, act=act)
178
+
179
+ def forward(self, x):
180
+ if self.conv_down is not None:
181
+ x = self.conv_down(x)
182
+ y1 = self.conv1(x)
183
+ y2 = self.blocks(self.conv2(x))
184
+ y = torch.concat([y1, y2], dim=1)
185
+ if self.attn is not None:
186
+ y = self.attn(y)
187
+ y = self.conv3(y)
188
+ return y
189
+
190
+
191
+ @register()
192
+ class CSPResNet(nn.Module):
193
+ layers = [3, 6, 6, 3]
194
+ channels = [64, 128, 256, 512, 1024]
195
+ model_cfg = {
196
+ 's': {'depth_mult': 0.33, 'width_mult': 0.50, },
197
+ 'm': {'depth_mult': 0.67, 'width_mult': 0.75, },
198
+ 'l': {'depth_mult': 1.00, 'width_mult': 1.00, },
199
+ 'x': {'depth_mult': 1.33, 'width_mult': 1.25, },
200
+ }
201
+
202
+ def __init__(self,
203
+ name: str,
204
+ act='silu',
205
+ return_idx=[1, 2, 3],
206
+ use_large_stem=True,
207
+ use_alpha=False,
208
+ pretrained=False):
209
+
210
+ super().__init__()
211
+ depth_mult = self.model_cfg[name]['depth_mult']
212
+ width_mult = self.model_cfg[name]['width_mult']
213
+
214
+ channels = [max(round(c * width_mult), 1) for c in self.channels]
215
+ layers = [max(round(l * depth_mult), 1) for l in self.layers]
216
+ act = get_activation(act)
217
+
218
+ if use_large_stem:
219
+ self.stem = nn.Sequential(OrderedDict([
220
+ ('conv1', ConvBNLayer(
221
+ 3, channels[0] // 2, 3, stride=2, padding=1, act=act)),
222
+ ('conv2', ConvBNLayer(
223
+ channels[0] // 2,
224
+ channels[0] // 2,
225
+ 3,
226
+ stride=1,
227
+ padding=1,
228
+ act=act)), ('conv3', ConvBNLayer(
229
+ channels[0] // 2,
230
+ channels[0],
231
+ 3,
232
+ stride=1,
233
+ padding=1,
234
+ act=act))]))
235
+ else:
236
+ self.stem = nn.Sequential(OrderedDict([
237
+ ('conv1', ConvBNLayer(
238
+ 3, channels[0] // 2, 3, stride=2, padding=1, act=act)),
239
+ ('conv2', ConvBNLayer(
240
+ channels[0] // 2,
241
+ channels[0],
242
+ 3,
243
+ stride=1,
244
+ padding=1,
245
+ act=act))]))
246
+
247
+ n = len(channels) - 1
248
+ self.stages = nn.Sequential(OrderedDict([(str(i), CSPResStage(
249
+ BasicBlock,
250
+ channels[i],
251
+ channels[i + 1],
252
+ layers[i],
253
+ 2,
254
+ act=act,
255
+ use_alpha=use_alpha)) for i in range(n)]))
256
+
257
+ self._out_channels = channels[1:]
258
+ self._out_strides = [4 * 2**i for i in range(n)]
259
+ self.return_idx = return_idx
260
+
261
+ if pretrained:
262
+ if isinstance(pretrained, bool) or 'http' in pretrained:
263
+ state = torch.hub.load_state_dict_from_url(donwload_url[name], map_location='cpu')
264
+ else:
265
+ state = torch.load(pretrained, map_location='cpu')
266
+ self.load_state_dict(state)
267
+ print(f'Load CSPResNet_{name} state_dict')
268
+
269
+ def forward(self, x):
270
+ x = self.stem(x)
271
+ outs = []
272
+ for idx, stage in enumerate(self.stages):
273
+ x = stage(x)
274
+ if idx in self.return_idx:
275
+ outs.append(x)
276
+
277
+ return outs
code/engine/backbone/hgnetv2.py ADDED
@@ -0,0 +1,543 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ reference
3
+ - https://github.com/PaddlePaddle/PaddleDetection/blob/develop/ppdet/modeling/backbones/hgnet_v2.py
4
+
5
+ Copyright (c) 2024 The D-FINE Authors. All Rights Reserved.
6
+ """
7
+
8
+ import torch
9
+ import torch.nn as nn
10
+ import torch.nn.functional as F
11
+ import os
12
+ from .common import FrozenBatchNorm2d
13
+ from ..core import register
14
+ import logging
15
+
16
+ # Constants for initialization
17
+ kaiming_normal_ = nn.init.kaiming_normal_
18
+ zeros_ = nn.init.zeros_
19
+ ones_ = nn.init.ones_
20
+
21
+ __all__ = ['HGNetv2']
22
+
23
+
24
+ class LearnableAffineBlock(nn.Module):
25
+ def __init__(
26
+ self,
27
+ scale_value=1.0,
28
+ bias_value=0.0
29
+ ):
30
+ super().__init__()
31
+ self.scale = nn.Parameter(torch.tensor([scale_value]), requires_grad=True)
32
+ self.bias = nn.Parameter(torch.tensor([bias_value]), requires_grad=True)
33
+
34
+ def forward(self, x):
35
+ return self.scale * x + self.bias
36
+
37
+
38
+ class ConvBNAct(nn.Module):
39
+ def __init__(
40
+ self,
41
+ in_chs,
42
+ out_chs,
43
+ kernel_size,
44
+ stride=1,
45
+ groups=1,
46
+ padding='',
47
+ use_act=True,
48
+ use_lab=False
49
+ ):
50
+ super().__init__()
51
+ self.use_act = use_act
52
+ self.use_lab = use_lab
53
+ if padding == 'same':
54
+ self.conv = nn.Sequential(
55
+ nn.ZeroPad2d([0, 1, 0, 1]),
56
+ nn.Conv2d(
57
+ in_chs,
58
+ out_chs,
59
+ kernel_size,
60
+ stride,
61
+ groups=groups,
62
+ bias=False
63
+ )
64
+ )
65
+ else:
66
+ self.conv = nn.Conv2d(
67
+ in_chs,
68
+ out_chs,
69
+ kernel_size,
70
+ stride,
71
+ padding=(kernel_size - 1) // 2,
72
+ groups=groups,
73
+ bias=False
74
+ )
75
+ self.bn = nn.BatchNorm2d(out_chs)
76
+ if self.use_act:
77
+ self.act = nn.ReLU()
78
+ else:
79
+ self.act = nn.Identity()
80
+ if self.use_act and self.use_lab:
81
+ self.lab = LearnableAffineBlock()
82
+ else:
83
+ self.lab = nn.Identity()
84
+
85
+ def forward(self, x):
86
+ x = self.conv(x)
87
+ x = self.bn(x)
88
+ x = self.act(x)
89
+ x = self.lab(x)
90
+ return x
91
+
92
+
93
+ class LightConvBNAct(nn.Module):
94
+ def __init__(
95
+ self,
96
+ in_chs,
97
+ out_chs,
98
+ kernel_size,
99
+ groups=1,
100
+ use_lab=False,
101
+ ):
102
+ super().__init__()
103
+ self.conv1 = ConvBNAct(
104
+ in_chs,
105
+ out_chs,
106
+ kernel_size=1,
107
+ use_act=False,
108
+ use_lab=use_lab,
109
+ )
110
+ self.conv2 = ConvBNAct(
111
+ out_chs,
112
+ out_chs,
113
+ kernel_size=kernel_size,
114
+ groups=out_chs,
115
+ use_act=True,
116
+ use_lab=use_lab,
117
+ )
118
+
119
+ def forward(self, x):
120
+ x = self.conv1(x)
121
+ x = self.conv2(x)
122
+ return x
123
+
124
+
125
+ class StemBlock(nn.Module):
126
+ # for HGNetv2
127
+ def __init__(self, in_chs, mid_chs, out_chs, use_lab=False):
128
+ super().__init__()
129
+ self.stem1 = ConvBNAct(
130
+ in_chs,
131
+ mid_chs,
132
+ kernel_size=3,
133
+ stride=2,
134
+ use_lab=use_lab,
135
+ )
136
+ self.stem2a = ConvBNAct(
137
+ mid_chs,
138
+ mid_chs // 2,
139
+ kernel_size=2,
140
+ stride=1,
141
+ use_lab=use_lab,
142
+ )
143
+ self.stem2b = ConvBNAct(
144
+ mid_chs // 2,
145
+ mid_chs,
146
+ kernel_size=2,
147
+ stride=1,
148
+ use_lab=use_lab,
149
+ )
150
+ self.stem3 = ConvBNAct(
151
+ mid_chs * 2,
152
+ mid_chs,
153
+ kernel_size=3,
154
+ stride=2,
155
+ use_lab=use_lab,
156
+ )
157
+ self.stem4 = ConvBNAct(
158
+ mid_chs,
159
+ out_chs,
160
+ kernel_size=1,
161
+ stride=1,
162
+ use_lab=use_lab,
163
+ )
164
+ self.pool = nn.MaxPool2d(kernel_size=2, stride=1, ceil_mode=True)
165
+
166
+ def forward(self, x):
167
+ x = self.stem1(x)
168
+ x = F.pad(x, (0, 1, 0, 1))
169
+ x2 = self.stem2a(x)
170
+ x2 = F.pad(x2, (0, 1, 0, 1))
171
+ x2 = self.stem2b(x2)
172
+ x1 = self.pool(x)
173
+ x = torch.cat([x1, x2], dim=1)
174
+ x = self.stem3(x)
175
+ x = self.stem4(x)
176
+ return x
177
+
178
+
179
+ class EseModule(nn.Module):
180
+ def __init__(self, chs):
181
+ super().__init__()
182
+ self.conv = nn.Conv2d(
183
+ chs,
184
+ chs,
185
+ kernel_size=1,
186
+ stride=1,
187
+ padding=0,
188
+ )
189
+ self.sigmoid = nn.Sigmoid()
190
+
191
+ def forward(self, x):
192
+ identity = x
193
+ x = x.mean((2, 3), keepdim=True)
194
+ x = self.conv(x)
195
+ x = self.sigmoid(x)
196
+ return torch.mul(identity, x)
197
+
198
+
199
+ class HG_Block(nn.Module):
200
+ def __init__(
201
+ self,
202
+ in_chs,
203
+ mid_chs,
204
+ out_chs,
205
+ layer_num,
206
+ kernel_size=3,
207
+ residual=False,
208
+ light_block=False,
209
+ use_lab=False,
210
+ agg='ese',
211
+ drop_path=0.,
212
+ ):
213
+ super().__init__()
214
+ self.residual = residual
215
+
216
+ self.layers = nn.ModuleList()
217
+ for i in range(layer_num):
218
+ if light_block:
219
+ self.layers.append(
220
+ LightConvBNAct(
221
+ in_chs if i == 0 else mid_chs,
222
+ mid_chs,
223
+ kernel_size=kernel_size,
224
+ use_lab=use_lab,
225
+ )
226
+ )
227
+ else:
228
+ self.layers.append(
229
+ ConvBNAct(
230
+ in_chs if i == 0 else mid_chs,
231
+ mid_chs,
232
+ kernel_size=kernel_size,
233
+ stride=1,
234
+ use_lab=use_lab,
235
+ )
236
+ )
237
+
238
+ # feature aggregation
239
+ total_chs = in_chs + layer_num * mid_chs
240
+ if agg == 'se':
241
+ aggregation_squeeze_conv = ConvBNAct(
242
+ total_chs,
243
+ out_chs // 2,
244
+ kernel_size=1,
245
+ stride=1,
246
+ use_lab=use_lab,
247
+ )
248
+ aggregation_excitation_conv = ConvBNAct(
249
+ out_chs // 2,
250
+ out_chs,
251
+ kernel_size=1,
252
+ stride=1,
253
+ use_lab=use_lab,
254
+ )
255
+ self.aggregation = nn.Sequential(
256
+ aggregation_squeeze_conv,
257
+ aggregation_excitation_conv,
258
+ )
259
+ else:
260
+ aggregation_conv = ConvBNAct(
261
+ total_chs,
262
+ out_chs,
263
+ kernel_size=1,
264
+ stride=1,
265
+ use_lab=use_lab,
266
+ )
267
+ att = EseModule(out_chs)
268
+ self.aggregation = nn.Sequential(
269
+ aggregation_conv,
270
+ att,
271
+ )
272
+
273
+ self.drop_path = nn.Dropout(drop_path) if drop_path else nn.Identity()
274
+
275
+ def forward(self, x):
276
+ identity = x
277
+ output = [x]
278
+ for layer in self.layers:
279
+ x = layer(x)
280
+ output.append(x)
281
+ x = torch.cat(output, dim=1)
282
+ x = self.aggregation(x)
283
+ if self.residual:
284
+ x = self.drop_path(x) + identity
285
+ return x
286
+
287
+
288
+ class HG_Stage(nn.Module):
289
+ def __init__(
290
+ self,
291
+ in_chs,
292
+ mid_chs,
293
+ out_chs,
294
+ block_num,
295
+ layer_num,
296
+ downsample=True,
297
+ light_block=False,
298
+ kernel_size=3,
299
+ use_lab=False,
300
+ agg='se',
301
+ drop_path=0.,
302
+ ):
303
+ super().__init__()
304
+ self.downsample = downsample
305
+ if downsample:
306
+ self.downsample = ConvBNAct(
307
+ in_chs,
308
+ in_chs,
309
+ kernel_size=3,
310
+ stride=2,
311
+ groups=in_chs,
312
+ use_act=False,
313
+ use_lab=use_lab,
314
+ )
315
+ else:
316
+ self.downsample = nn.Identity()
317
+
318
+ blocks_list = []
319
+ for i in range(block_num):
320
+ blocks_list.append(
321
+ HG_Block(
322
+ in_chs if i == 0 else out_chs,
323
+ mid_chs,
324
+ out_chs,
325
+ layer_num,
326
+ residual=False if i == 0 else True,
327
+ kernel_size=kernel_size,
328
+ light_block=light_block,
329
+ use_lab=use_lab,
330
+ agg=agg,
331
+ drop_path=drop_path[i] if isinstance(drop_path, (list, tuple)) else drop_path,
332
+ )
333
+ )
334
+ self.blocks = nn.Sequential(*blocks_list)
335
+
336
+ def forward(self, x):
337
+ x = self.downsample(x)
338
+ x = self.blocks(x)
339
+ return x
340
+
341
+
342
+
343
+ @register()
344
+ class HGNetv2(nn.Module):
345
+ """
346
+ HGNetV2
347
+ Args:
348
+ stem_channels: list. Number of channels for the stem block.
349
+ stage_type: str. The stage configuration of HGNet. such as the number of channels, stride, etc.
350
+ use_lab: boolean. Whether to use LearnableAffineBlock in network.
351
+ lr_mult_list: list. Control the learning rate of different stages.
352
+ Returns:
353
+ model: nn.Layer. Specific HGNetV2 model depends on args.
354
+ """
355
+
356
+ arch_configs = {
357
+ 'B0': {
358
+ 'stem_channels': [3, 16, 16],
359
+ 'stage_config': {
360
+ # in_channels, mid_channels, out_channels, num_blocks, downsample, light_block, kernel_size, layer_num
361
+ "stage1": [16, 16, 64, 1, False, False, 3, 3],
362
+ "stage2": [64, 32, 256, 1, True, False, 3, 3],
363
+ "stage3": [256, 64, 512, 2, True, True, 5, 3],
364
+ "stage4": [512, 128, 1024, 1, True, True, 5, 3],
365
+ },
366
+ 'url': 'https://github.com/Peterande/storage/releases/download/dfinev1.0/PPHGNetV2_B0_stage1.pth'
367
+ },
368
+ 'B1': {
369
+ 'stem_channels': [3, 24, 32],
370
+ 'stage_config': {
371
+ # in_channels, mid_channels, out_channels, num_blocks, downsample, light_block, kernel_size, layer_num
372
+ "stage1": [32, 32, 64, 1, False, False, 3, 3],
373
+ "stage2": [64, 48, 256, 1, True, False, 3, 3],
374
+ "stage3": [256, 96, 512, 2, True, True, 5, 3],
375
+ "stage4": [512, 192, 1024, 1, True, True, 5, 3],
376
+ },
377
+ 'url': 'https://github.com/Peterande/storage/releases/download/dfinev1.0/PPHGNetV2_B1_stage1.pth'
378
+ },
379
+ 'B2': {
380
+ 'stem_channels': [3, 24, 32],
381
+ 'stage_config': {
382
+ # in_channels, mid_channels, out_channels, num_blocks, downsample, light_block, kernel_size, layer_num
383
+ "stage1": [32, 32, 96, 1, False, False, 3, 4],
384
+ "stage2": [96, 64, 384, 1, True, False, 3, 4],
385
+ "stage3": [384, 128, 768, 3, True, True, 5, 4],
386
+ "stage4": [768, 256, 1536, 1, True, True, 5, 4],
387
+ },
388
+ 'url': 'https://github.com/Peterande/storage/releases/download/dfinev1.0/PPHGNetV2_B2_stage1.pth'
389
+ },
390
+ 'B3': {
391
+ 'stem_channels': [3, 24, 32],
392
+ 'stage_config': {
393
+ # in_channels, mid_channels, out_channels, num_blocks, downsample, light_block, kernel_size, layer_num
394
+ "stage1": [32, 32, 128, 1, False, False, 3, 5],
395
+ "stage2": [128, 64, 512, 1, True, False, 3, 5],
396
+ "stage3": [512, 128, 1024, 3, True, True, 5, 5],
397
+ "stage4": [1024, 256, 2048, 1, True, True, 5, 5],
398
+ },
399
+ 'url': 'https://github.com/Peterande/storage/releases/download/dfinev1.0/PPHGNetV2_B3_stage1.pth'
400
+ },
401
+ 'B4': {
402
+ 'stem_channels': [3, 32, 48],
403
+ 'stage_config': {
404
+ # in_channels, mid_channels, out_channels, num_blocks, downsample, light_block, kernel_size, layer_num
405
+ "stage1": [48, 48, 128, 1, False, False, 3, 6],
406
+ "stage2": [128, 96, 512, 1, True, False, 3, 6],
407
+ "stage3": [512, 192, 1024, 3, True, True, 5, 6],
408
+ "stage4": [1024, 384, 2048, 1, True, True, 5, 6],
409
+ },
410
+ 'url': 'https://github.com/Peterande/storage/releases/download/dfinev1.0/PPHGNetV2_B4_stage1.pth'
411
+ },
412
+ 'B5': {
413
+ 'stem_channels': [3, 32, 64],
414
+ 'stage_config': {
415
+ # in_channels, mid_channels, out_channels, num_blocks, downsample, light_block, kernel_size, layer_num
416
+ "stage1": [64, 64, 128, 1, False, False, 3, 6],
417
+ "stage2": [128, 128, 512, 2, True, False, 3, 6],
418
+ "stage3": [512, 256, 1024, 5, True, True, 5, 6],
419
+ "stage4": [1024, 512, 2048, 2, True, True, 5, 6],
420
+ },
421
+ 'url': 'https://github.com/Peterande/storage/releases/download/dfinev1.0/PPHGNetV2_B5_stage1.pth'
422
+ },
423
+ 'B6': {
424
+ 'stem_channels': [3, 48, 96],
425
+ 'stage_config': {
426
+ # in_channels, mid_channels, out_channels, num_blocks, downsample, light_block, kernel_size, layer_num
427
+ "stage1": [96, 96, 192, 2, False, False, 3, 6],
428
+ "stage2": [192, 192, 512, 3, True, False, 3, 6],
429
+ "stage3": [512, 384, 1024, 6, True, True, 5, 6],
430
+ "stage4": [1024, 768, 2048, 3, True, True, 5, 6],
431
+ },
432
+ 'url': 'https://github.com/Peterande/storage/releases/download/dfinev1.0/PPHGNetV2_B6_stage1.pth'
433
+ },
434
+ }
435
+
436
+ def __init__(self,
437
+ name,
438
+ use_lab=False,
439
+ return_idx=[1, 2, 3],
440
+ freeze_stem_only=True,
441
+ freeze_at=0,
442
+ freeze_norm=True,
443
+ pretrained=True,
444
+ local_model_dir='weight/hgnetv2/'):
445
+ super().__init__()
446
+ self.use_lab = use_lab
447
+ self.return_idx = return_idx
448
+
449
+ stem_channels = self.arch_configs[name]['stem_channels']
450
+ stage_config = self.arch_configs[name]['stage_config']
451
+ download_url = self.arch_configs[name]['url']
452
+
453
+ self._out_strides = [4, 8, 16, 32]
454
+ self._out_channels = [stage_config[k][2] for k in stage_config]
455
+
456
+ # stem
457
+ self.stem = StemBlock(
458
+ in_chs=stem_channels[0],
459
+ mid_chs=stem_channels[1],
460
+ out_chs=stem_channels[2],
461
+ use_lab=use_lab)
462
+
463
+ # stages
464
+ self.stages = nn.ModuleList()
465
+ for i, k in enumerate(stage_config):
466
+ in_channels, mid_channels, out_channels, block_num, downsample, light_block, kernel_size, layer_num = stage_config[
467
+ k]
468
+ self.stages.append(
469
+ HG_Stage(
470
+ in_channels,
471
+ mid_channels,
472
+ out_channels,
473
+ block_num,
474
+ layer_num,
475
+ downsample,
476
+ light_block,
477
+ kernel_size,
478
+ use_lab))
479
+
480
+ if freeze_at >= 0:
481
+ self._freeze_parameters(self.stem)
482
+ if not freeze_stem_only:
483
+ for i in range(min(freeze_at + 1, len(self.stages))):
484
+ self._freeze_parameters(self.stages[i])
485
+
486
+ if freeze_norm:
487
+ self._freeze_norm(self)
488
+
489
+ if pretrained:
490
+ RED, GREEN, RESET = "\033[91m", "\033[92m", "\033[0m"
491
+ try:
492
+ model_path = local_model_dir + 'PPHGNetV2_' + name + '_stage1.pth'
493
+ if os.path.exists(model_path):
494
+ state = torch.load(model_path, map_location='cpu')
495
+ print(f"Loaded stage1 {name} HGNetV2 from local file.")
496
+ else:
497
+ # If the file doesn't exist locally, download from the URL
498
+ if torch.distributed.get_rank() == 0:
499
+ print(GREEN + "If the pretrained HGNetV2 can't be downloaded automatically. Please check your network connection." + RESET)
500
+ print(GREEN + "Please check your network connection. Or download the model manually from " + RESET + f"{download_url}" + GREEN + " to " + RESET + f"{local_model_dir}." + RESET)
501
+ state = torch.hub.load_state_dict_from_url(download_url, map_location='cpu', model_dir=local_model_dir)
502
+ torch.distributed.barrier()
503
+ else:
504
+ torch.distributed.barrier()
505
+ state = torch.load(local_model_dir)
506
+
507
+ print(f"Loaded stage1 {name} HGNetV2 from URL.")
508
+
509
+ self.load_state_dict(state)
510
+
511
+ except (Exception, KeyboardInterrupt) as e:
512
+ if torch.distributed.get_rank() == 0:
513
+ print(f"{str(e)}")
514
+ logging.error(RED + "CRITICAL WARNING: Failed to load pretrained HGNetV2 model" + RESET)
515
+ logging.error(GREEN + "Please check your network connection. Or download the model manually from " \
516
+ + RESET + f"{download_url}" + GREEN + " to " + RESET + f"{local_model_dir}." + RESET)
517
+ exit()
518
+
519
+
520
+
521
+
522
+ def _freeze_norm(self, m: nn.Module):
523
+ if isinstance(m, nn.BatchNorm2d):
524
+ m = FrozenBatchNorm2d(m.num_features)
525
+ else:
526
+ for name, child in m.named_children():
527
+ _child = self._freeze_norm(child)
528
+ if _child is not child:
529
+ setattr(m, name, _child)
530
+ return m
531
+
532
+ def _freeze_parameters(self, m: nn.Module):
533
+ for p in m.parameters():
534
+ p.requires_grad = False
535
+
536
+ def forward(self, x):
537
+ x = self.stem(x)
538
+ outs = []
539
+ for idx, stage in enumerate(self.stages):
540
+ x = stage(x)
541
+ if idx in self.return_idx:
542
+ outs.append(x)
543
+ return outs
code/engine/backbone/presnet.py ADDED
@@ -0,0 +1,259 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Copied from RT-DETR (https://github.com/lyuwenyu/RT-DETR)
3
+ Copyright(c) 2023 lyuwenyu. All Rights Reserved.
4
+ """
5
+ import torch
6
+ import torch.nn as nn
7
+ import torch.nn.functional as F
8
+
9
+ from collections import OrderedDict
10
+
11
+ from .common import get_activation, FrozenBatchNorm2d
12
+
13
+ from ..core import register
14
+ import os
15
+
16
+
17
+ __all__ = ['PResNet']
18
+
19
+
20
+ ResNet_cfg = {
21
+ 18: [2, 2, 2, 2],
22
+ 34: [3, 4, 6, 3],
23
+ 50: [3, 4, 6, 3],
24
+ 101: [3, 4, 23, 3],
25
+ # 152: [3, 8, 36, 3],
26
+ }
27
+
28
+
29
+ donwload_url = {
30
+ 18: 'https://github.com/lyuwenyu/storage/releases/download/v0.1/ResNet18_vd_pretrained_from_paddle.pth',
31
+ 34: 'https://github.com/lyuwenyu/storage/releases/download/v0.1/ResNet34_vd_pretrained_from_paddle.pth',
32
+ 50: 'https://github.com/lyuwenyu/storage/releases/download/v0.1/ResNet50_vd_ssld_v2_pretrained_from_paddle.pth',
33
+ 101: 'https://github.com/lyuwenyu/storage/releases/download/v0.1/ResNet101_vd_ssld_pretrained_from_paddle.pth',
34
+ }
35
+
36
+ local_weights = {
37
+ 18: "ResNet18_vd_pretrained_from_paddle.pth",
38
+ 34: "ResNet34_vd_pretrained_from_paddle.pth",
39
+ 50: "ResNet50_vd_ssld_v2_pretrained_from_paddle.pth",
40
+ 101: "ResNet101_vd_ssld_pretrained_from_paddle.pth"
41
+ }
42
+
43
+ class ConvNormLayer(nn.Module):
44
+ def __init__(self, ch_in, ch_out, kernel_size, stride, padding=None, bias=False, act=None):
45
+ super().__init__()
46
+ self.conv = nn.Conv2d(
47
+ ch_in,
48
+ ch_out,
49
+ kernel_size,
50
+ stride,
51
+ padding=(kernel_size-1)//2 if padding is None else padding,
52
+ bias=bias)
53
+ self.norm = nn.BatchNorm2d(ch_out)
54
+ self.act = get_activation(act)
55
+
56
+ def forward(self, x):
57
+ return self.act(self.norm(self.conv(x)))
58
+
59
+
60
+ class BasicBlock(nn.Module):
61
+ expansion = 1
62
+
63
+ def __init__(self, ch_in, ch_out, stride, shortcut, act='relu', variant='b'):
64
+ super().__init__()
65
+
66
+ self.shortcut = shortcut
67
+
68
+ if not shortcut:
69
+ if variant == 'd' and stride == 2:
70
+ self.short = nn.Sequential(OrderedDict([
71
+ ('pool', nn.AvgPool2d(2, 2, 0, ceil_mode=True)),
72
+ ('conv', ConvNormLayer(ch_in, ch_out, 1, 1))
73
+ ]))
74
+ else:
75
+ self.short = ConvNormLayer(ch_in, ch_out, 1, stride)
76
+
77
+ self.branch2a = ConvNormLayer(ch_in, ch_out, 3, stride, act=act)
78
+ self.branch2b = ConvNormLayer(ch_out, ch_out, 3, 1, act=None)
79
+ self.act = nn.Identity() if act is None else get_activation(act)
80
+
81
+
82
+ def forward(self, x):
83
+ out = self.branch2a(x)
84
+ out = self.branch2b(out)
85
+ if self.shortcut:
86
+ short = x
87
+ else:
88
+ short = self.short(x)
89
+
90
+ out = out + short
91
+ out = self.act(out)
92
+
93
+ return out
94
+
95
+
96
+ class BottleNeck(nn.Module):
97
+ expansion = 4
98
+
99
+ def __init__(self, ch_in, ch_out, stride, shortcut, act='relu', variant='b'):
100
+ super().__init__()
101
+
102
+ if variant == 'a':
103
+ stride1, stride2 = stride, 1
104
+ else:
105
+ stride1, stride2 = 1, stride
106
+
107
+ width = ch_out
108
+
109
+ self.branch2a = ConvNormLayer(ch_in, width, 1, stride1, act=act)
110
+ self.branch2b = ConvNormLayer(width, width, 3, stride2, act=act)
111
+ self.branch2c = ConvNormLayer(width, ch_out * self.expansion, 1, 1)
112
+
113
+ self.shortcut = shortcut
114
+ if not shortcut:
115
+ if variant == 'd' and stride == 2:
116
+ self.short = nn.Sequential(OrderedDict([
117
+ ('pool', nn.AvgPool2d(2, 2, 0, ceil_mode=True)),
118
+ ('conv', ConvNormLayer(ch_in, ch_out * self.expansion, 1, 1))
119
+ ]))
120
+ else:
121
+ self.short = ConvNormLayer(ch_in, ch_out * self.expansion, 1, stride)
122
+
123
+ self.act = nn.Identity() if act is None else get_activation(act)
124
+
125
+ def forward(self, x):
126
+ out = self.branch2a(x)
127
+ out = self.branch2b(out)
128
+ out = self.branch2c(out)
129
+
130
+ if self.shortcut:
131
+ short = x
132
+ else:
133
+ short = self.short(x)
134
+
135
+ out = out + short
136
+ out = self.act(out)
137
+
138
+ return out
139
+
140
+
141
+ class Blocks(nn.Module):
142
+ def __init__(self, block, ch_in, ch_out, count, stage_num, act='relu', variant='b'):
143
+ super().__init__()
144
+
145
+ self.blocks = nn.ModuleList()
146
+ for i in range(count):
147
+ self.blocks.append(
148
+ block(
149
+ ch_in,
150
+ ch_out,
151
+ stride=2 if i == 0 and stage_num != 2 else 1,
152
+ shortcut=False if i == 0 else True,
153
+ variant=variant,
154
+ act=act)
155
+ )
156
+
157
+ if i == 0:
158
+ ch_in = ch_out * block.expansion
159
+
160
+ def forward(self, x):
161
+ out = x
162
+ for block in self.blocks:
163
+ out = block(out)
164
+ return out
165
+
166
+
167
+ @register()
168
+ class PResNet(nn.Module):
169
+ def __init__(
170
+ self,
171
+ depth,
172
+ variant='d',
173
+ num_stages=4,
174
+ return_idx=[0, 1, 2, 3],
175
+ act='relu',
176
+ freeze_at=-1,
177
+ freeze_norm=True,
178
+ pretrained=False,
179
+ local_model_dir='weights/resnets',
180
+ ):
181
+ super().__init__()
182
+
183
+ block_nums = ResNet_cfg[depth]
184
+ ch_in = 64
185
+ if variant in ['c', 'd']:
186
+ conv_def = [
187
+ [3, ch_in // 2, 3, 2, "conv1_1"],
188
+ [ch_in // 2, ch_in // 2, 3, 1, "conv1_2"],
189
+ [ch_in // 2, ch_in, 3, 1, "conv1_3"],
190
+ ]
191
+ else:
192
+ conv_def = [[3, ch_in, 7, 2, "conv1_1"]]
193
+
194
+ self.conv1 = nn.Sequential(OrderedDict([
195
+ (name, ConvNormLayer(cin, cout, k, s, act=act)) for cin, cout, k, s, name in conv_def
196
+ ]))
197
+
198
+ ch_out_list = [64, 128, 256, 512]
199
+ block = BottleNeck if depth >= 50 else BasicBlock
200
+
201
+ _out_channels = [block.expansion * v for v in ch_out_list]
202
+ _out_strides = [4, 8, 16, 32]
203
+
204
+ self.res_layers = nn.ModuleList()
205
+ for i in range(num_stages):
206
+ stage_num = i + 2
207
+ self.res_layers.append(
208
+ Blocks(block, ch_in, ch_out_list[i], block_nums[i], stage_num, act=act, variant=variant)
209
+ )
210
+ ch_in = _out_channels[i]
211
+
212
+ self.return_idx = return_idx
213
+ self.out_channels = [_out_channels[_i] for _i in return_idx]
214
+ self.out_strides = [_out_strides[_i] for _i in return_idx]
215
+
216
+ if freeze_at >= 0:
217
+ self._freeze_parameters(self.conv1)
218
+ for i in range(min(freeze_at, num_stages)):
219
+ self._freeze_parameters(self.res_layers[i])
220
+
221
+ if freeze_norm:
222
+ self._freeze_norm(self)
223
+
224
+ if pretrained:
225
+ model_path = local_model_dir + local_weights[depth]
226
+ if os.path.exists(model_path):
227
+ state = torch.load(model_path, map_location='cpu')
228
+ print(f"Loaded PResNet{depth} from local file@{model_path}.")
229
+ else:
230
+ if isinstance(pretrained, bool) or 'http' in pretrained:
231
+ state = torch.hub.load_state_dict_from_url(donwload_url[depth], map_location='cpu', model_dir=local_model_dir)
232
+ else:
233
+ state = torch.load(pretrained, map_location='cpu')
234
+ self.load_state_dict(state)
235
+ print(f'Load PResNet{depth} state_dict')
236
+
237
+ def _freeze_parameters(self, m: nn.Module):
238
+ for p in m.parameters():
239
+ p.requires_grad = False
240
+
241
+ def _freeze_norm(self, m: nn.Module):
242
+ if isinstance(m, nn.BatchNorm2d):
243
+ m = FrozenBatchNorm2d(m.num_features)
244
+ else:
245
+ for name, child in m.named_children():
246
+ _child = self._freeze_norm(child)
247
+ if _child is not child:
248
+ setattr(m, name, _child)
249
+ return m
250
+
251
+ def forward(self, x):
252
+ conv1 = self.conv1(x)
253
+ x = F.max_pool2d(conv1, kernel_size=3, stride=2, padding=1)
254
+ outs = []
255
+ for idx, stage in enumerate(self.res_layers):
256
+ x = stage(x)
257
+ if idx in self.return_idx:
258
+ outs.append(x)
259
+ return outs
code/engine/backbone/test_resnet.py ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torch.nn as nn
3
+ import torch.nn.functional as F
4
+
5
+ from collections import OrderedDict
6
+
7
+
8
+ from ..core import register
9
+
10
+
11
+ class BasicBlock(nn.Module):
12
+ expansion = 1
13
+
14
+ def __init__(self, in_planes, planes, stride=1):
15
+ super(BasicBlock, self).__init__()
16
+
17
+ self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=3, stride=stride, padding=1, bias=False)
18
+ self.bn1 = nn.BatchNorm2d(planes)
19
+
20
+ self.conv2 = nn.Conv2d(planes, planes, kernel_size=3,stride=1, padding=1, bias=False)
21
+ self.bn2 = nn.BatchNorm2d(planes)
22
+
23
+ self.shortcut = nn.Sequential()
24
+ if stride != 1 or in_planes != self.expansion*planes:
25
+ self.shortcut = nn.Sequential(
26
+ nn.Conv2d(in_planes, self.expansion*planes,kernel_size=1, stride=stride, bias=False),
27
+ nn.BatchNorm2d(self.expansion*planes)
28
+ )
29
+ def forward(self, x):
30
+ out = F.relu(self.bn1(self.conv1(x)))
31
+ out = self.bn2(self.conv2(out))
32
+ out += self.shortcut(x)
33
+ out = F.relu(out)
34
+ return out
35
+
36
+
37
+
38
+ class _ResNet(nn.Module):
39
+ def __init__(self, block, num_blocks, num_classes=10):
40
+ super().__init__()
41
+ self.in_planes = 64
42
+
43
+ self.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False)
44
+ self.bn1 = nn.BatchNorm2d(64)
45
+
46
+ self.layer1 = self._make_layer(block, 64, num_blocks[0], stride=1)
47
+ self.layer2 = self._make_layer(block, 128, num_blocks[1], stride=2)
48
+ self.layer3 = self._make_layer(block, 256, num_blocks[2], stride=2)
49
+ self.layer4 = self._make_layer(block, 512, num_blocks[3], stride=2)
50
+
51
+ self.linear = nn.Linear(512 * block.expansion, num_classes)
52
+
53
+ def _make_layer(self, block, planes, num_blocks, stride):
54
+ strides = [stride] + [1]*(num_blocks-1)
55
+ layers = []
56
+ for stride in strides:
57
+ layers.append(block(self.in_planes, planes, stride))
58
+ self.in_planes = planes * block.expansion
59
+ return nn.Sequential(*layers)
60
+
61
+ def forward(self, x):
62
+ out = F.relu(self.bn1(self.conv1(x)))
63
+ out = self.layer1(out)
64
+ out = self.layer2(out)
65
+ out = self.layer3(out)
66
+ out = self.layer4(out)
67
+ out = F.avg_pool2d(out, 4)
68
+ out = out.view(out.size(0), -1)
69
+ out = self.linear(out)
70
+ return out
71
+
72
+
73
+ @register()
74
+ class MResNet(nn.Module):
75
+ def __init__(self, num_classes=10, num_blocks=[2, 2, 2, 2]) -> None:
76
+ super().__init__()
77
+ self.model = _ResNet(BasicBlock, num_blocks, num_classes)
78
+
79
+ def forward(self, x):
80
+ return self.model(x)
code/engine/backbone/timm_model.py ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Copyright(c) 2023 lyuwenyu. All Rights Reserved.
2
+
3
+ https://towardsdatascience.com/getting-started-with-pytorch-image-models-timm-a-practitioners-guide-4e77b4bf9055#0583
4
+ """
5
+ import torch
6
+ from torchvision.models.feature_extraction import get_graph_node_names, create_feature_extractor
7
+
8
+ from .utils import IntermediateLayerGetter
9
+ from ..core import register
10
+
11
+
12
+ @register()
13
+ class TimmModel(torch.nn.Module):
14
+ def __init__(self, \
15
+ name,
16
+ return_layers,
17
+ pretrained=False,
18
+ exportable=True,
19
+ features_only=True,
20
+ **kwargs) -> None:
21
+
22
+ super().__init__()
23
+
24
+ import timm
25
+ model = timm.create_model(
26
+ name,
27
+ pretrained=pretrained,
28
+ exportable=exportable,
29
+ features_only=features_only,
30
+ **kwargs
31
+ )
32
+ # nodes, _ = get_graph_node_names(model)
33
+ # print(nodes)
34
+ # features = {'': ''}
35
+ # model = create_feature_extractor(model, return_nodes=features)
36
+
37
+ assert set(return_layers).issubset(model.feature_info.module_name()), \
38
+ f'return_layers should be a subset of {model.feature_info.module_name()}'
39
+
40
+ # self.model = model
41
+ self.model = IntermediateLayerGetter(model, return_layers)
42
+
43
+ return_idx = [model.feature_info.module_name().index(name) for name in return_layers]
44
+ self.strides = [model.feature_info.reduction()[i] for i in return_idx]
45
+ self.channels = [model.feature_info.channels()[i] for i in return_idx]
46
+ self.return_idx = return_idx
47
+ self.return_layers = return_layers
48
+
49
+ def forward(self, x: torch.Tensor):
50
+ outputs = self.model(x)
51
+ # outputs = [outputs[i] for i in self.return_idx]
52
+ return outputs
53
+
54
+
55
+ if __name__ == '__main__':
56
+
57
+ model = TimmModel(name='resnet34', return_layers=['layer2', 'layer3'])
58
+ data = torch.rand(1, 3, 640, 640)
59
+ outputs = model(data)
60
+
61
+ for output in outputs:
62
+ print(output.shape)
63
+
64
+ """
65
+ model:
66
+ type: TimmModel
67
+ name: resnet34
68
+ return_layers: ['layer2', 'layer4']
69
+ """
code/engine/backbone/torchvision_model.py ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Copied from RT-DETR (https://github.com/lyuwenyu/RT-DETR)
3
+ Copyright(c) 2023 lyuwenyu. All Rights Reserved.
4
+ """
5
+
6
+ import torch
7
+ import torchvision
8
+
9
+ from ..core import register
10
+ from .utils import IntermediateLayerGetter
11
+
12
+ __all__ = ['TorchVisionModel']
13
+
14
+ @register()
15
+ class TorchVisionModel(torch.nn.Module):
16
+ def __init__(self, name, return_layers, weights=None, **kwargs) -> None:
17
+ super().__init__()
18
+
19
+ if weights is not None:
20
+ weights = getattr(torchvision.models.get_model_weights(name), weights)
21
+
22
+ model = torchvision.models.get_model(name, weights=weights, **kwargs)
23
+
24
+ # TODO hard code.
25
+ if hasattr(model, 'features'):
26
+ model = IntermediateLayerGetter(model.features, return_layers)
27
+ else:
28
+ model = IntermediateLayerGetter(model, return_layers)
29
+
30
+ self.model = model
31
+
32
+ def forward(self, x):
33
+ return self.model(x)
34
+
35
+
36
+ # TorchVisionModel('swin_t', return_layers=['5', '7'])
37
+ # TorchVisionModel('resnet34', return_layers=['layer2','layer3', 'layer4'])
38
+
39
+ # TorchVisionModel:
40
+ # name: swin_t
41
+ # return_layers: ['5', '7']
42
+ # weights: DEFAULT
43
+
44
+
45
+ # model:
46
+ # type: TorchVisionModel
47
+ # name: resnet34
48
+ # return_layers: ['layer2','layer3', 'layer4']
49
+ # weights: DEFAULT
code/engine/backbone/utils.py ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ https://github.com/pytorch/vision/blob/main/torchvision/models/_utils.py
3
+
4
+ Copyright(c) 2023 lyuwenyu. All Rights Reserved.
5
+ """
6
+
7
+ from collections import OrderedDict
8
+ from typing import Dict, List
9
+
10
+
11
+ import torch.nn as nn
12
+
13
+
14
+ class IntermediateLayerGetter(nn.ModuleDict):
15
+ """
16
+ Module wrapper that returns intermediate layers from a model
17
+
18
+ It has a strong assumption that the modules have been registered
19
+ into the model in the same order as they are used.
20
+ This means that one should **not** reuse the same nn.Module
21
+ twice in the forward if you want this to work.
22
+
23
+ Additionally, it is only able to query submodules that are directly
24
+ assigned to the model. So if `model` is passed, `model.feature1` can
25
+ be returned, but not `model.feature1.layer2`.
26
+ """
27
+
28
+ _version = 3
29
+
30
+ def __init__(self, model: nn.Module, return_layers: List[str]) -> None:
31
+ if not set(return_layers).issubset([name for name, _ in model.named_children()]):
32
+ raise ValueError("return_layers are not present in model. {}"\
33
+ .format([name for name, _ in model.named_children()]))
34
+ orig_return_layers = return_layers
35
+ return_layers = {str(k): str(k) for k in return_layers}
36
+ layers = OrderedDict()
37
+ for name, module in model.named_children():
38
+ layers[name] = module
39
+ if name in return_layers:
40
+ del return_layers[name]
41
+ if not return_layers:
42
+ break
43
+
44
+ super().__init__(layers)
45
+ self.return_layers = orig_return_layers
46
+
47
+ def forward(self, x):
48
+ outputs = []
49
+ for name, module in self.items():
50
+ x = module(x)
51
+ if name in self.return_layers:
52
+ outputs.append(x)
53
+
54
+ return outputs
code/engine/core/__init__.py ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Copied from RT-DETR (https://github.com/lyuwenyu/RT-DETR)
3
+ Copyright(c) 2023 lyuwenyu. All Rights Reserved.
4
+ """
5
+
6
+ from .workspace import GLOBAL_CONFIG, register, create
7
+ from .yaml_utils import *
8
+ from ._config import BaseConfig
9
+ from .yaml_config import YAMLConfig
code/engine/core/_config.py ADDED
@@ -0,0 +1,299 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Copied from RT-DETR (https://github.com/lyuwenyu/RT-DETR)
3
+ Copyright(c) 2023 lyuwenyu. All Rights Reserved.
4
+ """
5
+
6
+ import torch
7
+ import torch.nn as nn
8
+ from torch.utils.data import Dataset, DataLoader
9
+ from torch.optim import Optimizer
10
+ from torch.optim.lr_scheduler import LRScheduler
11
+ from torch.cuda.amp.grad_scaler import GradScaler
12
+ from torch.utils.tensorboard import SummaryWriter
13
+
14
+ from pathlib import Path
15
+ from typing import Callable, List, Dict
16
+
17
+
18
+ __all__ = ['BaseConfig', ]
19
+
20
+
21
+ class BaseConfig(object):
22
+ # TODO property
23
+
24
+ def __init__(self) -> None:
25
+ super().__init__()
26
+
27
+ self.task :str = None
28
+
29
+ # instance / function
30
+ self._model :nn.Module = None
31
+ self._postprocessor :nn.Module = None
32
+ self._criterion :nn.Module = None
33
+ self._optimizer :Optimizer = None
34
+ self._lr_scheduler :LRScheduler = None
35
+ self._lr_warmup_scheduler: LRScheduler = None
36
+ self._train_dataloader :DataLoader = None
37
+ self._val_dataloader :DataLoader = None
38
+ self._ema :nn.Module = None
39
+ self._scaler :GradScaler = None
40
+ self._train_dataset :Dataset = None
41
+ self._val_dataset :Dataset = None
42
+ self._collate_fn :Callable = None
43
+ self._evaluator :Callable[[nn.Module, DataLoader, str], ] = None
44
+ self._writer: SummaryWriter = None
45
+
46
+ # dataset
47
+ self.num_workers :int = 0
48
+ self.batch_size :int = None
49
+ self._train_batch_size :int = None
50
+ self._val_batch_size :int = None
51
+ self._train_shuffle: bool = None
52
+ self._val_shuffle: bool = None
53
+
54
+ # runtime
55
+ self.resume :str = None
56
+ self.tuning :str = None
57
+
58
+ self.epoches :int = None
59
+ self.last_epoch :int = -1
60
+
61
+ # new_add for support self-defined cosine FIXME
62
+ self.lrsheduler: str = None
63
+ self.lr_gamma: float = None
64
+ self.no_aug_epoch: int = None
65
+ self.warmup_iter: int = None
66
+ self.flat_epoch: int = None
67
+
68
+ self.use_amp :bool = False
69
+ self.use_ema :bool = False
70
+ self.ema_decay :float = 0.9999
71
+ self.ema_warmups: int = 2000
72
+ self.sync_bn :bool = False
73
+ self.clip_max_norm : float = 0.
74
+ self.find_unused_parameters :bool = None
75
+
76
+ self.seed :int = None
77
+ self.print_freq :int = None
78
+ self.checkpoint_freq :int = 1
79
+ self.output_dir :str = None
80
+ self.summary_dir :str = None
81
+ self.device : str = ''
82
+
83
+ @property
84
+ def model(self, ) -> nn.Module:
85
+ return self._model
86
+
87
+ @model.setter
88
+ def model(self, m):
89
+ assert isinstance(m, nn.Module), f'{type(m)} != nn.Module, please check your model class'
90
+ self._model = m
91
+
92
+ @property
93
+ def postprocessor(self, ) -> nn.Module:
94
+ return self._postprocessor
95
+
96
+ @postprocessor.setter
97
+ def postprocessor(self, m):
98
+ assert isinstance(m, nn.Module), f'{type(m)} != nn.Module, please check your model class'
99
+ self._postprocessor = m
100
+
101
+ @property
102
+ def criterion(self, ) -> nn.Module:
103
+ return self._criterion
104
+
105
+ @criterion.setter
106
+ def criterion(self, m):
107
+ assert isinstance(m, nn.Module), f'{type(m)} != nn.Module, please check your model class'
108
+ self._criterion = m
109
+
110
+ @property
111
+ def optimizer(self, ) -> Optimizer:
112
+ return self._optimizer
113
+
114
+ @optimizer.setter
115
+ def optimizer(self, m):
116
+ assert isinstance(m, Optimizer), f'{type(m)} != optim.Optimizer, please check your model class'
117
+ self._optimizer = m
118
+
119
+ @property
120
+ def lr_scheduler(self, ) -> LRScheduler:
121
+ return self._lr_scheduler
122
+
123
+ @lr_scheduler.setter
124
+ def lr_scheduler(self, m):
125
+ assert isinstance(m, LRScheduler), f'{type(m)} != LRScheduler, please check your model class'
126
+ self._lr_scheduler = m
127
+
128
+ @property
129
+ def lr_warmup_scheduler(self, ) -> LRScheduler:
130
+ return self._lr_warmup_scheduler
131
+
132
+ @lr_warmup_scheduler.setter
133
+ def lr_warmup_scheduler(self, m):
134
+ self._lr_warmup_scheduler = m
135
+
136
+ @property
137
+ def train_dataloader(self) -> DataLoader:
138
+ if self._train_dataloader is None and self.train_dataset is not None:
139
+ loader = DataLoader(self.train_dataset,
140
+ batch_size=self.train_batch_size,
141
+ num_workers=self.num_workers,
142
+ collate_fn=self.collate_fn,
143
+ shuffle=self.train_shuffle, )
144
+ loader.shuffle = self.train_shuffle
145
+ self._train_dataloader = loader
146
+
147
+ return self._train_dataloader
148
+
149
+ @train_dataloader.setter
150
+ def train_dataloader(self, loader):
151
+ self._train_dataloader = loader
152
+
153
+ @property
154
+ def val_dataloader(self) -> DataLoader:
155
+ if self._val_dataloader is None and self.val_dataset is not None:
156
+ loader = DataLoader(self.val_dataset,
157
+ batch_size=self.val_batch_size,
158
+ num_workers=self.num_workers,
159
+ drop_last=False,
160
+ collate_fn=self.collate_fn,
161
+ shuffle=self.val_shuffle,
162
+ persistent_workers=True)
163
+ loader.shuffle = self.val_shuffle
164
+ self._val_dataloader = loader
165
+
166
+ return self._val_dataloader
167
+
168
+ @val_dataloader.setter
169
+ def val_dataloader(self, loader):
170
+ self._val_dataloader = loader
171
+
172
+ @property
173
+ def ema(self, ) -> nn.Module:
174
+ if self._ema is None and self.use_ema and self.model is not None:
175
+ from ..optim import ModelEMA
176
+ self._ema = ModelEMA(self.model, self.ema_decay, self.ema_warmups)
177
+ return self._ema
178
+
179
+ @ema.setter
180
+ def ema(self, obj):
181
+ self._ema = obj
182
+
183
+ @property
184
+ def scaler(self) -> GradScaler:
185
+ if self._scaler is None and self.use_amp and torch.cuda.is_available():
186
+ self._scaler = GradScaler()
187
+ return self._scaler
188
+
189
+ @scaler.setter
190
+ def scaler(self, obj: GradScaler):
191
+ self._scaler = obj
192
+
193
+ @property
194
+ def val_shuffle(self) -> bool:
195
+ if self._val_shuffle is None:
196
+ print('warning: set default val_shuffle=False')
197
+ return False
198
+ return self._val_shuffle
199
+
200
+ @val_shuffle.setter
201
+ def val_shuffle(self, shuffle):
202
+ assert isinstance(shuffle, bool), 'shuffle must be bool'
203
+ self._val_shuffle = shuffle
204
+
205
+ @property
206
+ def train_shuffle(self) -> bool:
207
+ if self._train_shuffle is None:
208
+ print('warning: set default train_shuffle=True')
209
+ return True
210
+ return self._train_shuffle
211
+
212
+ @train_shuffle.setter
213
+ def train_shuffle(self, shuffle):
214
+ assert isinstance(shuffle, bool), 'shuffle must be bool'
215
+ self._train_shuffle = shuffle
216
+
217
+
218
+ @property
219
+ def train_batch_size(self) -> int:
220
+ if self._train_batch_size is None and isinstance(self.batch_size, int):
221
+ print(f'warning: set train_batch_size=batch_size={self.batch_size}')
222
+ return self.batch_size
223
+ return self._train_batch_size
224
+
225
+ @train_batch_size.setter
226
+ def train_batch_size(self, batch_size):
227
+ assert isinstance(batch_size, int), 'batch_size must be int'
228
+ self._train_batch_size = batch_size
229
+
230
+ @property
231
+ def val_batch_size(self) -> int:
232
+ if self._val_batch_size is None:
233
+ print(f'warning: set val_batch_size=batch_size={self.batch_size}')
234
+ return self.batch_size
235
+ return self._val_batch_size
236
+
237
+ @val_batch_size.setter
238
+ def val_batch_size(self, batch_size):
239
+ assert isinstance(batch_size, int), 'batch_size must be int'
240
+ self._val_batch_size = batch_size
241
+
242
+
243
+ @property
244
+ def train_dataset(self) -> Dataset:
245
+ return self._train_dataset
246
+
247
+ @train_dataset.setter
248
+ def train_dataset(self, dataset):
249
+ assert isinstance(dataset, Dataset), f'{type(dataset)} must be Dataset'
250
+ self._train_dataset = dataset
251
+
252
+
253
+ @property
254
+ def val_dataset(self) -> Dataset:
255
+ return self._val_dataset
256
+
257
+ @val_dataset.setter
258
+ def val_dataset(self, dataset):
259
+ assert isinstance(dataset, Dataset), f'{type(dataset)} must be Dataset'
260
+ self._val_dataset = dataset
261
+
262
+ @property
263
+ def collate_fn(self) -> Callable:
264
+ return self._collate_fn
265
+
266
+ @collate_fn.setter
267
+ def collate_fn(self, fn):
268
+ assert isinstance(fn, Callable), f'{type(fn)} must be Callable'
269
+ self._collate_fn = fn
270
+
271
+ @property
272
+ def evaluator(self) -> Callable:
273
+ return self._evaluator
274
+
275
+ @evaluator.setter
276
+ def evaluator(self, fn):
277
+ assert isinstance(fn, Callable), f'{type(fn)} must be Callable'
278
+ self._evaluator = fn
279
+
280
+ @property
281
+ def writer(self) -> SummaryWriter:
282
+ if self._writer is None:
283
+ if self.summary_dir:
284
+ self._writer = SummaryWriter(self.summary_dir)
285
+ elif self.output_dir:
286
+ self._writer = SummaryWriter(Path(self.output_dir) / 'summary')
287
+ return self._writer
288
+
289
+ @writer.setter
290
+ def writer(self, m):
291
+ assert isinstance(m, SummaryWriter), f'{type(m)} must be SummaryWriter'
292
+ self._writer = m
293
+
294
+ def __repr__(self, ):
295
+ s = ''
296
+ for k, v in self.__dict__.items():
297
+ if not k.startswith('_'):
298
+ s += f'{k}: {v}\n'
299
+ return s
code/engine/core/workspace.py ADDED
@@ -0,0 +1,180 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Copied from RT-DETR (https://github.com/lyuwenyu/RT-DETR)
3
+ Copyright(c) 2023 lyuwenyu. All Rights Reserved.
4
+ """
5
+
6
+ import inspect
7
+ import importlib
8
+ import functools
9
+ from collections import defaultdict
10
+ from typing import Any, Dict, Optional, List
11
+
12
+
13
+ GLOBAL_CONFIG = defaultdict(dict)
14
+
15
+
16
+ def register(dct :Any=GLOBAL_CONFIG, name=None, force=False):
17
+ """
18
+ dct:
19
+ if dct is Dict, register foo into dct as key-value pair
20
+ if dct is Clas, register as modules attibute
21
+ force
22
+ whether force register.
23
+ """
24
+ def decorator(foo):
25
+ register_name = foo.__name__ if name is None else name
26
+ if not force:
27
+ if inspect.isclass(dct):
28
+ assert not hasattr(dct, foo.__name__), \
29
+ f'module {dct.__name__} has {foo.__name__}'
30
+ else:
31
+ assert foo.__name__ not in dct, \
32
+ f'{foo.__name__} has been already registered'
33
+
34
+ if inspect.isfunction(foo):
35
+ @functools.wraps(foo)
36
+ def wrap_func(*args, **kwargs):
37
+ return foo(*args, **kwargs)
38
+ if isinstance(dct, dict):
39
+ dct[foo.__name__] = wrap_func
40
+ elif inspect.isclass(dct):
41
+ setattr(dct, foo.__name__, wrap_func)
42
+ else:
43
+ raise AttributeError('')
44
+ return wrap_func
45
+
46
+ elif inspect.isclass(foo):
47
+ dct[register_name] = extract_schema(foo)
48
+
49
+ else:
50
+ raise ValueError(f'Do not support {type(foo)} register')
51
+
52
+ return foo
53
+
54
+ return decorator
55
+
56
+
57
+
58
+ def extract_schema(module: type):
59
+ """
60
+ Args:
61
+ module (type),
62
+ Return:
63
+ Dict,
64
+ """
65
+ argspec = inspect.getfullargspec(module.__init__)
66
+ arg_names = [arg for arg in argspec.args if arg != 'self']
67
+ num_defualts = len(argspec.defaults) if argspec.defaults is not None else 0
68
+ num_requires = len(arg_names) - num_defualts
69
+
70
+ schame = dict()
71
+ schame['_name'] = module.__name__
72
+ schame['_pymodule'] = importlib.import_module(module.__module__)
73
+ schame['_inject'] = getattr(module, '__inject__', [])
74
+ schame['_share'] = getattr(module, '__share__', [])
75
+ schame['_kwargs'] = {}
76
+ for i, name in enumerate(arg_names):
77
+ if name in schame['_share']:
78
+ assert i >= num_requires, 'share config must have default value.'
79
+ value = argspec.defaults[i - num_requires]
80
+
81
+ elif i >= num_requires:
82
+ value = argspec.defaults[i - num_requires]
83
+
84
+ else:
85
+ value = None
86
+
87
+ schame[name] = value
88
+ schame['_kwargs'][name] = value
89
+
90
+ return schame
91
+
92
+
93
+ def create(type_or_name, global_cfg=GLOBAL_CONFIG, **kwargs):
94
+ """
95
+ """
96
+ assert type(type_or_name) in (type, str), 'create should be modules or name.'
97
+
98
+ name = type_or_name if isinstance(type_or_name, str) else type_or_name.__name__
99
+
100
+ if name in global_cfg:
101
+ if hasattr(global_cfg[name], '__dict__'):
102
+ return global_cfg[name]
103
+ else:
104
+ raise ValueError('The module {} is not registered'.format(name))
105
+
106
+ cfg = global_cfg[name]
107
+
108
+ if isinstance(cfg, dict) and 'type' in cfg:
109
+ _cfg: dict = global_cfg[cfg['type']]
110
+ # clean args
111
+ _keys = [k for k in _cfg.keys() if not k.startswith('_')]
112
+ for _arg in _keys:
113
+ del _cfg[_arg]
114
+ _cfg.update(_cfg['_kwargs']) # restore default args
115
+ _cfg.update(cfg) # load config args
116
+ _cfg.update(kwargs) # TODO recive extra kwargs
117
+ name = _cfg.pop('type') # pop extra key `type` (from cfg)
118
+
119
+ return create(name, global_cfg)
120
+
121
+ module = getattr(cfg['_pymodule'], name)
122
+ module_kwargs = {}
123
+ module_kwargs.update(cfg)
124
+
125
+ # shared var
126
+ for k in cfg['_share']:
127
+ if k in global_cfg:
128
+ module_kwargs[k] = global_cfg[k]
129
+ else:
130
+ module_kwargs[k] = cfg[k]
131
+
132
+ # inject
133
+ for k in cfg['_inject']:
134
+ _k = cfg[k]
135
+
136
+ if _k is None:
137
+ continue
138
+
139
+ if isinstance(_k, str):
140
+ if _k not in global_cfg:
141
+ raise ValueError(f'Missing inject config of {_k}.')
142
+
143
+ _cfg = global_cfg[_k]
144
+
145
+ if isinstance(_cfg, dict):
146
+ module_kwargs[k] = create(_cfg['_name'], global_cfg)
147
+ else:
148
+ module_kwargs[k] = _cfg
149
+
150
+ elif isinstance(_k, dict):
151
+ if 'type' not in _k.keys():
152
+ raise ValueError('Missing inject for `type` style.')
153
+
154
+ _type = str(_k['type'])
155
+ if _type not in global_cfg:
156
+ raise ValueError(f'Missing {_type} in inspect stage.')
157
+
158
+ # TODO
159
+ _cfg: dict = global_cfg[_type]
160
+ # clean args
161
+ _keys = [k for k in _cfg.keys() if not k.startswith('_')]
162
+ for _arg in _keys:
163
+ del _cfg[_arg]
164
+ _cfg.update(_cfg['_kwargs']) # restore default values
165
+ _cfg.update(_k) # load config args
166
+ name = _cfg.pop('type') # pop extra key (`type` from _k)
167
+ module_kwargs[k] = create(name, global_cfg)
168
+
169
+ else:
170
+ raise ValueError(f'Inject does not support {_k}')
171
+
172
+ # TODO hard code
173
+ module_kwargs = {k: v for k, v in module_kwargs.items() if not k.startswith('_')}
174
+
175
+ # TODO for **kwargs
176
+ # extra_args = set(module_kwargs.keys()) - set(arg_names)
177
+ # if len(extra_args) > 0:
178
+ # raise RuntimeError(f'Error: unknown args {extra_args} for {module}')
179
+
180
+ return module(**module_kwargs)