Module `super().__init__()` (#4065)
Browse files* Module `super().__init__()`
* remove NMS
- models/common.py +18 -24
- models/experimental.py +6 -6
- models/yolo.py +3 -17
models/common.py
CHANGED
@@ -36,7 +36,7 @@ def DWConv(c1, c2, k=1, s=1, act=True):
|
|
36 |
class Conv(nn.Module):
|
37 |
# Standard convolution
|
38 |
def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True): # ch_in, ch_out, kernel, stride, padding, groups
|
39 |
-
super(
|
40 |
self.conv = nn.Conv2d(c1, c2, k, s, autopad(k, p), groups=g, bias=False)
|
41 |
self.bn = nn.BatchNorm2d(c2)
|
42 |
self.act = nn.SiLU() if act is True else (act if isinstance(act, nn.Module) else nn.Identity())
|
@@ -87,7 +87,7 @@ class TransformerBlock(nn.Module):
|
|
87 |
class Bottleneck(nn.Module):
|
88 |
# Standard bottleneck
|
89 |
def __init__(self, c1, c2, shortcut=True, g=1, e=0.5): # ch_in, ch_out, shortcut, groups, expansion
|
90 |
-
super(
|
91 |
c_ = int(c2 * e) # hidden channels
|
92 |
self.cv1 = Conv(c1, c_, 1, 1)
|
93 |
self.cv2 = Conv(c_, c2, 3, 1, g=g)
|
@@ -100,7 +100,7 @@ class Bottleneck(nn.Module):
|
|
100 |
class BottleneckCSP(nn.Module):
|
101 |
# CSP Bottleneck https://github.com/WongKinYiu/CrossStagePartialNetworks
|
102 |
def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): # ch_in, ch_out, number, shortcut, groups, expansion
|
103 |
-
super(
|
104 |
c_ = int(c2 * e) # hidden channels
|
105 |
self.cv1 = Conv(c1, c_, 1, 1)
|
106 |
self.cv2 = nn.Conv2d(c1, c_, 1, 1, bias=False)
|
@@ -119,7 +119,7 @@ class BottleneckCSP(nn.Module):
|
|
119 |
class C3(nn.Module):
|
120 |
# CSP Bottleneck with 3 convolutions
|
121 |
def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): # ch_in, ch_out, number, shortcut, groups, expansion
|
122 |
-
super(
|
123 |
c_ = int(c2 * e) # hidden channels
|
124 |
self.cv1 = Conv(c1, c_, 1, 1)
|
125 |
self.cv2 = Conv(c1, c_, 1, 1)
|
@@ -139,10 +139,18 @@ class C3TR(C3):
|
|
139 |
self.m = TransformerBlock(c_, c_, 4, n)
|
140 |
|
141 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
142 |
class SPP(nn.Module):
|
143 |
# Spatial pyramid pooling layer used in YOLOv3-SPP
|
144 |
def __init__(self, c1, c2, k=(5, 9, 13)):
|
145 |
-
super(
|
146 |
c_ = c1 // 2 # hidden channels
|
147 |
self.cv1 = Conv(c1, c_, 1, 1)
|
148 |
self.cv2 = Conv(c_ * (len(k) + 1), c2, 1, 1)
|
@@ -156,7 +164,7 @@ class SPP(nn.Module):
|
|
156 |
class Focus(nn.Module):
|
157 |
# Focus wh information into c-space
|
158 |
def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True): # ch_in, ch_out, kernel, stride, padding, groups
|
159 |
-
super(
|
160 |
self.conv = Conv(c1 * 4, c2, k, s, p, g, act)
|
161 |
# self.contract = Contract(gain=2)
|
162 |
|
@@ -196,27 +204,13 @@ class Expand(nn.Module):
|
|
196 |
class Concat(nn.Module):
|
197 |
# Concatenate a list of tensors along dimension
|
198 |
def __init__(self, dimension=1):
|
199 |
-
super(
|
200 |
self.d = dimension
|
201 |
|
202 |
def forward(self, x):
|
203 |
return torch.cat(x, self.d)
|
204 |
|
205 |
|
206 |
-
class NMS(nn.Module):
|
207 |
-
# Non-Maximum Suppression (NMS) module
|
208 |
-
conf = 0.25 # confidence threshold
|
209 |
-
iou = 0.45 # IoU threshold
|
210 |
-
classes = None # (optional list) filter by class
|
211 |
-
max_det = 1000 # maximum number of detections per image
|
212 |
-
|
213 |
-
def __init__(self):
|
214 |
-
super(NMS, self).__init__()
|
215 |
-
|
216 |
-
def forward(self, x):
|
217 |
-
return non_max_suppression(x[0], self.conf, iou_thres=self.iou, classes=self.classes, max_det=self.max_det)
|
218 |
-
|
219 |
-
|
220 |
class AutoShape(nn.Module):
|
221 |
# YOLOv5 input-robust model wrapper for passing cv2/np/PIL/torch inputs. Includes preprocessing, inference and NMS
|
222 |
conf = 0.25 # NMS confidence threshold
|
@@ -225,7 +219,7 @@ class AutoShape(nn.Module):
|
|
225 |
max_det = 1000 # maximum number of detections per image
|
226 |
|
227 |
def __init__(self, model):
|
228 |
-
super(
|
229 |
self.model = model.eval()
|
230 |
|
231 |
def autoshape(self):
|
@@ -292,7 +286,7 @@ class AutoShape(nn.Module):
|
|
292 |
class Detections:
|
293 |
# YOLOv5 detections class for inference results
|
294 |
def __init__(self, imgs, pred, files, times=None, names=None, shape=None):
|
295 |
-
super(
|
296 |
d = pred[0].device # device
|
297 |
gn = [torch.tensor([*[im.shape[i] for i in [1, 0, 1, 0]], 1., 1.], device=d) for im in imgs] # normalizations
|
298 |
self.imgs = imgs # list of images as numpy arrays
|
@@ -383,7 +377,7 @@ class Detections:
|
|
383 |
class Classify(nn.Module):
|
384 |
# Classification head, i.e. x(b,c1,20,20) to x(b,c2)
|
385 |
def __init__(self, c1, c2, k=1, s=1, p=None, g=1): # ch_in, ch_out, kernel, stride, padding, groups
|
386 |
-
super(
|
387 |
self.aap = nn.AdaptiveAvgPool2d(1) # to x(b,c1,1,1)
|
388 |
self.conv = nn.Conv2d(c1, c2, k, s, autopad(k, p), groups=g) # to x(b,c2,1,1)
|
389 |
self.flat = nn.Flatten()
|
|
|
36 |
class Conv(nn.Module):
|
37 |
# Standard convolution
|
38 |
def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True): # ch_in, ch_out, kernel, stride, padding, groups
|
39 |
+
super().__init__()
|
40 |
self.conv = nn.Conv2d(c1, c2, k, s, autopad(k, p), groups=g, bias=False)
|
41 |
self.bn = nn.BatchNorm2d(c2)
|
42 |
self.act = nn.SiLU() if act is True else (act if isinstance(act, nn.Module) else nn.Identity())
|
|
|
87 |
class Bottleneck(nn.Module):
|
88 |
# Standard bottleneck
|
89 |
def __init__(self, c1, c2, shortcut=True, g=1, e=0.5): # ch_in, ch_out, shortcut, groups, expansion
|
90 |
+
super().__init__()
|
91 |
c_ = int(c2 * e) # hidden channels
|
92 |
self.cv1 = Conv(c1, c_, 1, 1)
|
93 |
self.cv2 = Conv(c_, c2, 3, 1, g=g)
|
|
|
100 |
class BottleneckCSP(nn.Module):
|
101 |
# CSP Bottleneck https://github.com/WongKinYiu/CrossStagePartialNetworks
|
102 |
def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): # ch_in, ch_out, number, shortcut, groups, expansion
|
103 |
+
super().__init__()
|
104 |
c_ = int(c2 * e) # hidden channels
|
105 |
self.cv1 = Conv(c1, c_, 1, 1)
|
106 |
self.cv2 = nn.Conv2d(c1, c_, 1, 1, bias=False)
|
|
|
119 |
class C3(nn.Module):
|
120 |
# CSP Bottleneck with 3 convolutions
|
121 |
def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): # ch_in, ch_out, number, shortcut, groups, expansion
|
122 |
+
super().__init__()
|
123 |
c_ = int(c2 * e) # hidden channels
|
124 |
self.cv1 = Conv(c1, c_, 1, 1)
|
125 |
self.cv2 = Conv(c1, c_, 1, 1)
|
|
|
139 |
self.m = TransformerBlock(c_, c_, 4, n)
|
140 |
|
141 |
|
142 |
+
class C3SPP(C3):
|
143 |
+
# C3 module with SPP()
|
144 |
+
def __init__(self, c1, c2, k=(5, 9, 13), n=1, shortcut=True, g=1, e=0.5):
|
145 |
+
super().__init__(c1, c2, n, shortcut, g, e)
|
146 |
+
c_ = int(c2 * e)
|
147 |
+
self.m = SPP(c_, c_, k)
|
148 |
+
|
149 |
+
|
150 |
class SPP(nn.Module):
|
151 |
# Spatial pyramid pooling layer used in YOLOv3-SPP
|
152 |
def __init__(self, c1, c2, k=(5, 9, 13)):
|
153 |
+
super().__init__()
|
154 |
c_ = c1 // 2 # hidden channels
|
155 |
self.cv1 = Conv(c1, c_, 1, 1)
|
156 |
self.cv2 = Conv(c_ * (len(k) + 1), c2, 1, 1)
|
|
|
164 |
class Focus(nn.Module):
|
165 |
# Focus wh information into c-space
|
166 |
def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True): # ch_in, ch_out, kernel, stride, padding, groups
|
167 |
+
super().__init__()
|
168 |
self.conv = Conv(c1 * 4, c2, k, s, p, g, act)
|
169 |
# self.contract = Contract(gain=2)
|
170 |
|
|
|
204 |
class Concat(nn.Module):
|
205 |
# Concatenate a list of tensors along dimension
|
206 |
def __init__(self, dimension=1):
|
207 |
+
super().__init__()
|
208 |
self.d = dimension
|
209 |
|
210 |
def forward(self, x):
|
211 |
return torch.cat(x, self.d)
|
212 |
|
213 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
214 |
class AutoShape(nn.Module):
|
215 |
# YOLOv5 input-robust model wrapper for passing cv2/np/PIL/torch inputs. Includes preprocessing, inference and NMS
|
216 |
conf = 0.25 # NMS confidence threshold
|
|
|
219 |
max_det = 1000 # maximum number of detections per image
|
220 |
|
221 |
def __init__(self, model):
|
222 |
+
super().__init__()
|
223 |
self.model = model.eval()
|
224 |
|
225 |
def autoshape(self):
|
|
|
286 |
class Detections:
|
287 |
# YOLOv5 detections class for inference results
|
288 |
def __init__(self, imgs, pred, files, times=None, names=None, shape=None):
|
289 |
+
super().__init__()
|
290 |
d = pred[0].device # device
|
291 |
gn = [torch.tensor([*[im.shape[i] for i in [1, 0, 1, 0]], 1., 1.], device=d) for im in imgs] # normalizations
|
292 |
self.imgs = imgs # list of images as numpy arrays
|
|
|
377 |
class Classify(nn.Module):
|
378 |
# Classification head, i.e. x(b,c1,20,20) to x(b,c2)
|
379 |
def __init__(self, c1, c2, k=1, s=1, p=None, g=1): # ch_in, ch_out, kernel, stride, padding, groups
|
380 |
+
super().__init__()
|
381 |
self.aap = nn.AdaptiveAvgPool2d(1) # to x(b,c1,1,1)
|
382 |
self.conv = nn.Conv2d(c1, c2, k, s, autopad(k, p), groups=g) # to x(b,c2,1,1)
|
383 |
self.flat = nn.Flatten()
|
models/experimental.py
CHANGED
@@ -12,7 +12,7 @@ class CrossConv(nn.Module):
|
|
12 |
# Cross Convolution Downsample
|
13 |
def __init__(self, c1, c2, k=3, s=1, g=1, e=1.0, shortcut=False):
|
14 |
# ch_in, ch_out, kernel, stride, groups, expansion, shortcut
|
15 |
-
super(
|
16 |
c_ = int(c2 * e) # hidden channels
|
17 |
self.cv1 = Conv(c1, c_, (1, k), (1, s))
|
18 |
self.cv2 = Conv(c_, c2, (k, 1), (s, 1), g=g)
|
@@ -25,7 +25,7 @@ class CrossConv(nn.Module):
|
|
25 |
class Sum(nn.Module):
|
26 |
# Weighted sum of 2 or more layers https://arxiv.org/abs/1911.09070
|
27 |
def __init__(self, n, weight=False): # n: number of inputs
|
28 |
-
super(
|
29 |
self.weight = weight # apply weights boolean
|
30 |
self.iter = range(n - 1) # iter object
|
31 |
if weight:
|
@@ -46,7 +46,7 @@ class Sum(nn.Module):
|
|
46 |
class GhostConv(nn.Module):
|
47 |
# Ghost Convolution https://github.com/huawei-noah/ghostnet
|
48 |
def __init__(self, c1, c2, k=1, s=1, g=1, act=True): # ch_in, ch_out, kernel, stride, groups
|
49 |
-
super(
|
50 |
c_ = c2 // 2 # hidden channels
|
51 |
self.cv1 = Conv(c1, c_, k, s, None, g, act)
|
52 |
self.cv2 = Conv(c_, c_, 5, 1, None, c_, act)
|
@@ -59,7 +59,7 @@ class GhostConv(nn.Module):
|
|
59 |
class GhostBottleneck(nn.Module):
|
60 |
# Ghost Bottleneck https://github.com/huawei-noah/ghostnet
|
61 |
def __init__(self, c1, c2, k=3, s=1): # ch_in, ch_out, kernel, stride
|
62 |
-
super(
|
63 |
c_ = c2 // 2
|
64 |
self.conv = nn.Sequential(GhostConv(c1, c_, 1, 1), # pw
|
65 |
DWConv(c_, c_, k, s, act=False) if s == 2 else nn.Identity(), # dw
|
@@ -74,7 +74,7 @@ class GhostBottleneck(nn.Module):
|
|
74 |
class MixConv2d(nn.Module):
|
75 |
# Mixed Depthwise Conv https://arxiv.org/abs/1907.09595
|
76 |
def __init__(self, c1, c2, k=(1, 3), s=1, equal_ch=True):
|
77 |
-
super(
|
78 |
groups = len(k)
|
79 |
if equal_ch: # equal c_ per group
|
80 |
i = torch.linspace(0, groups - 1E-6, c2).floor() # c2 indices
|
@@ -98,7 +98,7 @@ class MixConv2d(nn.Module):
|
|
98 |
class Ensemble(nn.ModuleList):
|
99 |
# Ensemble of models
|
100 |
def __init__(self):
|
101 |
-
super(
|
102 |
|
103 |
def forward(self, x, augment=False, profile=False, visualize=False):
|
104 |
y = []
|
|
|
12 |
# Cross Convolution Downsample
|
13 |
def __init__(self, c1, c2, k=3, s=1, g=1, e=1.0, shortcut=False):
|
14 |
# ch_in, ch_out, kernel, stride, groups, expansion, shortcut
|
15 |
+
super().__init__()
|
16 |
c_ = int(c2 * e) # hidden channels
|
17 |
self.cv1 = Conv(c1, c_, (1, k), (1, s))
|
18 |
self.cv2 = Conv(c_, c2, (k, 1), (s, 1), g=g)
|
|
|
25 |
class Sum(nn.Module):
|
26 |
# Weighted sum of 2 or more layers https://arxiv.org/abs/1911.09070
|
27 |
def __init__(self, n, weight=False): # n: number of inputs
|
28 |
+
super().__init__()
|
29 |
self.weight = weight # apply weights boolean
|
30 |
self.iter = range(n - 1) # iter object
|
31 |
if weight:
|
|
|
46 |
class GhostConv(nn.Module):
|
47 |
# Ghost Convolution https://github.com/huawei-noah/ghostnet
|
48 |
def __init__(self, c1, c2, k=1, s=1, g=1, act=True): # ch_in, ch_out, kernel, stride, groups
|
49 |
+
super().__init__()
|
50 |
c_ = c2 // 2 # hidden channels
|
51 |
self.cv1 = Conv(c1, c_, k, s, None, g, act)
|
52 |
self.cv2 = Conv(c_, c_, 5, 1, None, c_, act)
|
|
|
59 |
class GhostBottleneck(nn.Module):
|
60 |
# Ghost Bottleneck https://github.com/huawei-noah/ghostnet
|
61 |
def __init__(self, c1, c2, k=3, s=1): # ch_in, ch_out, kernel, stride
|
62 |
+
super().__init__()
|
63 |
c_ = c2 // 2
|
64 |
self.conv = nn.Sequential(GhostConv(c1, c_, 1, 1), # pw
|
65 |
DWConv(c_, c_, k, s, act=False) if s == 2 else nn.Identity(), # dw
|
|
|
74 |
class MixConv2d(nn.Module):
|
75 |
# Mixed Depthwise Conv https://arxiv.org/abs/1907.09595
|
76 |
def __init__(self, c1, c2, k=(1, 3), s=1, equal_ch=True):
|
77 |
+
super().__init__()
|
78 |
groups = len(k)
|
79 |
if equal_ch: # equal c_ per group
|
80 |
i = torch.linspace(0, groups - 1E-6, c2).floor() # c2 indices
|
|
|
98 |
class Ensemble(nn.ModuleList):
|
99 |
# Ensemble of models
|
100 |
def __init__(self):
|
101 |
+
super().__init__()
|
102 |
|
103 |
def forward(self, x, augment=False, profile=False, visualize=False):
|
104 |
y = []
|
models/yolo.py
CHANGED
@@ -33,7 +33,7 @@ class Detect(nn.Module):
|
|
33 |
onnx_dynamic = False # ONNX export parameter
|
34 |
|
35 |
def __init__(self, nc=80, anchors=(), ch=(), inplace=True): # detection layer
|
36 |
-
super(
|
37 |
self.nc = nc # number of classes
|
38 |
self.no = nc + 5 # number of outputs per anchor
|
39 |
self.nl = len(anchors) # number of detection layers
|
@@ -77,7 +77,7 @@ class Detect(nn.Module):
|
|
77 |
|
78 |
class Model(nn.Module):
|
79 |
def __init__(self, cfg='yolov5s.yaml', ch=3, nc=None, anchors=None): # model, input channels, number of classes
|
80 |
-
super(
|
81 |
if isinstance(cfg, dict):
|
82 |
self.yaml = cfg # model dict
|
83 |
else: # is *.yaml
|
@@ -209,20 +209,6 @@ class Model(nn.Module):
|
|
209 |
self.info()
|
210 |
return self
|
211 |
|
212 |
-
def nms(self, mode=True): # add or remove NMS module
|
213 |
-
present = type(self.model[-1]) is NMS # last layer is NMS
|
214 |
-
if mode and not present:
|
215 |
-
LOGGER.info('Adding NMS... ')
|
216 |
-
m = NMS() # module
|
217 |
-
m.f = -1 # from
|
218 |
-
m.i = self.model[-1].i + 1 # index
|
219 |
-
self.model.add_module(name='%s' % m.i, module=m) # add
|
220 |
-
self.eval()
|
221 |
-
elif not mode and present:
|
222 |
-
LOGGER.info('Removing NMS... ')
|
223 |
-
self.model = self.model[:-1] # remove
|
224 |
-
return self
|
225 |
-
|
226 |
def autoshape(self): # add AutoShape module
|
227 |
LOGGER.info('Adding AutoShape... ')
|
228 |
m = AutoShape(self) # wrap model
|
@@ -250,7 +236,7 @@ def parse_model(d, ch): # model_dict, input_channels(3)
|
|
250 |
|
251 |
n = max(round(n * gd), 1) if n > 1 else n # depth gain
|
252 |
if m in [Conv, GhostConv, Bottleneck, GhostBottleneck, SPP, DWConv, MixConv2d, Focus, CrossConv, BottleneckCSP,
|
253 |
-
C3, C3TR]:
|
254 |
c1, c2 = ch[f], args[0]
|
255 |
if c2 != no: # if not output
|
256 |
c2 = make_divisible(c2 * gw, 8)
|
|
|
33 |
onnx_dynamic = False # ONNX export parameter
|
34 |
|
35 |
def __init__(self, nc=80, anchors=(), ch=(), inplace=True): # detection layer
|
36 |
+
super().__init__()
|
37 |
self.nc = nc # number of classes
|
38 |
self.no = nc + 5 # number of outputs per anchor
|
39 |
self.nl = len(anchors) # number of detection layers
|
|
|
77 |
|
78 |
class Model(nn.Module):
|
79 |
def __init__(self, cfg='yolov5s.yaml', ch=3, nc=None, anchors=None): # model, input channels, number of classes
|
80 |
+
super().__init__()
|
81 |
if isinstance(cfg, dict):
|
82 |
self.yaml = cfg # model dict
|
83 |
else: # is *.yaml
|
|
|
209 |
self.info()
|
210 |
return self
|
211 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
212 |
def autoshape(self): # add AutoShape module
|
213 |
LOGGER.info('Adding AutoShape... ')
|
214 |
m = AutoShape(self) # wrap model
|
|
|
236 |
|
237 |
n = max(round(n * gd), 1) if n > 1 else n # depth gain
|
238 |
if m in [Conv, GhostConv, Bottleneck, GhostBottleneck, SPP, DWConv, MixConv2d, Focus, CrossConv, BottleneckCSP,
|
239 |
+
C3, C3TR, C3SPP]:
|
240 |
c1, c2 = ch[f], args[0]
|
241 |
if c2 != no: # if not output
|
242 |
c2 = make_divisible(c2 * gw, 8)
|