lucytuan commited on
Commit
d15523e
Β·
2 Parent(s): d1aff91 91f2300

Merge branch 'MODEL' of github.com:LucyTuan/yolov9mit into MODEL

Browse files
yolo/model/module.py CHANGED
@@ -1,10 +1,10 @@
1
- from typing import Any, Dict, Optional, Tuple
2
 
3
  import torch
4
  from torch import Tensor, nn
5
  from torch.nn.common_types import _size_2_t
6
 
7
- from yolo.tools.module_helper import auto_pad, get_activation
8
 
9
 
10
  class Conv(nn.Module):
@@ -99,6 +99,47 @@ class SPPELAN(nn.Module):
99
  #### -- ####
100
 
101
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102
  # RepVGG
103
  class RepConv(nn.Module):
104
  """A convolutional block that combines two convolution layers (kernel and point-wise)."""
 
1
+ from typing import Any, Dict, List, Optional, Tuple
2
 
3
  import torch
4
  from torch import Tensor, nn
5
  from torch.nn.common_types import _size_2_t
6
 
7
+ from yolo.tools.module_helper import auto_pad, get_activation, round_up
8
 
9
 
10
  class Conv(nn.Module):
 
99
  #### -- ####
100
 
101
 
102
+ class Detection(nn.Module):
103
+ """A single YOLO Detection head for detection models"""
104
+
105
+ def __init__(self, in_channels: int, num_classes: int, *, reg_max: int = 16, use_group: bool = True):
106
+ super().__init__()
107
+
108
+ groups = 4 if use_group else 1
109
+ anchor_channels = 4 * reg_max
110
+ # TODO: round up head[0] channels or each head?
111
+ anchor_neck = max(round_up(in_channels // 4, groups), anchor_channels, 16)
112
+ class_neck = max(in_channels, min(num_classes * 2, 128))
113
+
114
+ self.anchor_conv = nn.Sequential(
115
+ Conv(in_channels, anchor_neck, 3),
116
+ Conv(anchor_neck, anchor_neck, 3, groups=groups),
117
+ nn.Conv2d(anchor_neck, anchor_channels, 1, groups=groups),
118
+ )
119
+ self.class_conv = nn.Sequential(
120
+ Conv(in_channels, class_neck, 3), Conv(class_neck, class_neck, 3), nn.Conv2d(class_neck, num_classes, 1)
121
+ )
122
+
123
+ def forward(self, x: List[Tensor]) -> List[Tensor]:
124
+ anchor_x = self.anchor_conv(x)
125
+ class_x = self.class_conv(x)
126
+ return torch.cat([anchor_x, class_x], dim=1)
127
+
128
+
129
+ class MultiheadDetection(nn.Module):
130
+ """Mutlihead Detection module for Dual detect or Triple detect"""
131
+
132
+ def __init__(self, in_channels: List[int], num_classes: int, **head_kwargs):
133
+ super().__init__()
134
+ self.heads = nn.ModuleList(
135
+ [Detection(head_in_channels, num_classes, **head_kwargs) for head_in_channels in in_channels]
136
+ )
137
+
138
+ def forward(self, x_list: List[torch.Tensor]) -> List[torch.Tensor]:
139
+ return [head(x) for x, head in zip(x_list, self.heads)]
140
+
141
+
142
+ #### -- ####
143
  # RepVGG
144
  class RepConv(nn.Module):
145
  """A convolutional block that combines two convolution layers (kernel and point-wise)."""
yolo/model/yolo.py CHANGED
@@ -27,8 +27,9 @@ class YOLO(nn.Module):
27
  model_list = nn.ModuleList()
28
  output_dim = [3]
29
  layer_indices_by_tag = {}
 
30
  for arch_name in model_arch:
31
- logger.info(f"πŸ—οΈ Building model-{arch_name}")
32
  for layer_idx, layer_spec in enumerate(model_arch[arch_name], start=1):
33
  layer_type, layer_info = next(iter(layer_spec.items()))
34
  layer_args = layer_info.get("args", {})
@@ -102,9 +103,3 @@ def get_model(model_cfg: dict) -> YOLO:
102
  model = YOLO(model_cfg)
103
  logger.info("βœ… Success load model")
104
  return model
105
-
106
-
107
- if __name__ == "__main__":
108
- model_cfg = load_model_cfg("v7-base")
109
-
110
- YOLO(model_cfg)
 
27
  model_list = nn.ModuleList()
28
  output_dim = [3]
29
  layer_indices_by_tag = {}
30
+ logger.info(f"🚜 Building YOLO")
31
  for arch_name in model_arch:
32
+ logger.info(f" πŸ—οΈ Building {arch_name}")
33
  for layer_idx, layer_spec in enumerate(model_arch[arch_name], start=1):
34
  layer_type, layer_info = next(iter(layer_spec.items()))
35
  layer_args = layer_info.get("args", {})
 
103
  model = YOLO(model_cfg)
104
  logger.info("βœ… Success load model")
105
  return model
 
 
 
 
 
 
yolo/tools/module_helper.py CHANGED
@@ -1,6 +1,6 @@
1
- from typing import Tuple
2
 
3
- from torch import nn
4
  from torch.nn.common_types import _size_2_t
5
 
6
 
@@ -34,3 +34,27 @@ def get_activation(activation: str) -> nn.Module:
34
  return activation_map[activation.lower()]()
35
  else:
36
  raise ValueError(f"Activation function '{activation}' is not found in torch.nn")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Tuple, Union
2
 
3
+ from torch import Tensor, nn
4
  from torch.nn.common_types import _size_2_t
5
 
6
 
 
34
  return activation_map[activation.lower()]()
35
  else:
36
  raise ValueError(f"Activation function '{activation}' is not found in torch.nn")
37
+
38
+
39
+ def round_up(x: Union[int, Tensor], div: int = 1) -> Union[int, Tensor]:
40
+ """
41
+ Rounds up `x` to the bigger-nearest multiple of `div`.
42
+ """
43
+ return x + (-x % div)
44
+
45
+
46
+ def make_chunk(input_list, chunk_num):
47
+ """
48
+ Args: input_list: [0, 1, 2, 3, 4, 5], chunk: 2
49
+ Return: [[0, 1, 2], [3, 4, 5]]
50
+ """
51
+ list_size = len(input_list)
52
+
53
+ if list_size % chunk_num != 0:
54
+ raise ValueError(
55
+ f"The length of the input list ({list_size}) must be exactly\
56
+ divisible by the number of chunks ({chunk_num})."
57
+ )
58
+
59
+ chunk_size = list_size // chunk_num
60
+ return [input_list[i : i + chunk_size] for i in range(0, list_size, chunk_size)]