Daryl Fung commited on
Commit
b0be318
β€’
1 Parent(s): 90023e1

added git lfs

Browse files
This view is limited to 50 files because it contains too many changes. Β  See raw diff
Files changed (50) hide show
  1. .gitignore +4 -0
  2. app.py +98 -0
  3. yolov5/.DS_Store +0 -0
  4. yolov5/__pycache__/export.cpython-39.pyc +0 -0
  5. yolov5/detect.py +258 -0
  6. yolov5/export.py +544 -0
  7. yolov5/models/__init__.py +0 -0
  8. yolov5/models/__pycache__/__init__.cpython-36.pyc +0 -0
  9. yolov5/models/__pycache__/__init__.cpython-39.pyc +0 -0
  10. yolov5/models/__pycache__/common.cpython-36.pyc +0 -0
  11. yolov5/models/__pycache__/common.cpython-39.pyc +0 -0
  12. yolov5/models/__pycache__/experimental.cpython-36.pyc +0 -0
  13. yolov5/models/__pycache__/experimental.cpython-39.pyc +0 -0
  14. yolov5/models/__pycache__/yolo.cpython-36.pyc +0 -0
  15. yolov5/models/__pycache__/yolo.cpython-39.pyc +0 -0
  16. yolov5/models/common.py +674 -0
  17. yolov5/models/experimental.py +120 -0
  18. yolov5/models/hub/anchors.yaml +59 -0
  19. yolov5/models/hub/yolov3-spp.yaml +51 -0
  20. yolov5/models/hub/yolov3-tiny.yaml +41 -0
  21. yolov5/models/hub/yolov3.yaml +51 -0
  22. yolov5/models/hub/yolov5-bifpn.yaml +48 -0
  23. yolov5/models/hub/yolov5-fpn.yaml +42 -0
  24. yolov5/models/hub/yolov5-p2.yaml +54 -0
  25. yolov5/models/hub/yolov5-p34.yaml +41 -0
  26. yolov5/models/hub/yolov5-p6.yaml +56 -0
  27. yolov5/models/hub/yolov5-p7.yaml +67 -0
  28. yolov5/models/hub/yolov5-panet.yaml +48 -0
  29. yolov5/models/hub/yolov5l6.yaml +60 -0
  30. yolov5/models/hub/yolov5m6.yaml +60 -0
  31. yolov5/models/hub/yolov5n6.yaml +60 -0
  32. yolov5/models/hub/yolov5s-ghost.yaml +48 -0
  33. yolov5/models/hub/yolov5s-transformer.yaml +48 -0
  34. yolov5/models/hub/yolov5s6.yaml +60 -0
  35. yolov5/models/hub/yolov5x6.yaml +60 -0
  36. yolov5/models/tf.py +464 -0
  37. yolov5/models/yolo.py +329 -0
  38. yolov5/models/yolov5l.yaml +48 -0
  39. yolov5/models/yolov5m.yaml +48 -0
  40. yolov5/models/yolov5n.yaml +48 -0
  41. yolov5/models/yolov5s.yaml +48 -0
  42. yolov5/models/yolov5x.yaml +48 -0
  43. yolov5/utils/__init__.py +37 -0
  44. yolov5/utils/__pycache__/__init__.cpython-36.pyc +0 -0
  45. yolov5/utils/__pycache__/__init__.cpython-39.pyc +0 -0
  46. yolov5/utils/__pycache__/activations.cpython-36.pyc +0 -0
  47. yolov5/utils/__pycache__/activations.cpython-39.pyc +0 -0
  48. yolov5/utils/__pycache__/augmentations.cpython-36.pyc +0 -0
  49. yolov5/utils/__pycache__/augmentations.cpython-39.pyc +0 -0
  50. yolov5/utils/__pycache__/autoanchor.cpython-36.pyc +0 -0
.gitignore ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ **/__pycache__/
2
+ .DS_Store
3
+ .idea/
4
+ *.pyc
app.py ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import torch
3
+ import numpy as np
4
+
5
+ from yolov5.models.common import DetectMultiBackend
6
+ from yolov5.utils.datasets import IMG_FORMATS, VID_FORMATS, LoadImages, LoadStreams
7
+ from yolov5.utils.general import (LOGGER, check_file, check_img_size, check_imshow, check_requirements, colorstr,
8
+ increment_path, non_max_suppression, print_args, scale_coords, strip_optimizer, xyxy2xywh)
9
+ from yolov5.utils.plots import Annotator, colors, save_one_box
10
+ from yolov5.utils.torch_utils import select_device, time_sync
11
+ from yolov5.utils.augmentations import letterbox
12
+
13
+ device = 'cpu'
14
+ half = False
15
+ weights = 'yolov5/best_yolov5l6_joint_pseudo.pt'
16
+ model = DetectMultiBackend(weights, device=device, dnn=False, data=None)
17
+ stride, names, pt, jit, onnx, engine = model.stride, model.names, model.pt, model.jit, model.onnx, model.engine
18
+ bs = 1
19
+ imgsz = (640, 640)
20
+ conf_thres = 0.1
21
+ iou_thres = 0.1
22
+ hide_labels = False
23
+ hide_conf = True
24
+ line_thickness = 1
25
+
26
+ def joint_detection(img0):
27
+ global imgsz
28
+ img = letterbox(img0, 640, stride=stride, auto=pt)[0]
29
+ img = img.transpose((2, 0, 1))[::-1] # HWC to CHW, BGR to RGB
30
+ img = np.ascontiguousarray(img)
31
+
32
+ im = torch.from_numpy(img).to(device)
33
+ im = im.half() if half else im.float() # uint8 to fp16/32
34
+ im /= 255 # 0 - 255 to 0.0 - 1.0
35
+ if len(im.shape) == 3:
36
+ im = im[None] # expand for batch dim
37
+ # Padded resize
38
+
39
+ # Convert
40
+ imgsz = check_img_size(imgsz, s=stride) # check image size
41
+
42
+ # Inference
43
+ model.warmup(imgsz=(1 if pt else bs, 3, *imgsz), half=half) # warmup
44
+ pred = model(im, augment=False, visualize=False)
45
+ t3 = time_sync()
46
+
47
+ # NMS
48
+ pred = non_max_suppression(pred, conf_thres, iou_thres, None, False, max_det=1000)
49
+
50
+ # Second-stage classifier (optional)
51
+ # pred = utils.general.apply_classifier(pred, classifier_model, im, im0s)
52
+
53
+ # Process predictions
54
+ for i, det in enumerate(pred): # per image
55
+ im0 = img0.copy()
56
+ gn = torch.tensor(im0.shape)[[1, 0, 1, 0]] # normalization gain whwh
57
+ annotator = Annotator(im0, line_width=line_thickness, example=str(names))
58
+ imc = im0
59
+ if len(det):
60
+ # Rescale boxes from img_size to im0 size
61
+ det[:, :4] = scale_coords(im.shape[2:], det[:, :4], im0.shape).round()
62
+
63
+ # Write results
64
+ for *xyxy, conf, cls in reversed(det):
65
+ c = int(cls) # integer class
66
+ label = None if hide_labels else (names[c] if hide_conf else f'{names[c]} {conf:.2f}')
67
+ annotator.box_label(xyxy, label, color=colors(c, True))
68
+
69
+ # Stream results
70
+ im0 = annotator.result()
71
+ return im0
72
+ # if view_img:
73
+ # cv2.imshow(str(p), im0)
74
+ # cv2.waitKey(1) # 1 millisecond
75
+ #
76
+ # # Save results (image with detections)
77
+ # if save_img:
78
+ # if dataset.mode == 'image':
79
+ # cv2.imwrite(save_path, im0)
80
+ # else: # 'video' or 'stream'
81
+ # if vid_path[i] != save_path: # new video
82
+ # vid_path[i] = save_path
83
+ # if isinstance(vid_writer[i], cv2.VideoWriter):
84
+ # vid_writer[i].release() # release previous video writer
85
+ # if vid_cap: # video
86
+ # fps = vid_cap.get(cv2.CAP_PROP_FPS)
87
+ # w = int(vid_cap.get(cv2.CAP_PROP_FRAME_WIDTH))
88
+ # h = int(vid_cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
89
+ # else: # stream
90
+ # fps, w, h = 30, im0.shape[1], im0.shape[0]
91
+ # save_path = str(Path(save_path).with_suffix('.mp4')) # force *.mp4 suffix on results videos
92
+ # vid_writer[i] = cv2.VideoWriter(save_path, cv2.VideoWriter_fourcc(*'mp4v'), fps, (w, h))
93
+ # vid_writer[i].write(im0)
94
+
95
+ # Print time (inference-only)
96
+
97
+ iface = gr.Interface(fn=joint_detection, inputs="image", outputs="image")
98
+ iface.launch()
yolov5/.DS_Store ADDED
Binary file (14.3 kB). View file
 
yolov5/__pycache__/export.cpython-39.pyc ADDED
Binary file (21.3 kB). View file
 
yolov5/detect.py ADDED
@@ -0,0 +1,258 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # YOLOv5 πŸš€ by Ultralytics, GPL-3.0 license
2
+ """
3
+ Run inference on images, videos, directories, streams, etc.
4
+
5
+ Usage - sources:
6
+ $ python path/to/detect.py --weights yolov5s.pt --source 0 # webcam
7
+ img.jpg # image
8
+ vid.mp4 # video
9
+ path/ # directory
10
+ path/*.jpg # glob
11
+ 'https://youtu.be/Zgi9g1ksQHc' # YouTube
12
+ 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP stream
13
+
14
+ Usage - formats:
15
+ $ python path/to/detect.py --weights yolov5s.pt # PyTorch
16
+ yolov5s.torchscript # TorchScript
17
+ yolov5s.onnx # ONNX Runtime or OpenCV DNN with --dnn
18
+ yolov5s.xml # OpenVINO
19
+ yolov5s.engine # TensorRT
20
+ yolov5s.mlmodel # CoreML (MacOS-only)
21
+ yolov5s_saved_model # TensorFlow SavedModel
22
+ yolov5s.pb # TensorFlow GraphDef
23
+ yolov5s.tflite # TensorFlow Lite
24
+ yolov5s_edgetpu.tflite # TensorFlow Edge TPU
25
+ """
26
+
27
+ import argparse
28
+ import os
29
+ import sys
30
+ from pathlib import Path
31
+
32
+ import cv2
33
+ import torch
34
+ import torch.backends.cudnn as cudnn
35
+
36
+ FILE = Path(__file__).resolve()
37
+ ROOT = FILE.parents[0] # YOLOv5 root directory
38
+ if str(ROOT) not in sys.path:
39
+ sys.path.append(str(ROOT)) # add ROOT to PATH
40
+ ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative
41
+
42
+ from models.common import DetectMultiBackend
43
+ from utils.datasets import IMG_FORMATS, VID_FORMATS, LoadImages, LoadStreams
44
+ from utils.general import (LOGGER, check_file, check_img_size, check_imshow, check_requirements, colorstr,
45
+ increment_path, non_max_suppression, print_args, scale_coords, strip_optimizer, xyxy2xywh)
46
+ from utils.plots import Annotator, colors, save_one_box
47
+ from utils.torch_utils import select_device, time_sync
48
+
49
+
50
+
51
+ @torch.no_grad()
52
+ def run(weights=ROOT / 'yolov5s.pt', # model.pt path(s)
53
+ source=ROOT / 'data/images', # file/dir/URL/glob, 0 for webcam
54
+ data=ROOT / 'data/coco128.yaml', # dataset.yaml path
55
+ imgsz=(640, 640), # inference size (height, width)
56
+ conf_thres=0.25, # confidence threshold
57
+ iou_thres=0.45, # NMS IOU threshold
58
+ max_det=1000, # maximum detections per image
59
+ device='', # cuda device, i.e. 0 or 0,1,2,3 or cpu
60
+ view_img=False, # show results
61
+ save_txt=False, # save results to *.txt
62
+ save_conf=False, # save confidences in --save-txt labels
63
+ save_crop=False, # save cropped prediction boxes
64
+ nosave=False, # do not save images/videos
65
+ classes=None, # filter by class: --class 0, or --class 0 2 3
66
+ agnostic_nms=False, # class-agnostic NMS
67
+ augment=False, # augmented inference
68
+ visualize=False, # visualize features
69
+ update=False, # update all models
70
+ project=ROOT / 'runs/detect', # save results to project/name
71
+ name='exp', # save results to project/name
72
+ exist_ok=False, # existing project/name ok, do not increment
73
+ line_thickness=3, # bounding box thickness (pixels)
74
+ hide_labels=False, # hide labels
75
+ hide_conf=False, # hide confidences
76
+ half=False, # use FP16 half-precision inference
77
+ dnn=False, # use OpenCV DNN for ONNX inference
78
+ ):
79
+ source = str(source)
80
+ save_img = not nosave and not source.endswith('.txt') # save inference images
81
+ is_file = Path(source).suffix[1:] in (IMG_FORMATS + VID_FORMATS)
82
+ is_url = source.lower().startswith(('rtsp://', 'rtmp://', 'http://', 'https://'))
83
+ webcam = source.isnumeric() or source.endswith('.txt') or (is_url and not is_file)
84
+ if is_url and is_file:
85
+ source = check_file(source) # download
86
+
87
+ # Directories
88
+ save_dir = increment_path(Path(project) / name, exist_ok=exist_ok) # increment run
89
+ (save_dir / 'labels' if save_txt else save_dir).mkdir(parents=True, exist_ok=True) # make dir
90
+
91
+ # Load model
92
+ device = select_device(device)
93
+ model = DetectMultiBackend(weights, device=device, dnn=dnn, data=data)
94
+ stride, names, pt, jit, onnx, engine = model.stride, model.names, model.pt, model.jit, model.onnx, model.engine
95
+ imgsz = check_img_size(imgsz, s=stride) # check image size
96
+
97
+ # Half
98
+ half &= (pt or jit or onnx or engine) and device.type != 'cpu' # FP16 supported on limited backends with CUDA
99
+ if pt or jit:
100
+ model.model.half() if half else model.model.float()
101
+
102
+ # Dataloader
103
+ if webcam:
104
+ view_img = check_imshow()
105
+ cudnn.benchmark = True # set True to speed up constant image size inference
106
+ dataset = LoadStreams(source, img_size=imgsz, stride=stride, auto=pt)
107
+ bs = len(dataset) # batch_size
108
+ else:
109
+ dataset = LoadImages(source, img_size=imgsz, stride=stride, auto=pt)
110
+ bs = 1 # batch_size
111
+ vid_path, vid_writer = [None] * bs, [None] * bs
112
+
113
+ # Run inference
114
+ model.warmup(imgsz=(1 if pt else bs, 3, *imgsz), half=half) # warmup
115
+ dt, seen = [0.0, 0.0, 0.0], 0
116
+ for path, im, im0s, vid_cap, s in dataset:
117
+ t1 = time_sync()
118
+ im = torch.from_numpy(im).to(device)
119
+ im = im.half() if half else im.float() # uint8 to fp16/32
120
+ im /= 255 # 0 - 255 to 0.0 - 1.0
121
+ if len(im.shape) == 3:
122
+ im = im[None] # expand for batch dim
123
+ t2 = time_sync()
124
+ dt[0] += t2 - t1
125
+
126
+ # Inference
127
+ visualize = increment_path(save_dir / Path(path).stem, mkdir=True) if visualize else False
128
+ pred = model(im, augment=augment, visualize=visualize)
129
+ t3 = time_sync()
130
+ dt[1] += t3 - t2
131
+
132
+ # NMS
133
+ pred = non_max_suppression(pred, conf_thres, iou_thres, classes, agnostic_nms, max_det=max_det)
134
+ dt[2] += time_sync() - t3
135
+
136
+ # Second-stage classifier (optional)
137
+ # pred = utils.general.apply_classifier(pred, classifier_model, im, im0s)
138
+
139
+ # Process predictions
140
+ for i, det in enumerate(pred): # per image
141
+ seen += 1
142
+ if webcam: # batch_size >= 1
143
+ p, im0, frame = path[i], im0s[i].copy(), dataset.count
144
+ s += f'{i}: '
145
+ else:
146
+ p, im0, frame = path, im0s.copy(), getattr(dataset, 'frame', 0)
147
+
148
+ p = Path(p) # to Path
149
+ save_path = str(save_dir / p.name) # im.jpg
150
+ txt_path = str(save_dir / 'labels' / p.stem) + ('' if dataset.mode == 'image' else f'_{frame}') # im.txt
151
+ s += '%gx%g ' % im.shape[2:] # print string
152
+ gn = torch.tensor(im0.shape)[[1, 0, 1, 0]] # normalization gain whwh
153
+ imc = im0.copy() if save_crop else im0 # for save_crop
154
+ annotator = Annotator(im0, line_width=line_thickness, example=str(names))
155
+ if len(det):
156
+ # Rescale boxes from img_size to im0 size
157
+ det[:, :4] = scale_coords(im.shape[2:], det[:, :4], im0.shape).round()
158
+
159
+ # Print results
160
+ for c in det[:, -1].unique():
161
+ n = (det[:, -1] == c).sum() # detections per class
162
+ s += f"{n} {names[int(c)]}{'s' * (n > 1)}, " # add to string
163
+
164
+ # Write results
165
+ for *xyxy, conf, cls in reversed(det):
166
+ if save_txt: # Write to file
167
+ xywh = (xyxy2xywh(torch.tensor(xyxy).view(1, 4)) / gn).view(-1).tolist() # normalized xywh
168
+ line = (cls, *xywh, conf) if save_conf else (cls, *xywh) # label format
169
+ with open(txt_path + '.txt', 'a') as f:
170
+ f.write(('%g ' * len(line)).rstrip() % line + '\n')
171
+
172
+ if save_img or save_crop or view_img: # Add bbox to image
173
+ c = int(cls) # integer class
174
+ label = None if hide_labels else (names[c] if hide_conf else f'{names[c]} {conf:.2f}')
175
+ annotator.box_label(xyxy, label, color=colors(c, True))
176
+ if save_crop:
177
+ save_one_box(xyxy, imc, file=save_dir / 'crops' / names[c] / f'{p.stem}.jpg', BGR=True)
178
+
179
+ # Stream results
180
+ im0 = annotator.result()
181
+ if view_img:
182
+ cv2.imshow(str(p), im0)
183
+ cv2.waitKey(1) # 1 millisecond
184
+
185
+ # Save results (image with detections)
186
+ if save_img:
187
+ if dataset.mode == 'image':
188
+ cv2.imwrite(save_path, im0)
189
+ else: # 'video' or 'stream'
190
+ if vid_path[i] != save_path: # new video
191
+ vid_path[i] = save_path
192
+ if isinstance(vid_writer[i], cv2.VideoWriter):
193
+ vid_writer[i].release() # release previous video writer
194
+ if vid_cap: # video
195
+ fps = vid_cap.get(cv2.CAP_PROP_FPS)
196
+ w = int(vid_cap.get(cv2.CAP_PROP_FRAME_WIDTH))
197
+ h = int(vid_cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
198
+ else: # stream
199
+ fps, w, h = 30, im0.shape[1], im0.shape[0]
200
+ save_path = str(Path(save_path).with_suffix('.mp4')) # force *.mp4 suffix on results videos
201
+ vid_writer[i] = cv2.VideoWriter(save_path, cv2.VideoWriter_fourcc(*'mp4v'), fps, (w, h))
202
+ vid_writer[i].write(im0)
203
+
204
+ # Print time (inference-only)
205
+ LOGGER.info(f'{s}Done. ({t3 - t2:.3f}s)')
206
+
207
+ # Print results
208
+ t = tuple(x / seen * 1E3 for x in dt) # speeds per image
209
+ LOGGER.info(f'Speed: %.1fms pre-process, %.1fms inference, %.1fms NMS per image at shape {(1, 3, *imgsz)}' % t)
210
+ if save_txt or save_img:
211
+ s = f"\n{len(list(save_dir.glob('labels/*.txt')))} labels saved to {save_dir / 'labels'}" if save_txt else ''
212
+ LOGGER.info(f"Results saved to {colorstr('bold', save_dir)}{s}")
213
+ if update:
214
+ strip_optimizer(weights) # update model (to fix SourceChangeWarning)
215
+
216
+
217
+ def parse_opt():
218
+ parser = argparse.ArgumentParser()
219
+ parser.add_argument('--weights', nargs='+', type=str, default=ROOT / 'best2.pt', help='model path(s)')
220
+ parser.add_argument('--source', type=str, default=ROOT / 'data/images', help='file/dir/URL/glob, 0 for webcam')
221
+ parser.add_argument('--data', type=str, default=ROOT / 'data/coco128.yaml', help='(optional) dataset.yaml path')
222
+ parser.add_argument('--imgsz', '--img', '--img-size', nargs='+', type=int, default=[640], help='inference size h,w')
223
+ parser.add_argument('--conf-thres', type=float, default=0.25, help='confidence threshold')
224
+ parser.add_argument('--iou-thres', type=float, default=0.45, help='NMS IoU threshold')
225
+ parser.add_argument('--max-det', type=int, default=1000, help='maximum detections per image')
226
+ parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu')
227
+ parser.add_argument('--view-img', action='store_true', help='show results')
228
+ parser.add_argument('--save-txt', action='store_true', help='save results to *.txt')
229
+ parser.add_argument('--save-conf', action='store_true', help='save confidences in --save-txt labels')
230
+ parser.add_argument('--save-crop', action='store_true', help='save cropped prediction boxes')
231
+ parser.add_argument('--nosave', action='store_true', help='do not save images/videos')
232
+ parser.add_argument('--classes', nargs='+', type=int, help='filter by class: --classes 0, or --classes 0 2 3')
233
+ parser.add_argument('--agnostic-nms', action='store_true', help='class-agnostic NMS')
234
+ parser.add_argument('--augment', action='store_true', help='augmented inference')
235
+ parser.add_argument('--visualize', action='store_true', help='visualize features')
236
+ parser.add_argument('--update', action='store_true', help='update all models')
237
+ parser.add_argument('--project', default=ROOT / 'runs/detect', help='save results to project/name')
238
+ parser.add_argument('--name', default='exp', help='save results to project/name')
239
+ parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment')
240
+ parser.add_argument('--line-thickness', default=1, type=int, help='bounding box thickness (pixels)')
241
+ parser.add_argument('--hide-labels', default=False, action='store_true', help='hide labels')
242
+ parser.add_argument('--hide-conf', default=False, action='store_true', help='hide confidences')
243
+ parser.add_argument('--half', action='store_true', help='use FP16 half-precision inference')
244
+ parser.add_argument('--dnn', action='store_true', help='use OpenCV DNN for ONNX inference')
245
+ opt = parser.parse_args()
246
+ opt.imgsz *= 2 if len(opt.imgsz) == 1 else 1 # expand
247
+ print_args(FILE.stem, opt)
248
+ return opt
249
+
250
+
251
+ def main(opt):
252
+ check_requirements(exclude=('tensorboard', 'thop'))
253
+ run(**vars(opt))
254
+
255
+
256
+ if __name__ == "__main__":
257
+ opt = parse_opt()
258
+ main(opt)
yolov5/export.py ADDED
@@ -0,0 +1,544 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # YOLOv5 πŸš€ by Ultralytics, GPL-3.0 license
2
+ """
3
+ Export a YOLOv5 PyTorch model to other formats. TensorFlow exports authored by https://github.com/zldrobit
4
+
5
+ Format | `export.py --include` | Model
6
+ --- | --- | ---
7
+ PyTorch | - | yolov5s.pt
8
+ TorchScript | `torchscript` | yolov5s.torchscript
9
+ ONNX | `onnx` | yolov5s.onnx
10
+ OpenVINO | `openvino` | yolov5s_openvino_model/
11
+ TensorRT | `engine` | yolov5s.engine
12
+ CoreML | `coreml` | yolov5s.mlmodel
13
+ TensorFlow SavedModel | `saved_model` | yolov5s_saved_model/
14
+ TensorFlow GraphDef | `pb` | yolov5s.pb
15
+ TensorFlow Lite | `tflite` | yolov5s.tflite
16
+ TensorFlow Edge TPU | `edgetpu` | yolov5s_edgetpu.tflite
17
+ TensorFlow.js | `tfjs` | yolov5s_web_model/
18
+
19
+ Requirements:
20
+ $ pip install -r requirements.txt coremltools onnx onnx-simplifier onnxruntime openvino-dev tensorflow-cpu # CPU
21
+ $ pip install -r requirements.txt coremltools onnx onnx-simplifier onnxruntime-gpu openvino-dev tensorflow # GPU
22
+
23
+ Usage:
24
+ $ python path/to/export.py --weights yolov5s.pt --include torchscript onnx openvino engine coreml tflite ...
25
+
26
+ Inference:
27
+ $ python path/to/detect.py --weights yolov5s.pt # PyTorch
28
+ yolov5s.torchscript # TorchScript
29
+ yolov5s.onnx # ONNX Runtime or OpenCV DNN with --dnn
30
+ yolov5s.xml # OpenVINO
31
+ yolov5s.engine # TensorRT
32
+ yolov5s.mlmodel # CoreML (MacOS-only)
33
+ yolov5s_saved_model # TensorFlow SavedModel
34
+ yolov5s.pb # TensorFlow GraphDef
35
+ yolov5s.tflite # TensorFlow Lite
36
+ yolov5s_edgetpu.tflite # TensorFlow Edge TPU
37
+
38
+ TensorFlow.js:
39
+ $ cd .. && git clone https://github.com/zldrobit/tfjs-yolov5-example.git && cd tfjs-yolov5-example
40
+ $ npm install
41
+ $ ln -s ../../yolov5/yolov5s_web_model public/yolov5s_web_model
42
+ $ npm start
43
+ """
44
+
45
+ import argparse
46
+ import json
47
+ import os
48
+ import platform
49
+ import subprocess
50
+ import sys
51
+ import time
52
+ import warnings
53
+ from pathlib import Path
54
+
55
+ import pandas as pd
56
+ import torch
57
+ import torch.nn as nn
58
+ from torch.utils.mobile_optimizer import optimize_for_mobile
59
+
60
+ FILE = Path(__file__).resolve()
61
+ ROOT = FILE.parents[0] # YOLOv5 root directory
62
+ if str(ROOT) not in sys.path:
63
+ sys.path.append(str(ROOT)) # add ROOT to PATH
64
+ ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative
65
+
66
+ from models.common import Conv
67
+ from models.experimental import attempt_load
68
+ from models.yolo import Detect
69
+ from utils.activations import SiLU
70
+ from utils.datasets import LoadImages
71
+ from utils.general import (LOGGER, check_dataset, check_img_size, check_requirements, check_version, colorstr,
72
+ file_size, print_args, url2file)
73
+ from utils.torch_utils import select_device
74
+
75
+
76
+ def export_formats():
77
+ # YOLOv5 export formats
78
+ x = [['PyTorch', '-', '.pt'],
79
+ ['TorchScript', 'torchscript', '.torchscript'],
80
+ ['ONNX', 'onnx', '.onnx'],
81
+ ['OpenVINO', 'openvino', '_openvino_model'],
82
+ ['TensorRT', 'engine', '.engine'],
83
+ ['CoreML', 'coreml', '.mlmodel'],
84
+ ['TensorFlow SavedModel', 'saved_model', '_saved_model'],
85
+ ['TensorFlow GraphDef', 'pb', '.pb'],
86
+ ['TensorFlow Lite', 'tflite', '.tflite'],
87
+ ['TensorFlow Edge TPU', 'edgetpu', '_edgetpu.tflite'],
88
+ ['TensorFlow.js', 'tfjs', '_web_model']]
89
+ return pd.DataFrame(x, columns=['Format', 'Argument', 'Suffix'])
90
+
91
+
92
+ def export_torchscript(model, im, file, optimize, prefix=colorstr('TorchScript:')):
93
+ # YOLOv5 TorchScript model export
94
+ try:
95
+ LOGGER.info(f'\n{prefix} starting export with torch {torch.__version__}...')
96
+ f = file.with_suffix('.torchscript')
97
+
98
+ ts = torch.jit.trace(model, im, strict=False)
99
+ d = {"shape": im.shape, "stride": int(max(model.stride)), "names": model.names}
100
+ extra_files = {'config.txt': json.dumps(d)} # torch._C.ExtraFilesMap()
101
+ if optimize: # https://pytorch.org/tutorials/recipes/mobile_interpreter.html
102
+ optimize_for_mobile(ts)._save_for_lite_interpreter(str(f), _extra_files=extra_files)
103
+ else:
104
+ ts.save(str(f), _extra_files=extra_files)
105
+
106
+ LOGGER.info(f'{prefix} export success, saved as {f} ({file_size(f):.1f} MB)')
107
+ return f
108
+ except Exception as e:
109
+ LOGGER.info(f'{prefix} export failure: {e}')
110
+
111
+
112
+ def export_onnx(model, im, file, opset, train, dynamic, simplify, prefix=colorstr('ONNX:')):
113
+ # YOLOv5 ONNX export
114
+ try:
115
+ check_requirements(('onnx',))
116
+ import onnx
117
+
118
+ LOGGER.info(f'\n{prefix} starting export with onnx {onnx.__version__}...')
119
+ f = file.with_suffix('.onnx')
120
+
121
+ torch.onnx.export(model, im, f, verbose=False, opset_version=opset,
122
+ training=torch.onnx.TrainingMode.TRAINING if train else torch.onnx.TrainingMode.EVAL,
123
+ do_constant_folding=not train,
124
+ input_names=['images'],
125
+ output_names=['output'],
126
+ dynamic_axes={'images': {0: 'batch', 2: 'height', 3: 'width'}, # shape(1,3,640,640)
127
+ 'output': {0: 'batch', 1: 'anchors'} # shape(1,25200,85)
128
+ } if dynamic else None)
129
+
130
+ # Checks
131
+ model_onnx = onnx.load(f) # load onnx model
132
+ onnx.checker.check_model(model_onnx) # check onnx model
133
+ # LOGGER.info(onnx.helper.printable_graph(model_onnx.graph)) # print
134
+
135
+ # Simplify
136
+ if simplify:
137
+ try:
138
+ check_requirements(('onnx-simplifier',))
139
+ import onnxsim
140
+
141
+ LOGGER.info(f'{prefix} simplifying with onnx-simplifier {onnxsim.__version__}...')
142
+ model_onnx, check = onnxsim.simplify(
143
+ model_onnx,
144
+ dynamic_input_shape=dynamic,
145
+ input_shapes={'images': list(im.shape)} if dynamic else None)
146
+ assert check, 'assert check failed'
147
+ onnx.save(model_onnx, f)
148
+ except Exception as e:
149
+ LOGGER.info(f'{prefix} simplifier failure: {e}')
150
+ LOGGER.info(f'{prefix} export success, saved as {f} ({file_size(f):.1f} MB)')
151
+ return f
152
+ except Exception as e:
153
+ LOGGER.info(f'{prefix} export failure: {e}')
154
+
155
+
156
+ def export_openvino(model, im, file, prefix=colorstr('OpenVINO:')):
157
+ # YOLOv5 OpenVINO export
158
+ try:
159
+ check_requirements(('openvino-dev',)) # requires openvino-dev: https://pypi.org/project/openvino-dev/
160
+ import openvino.inference_engine as ie
161
+
162
+ LOGGER.info(f'\n{prefix} starting export with openvino {ie.__version__}...')
163
+ f = str(file).replace('.pt', '_openvino_model' + os.sep)
164
+
165
+ cmd = f"mo --input_model {file.with_suffix('.onnx')} --output_dir {f}"
166
+ subprocess.check_output(cmd, shell=True)
167
+
168
+ LOGGER.info(f'{prefix} export success, saved as {f} ({file_size(f):.1f} MB)')
169
+ return f
170
+ except Exception as e:
171
+ LOGGER.info(f'\n{prefix} export failure: {e}')
172
+
173
+
174
+ def export_coreml(model, im, file, prefix=colorstr('CoreML:')):
175
+ # YOLOv5 CoreML export
176
+ try:
177
+ check_requirements(('coremltools',))
178
+ import coremltools as ct
179
+
180
+ LOGGER.info(f'\n{prefix} starting export with coremltools {ct.__version__}...')
181
+ f = file.with_suffix('.mlmodel')
182
+
183
+ ts = torch.jit.trace(model, im, strict=False) # TorchScript model
184
+ ct_model = ct.convert(ts, inputs=[ct.ImageType('image', shape=im.shape, scale=1 / 255, bias=[0, 0, 0])])
185
+ ct_model.save(f)
186
+
187
+ LOGGER.info(f'{prefix} export success, saved as {f} ({file_size(f):.1f} MB)')
188
+ return ct_model, f
189
+ except Exception as e:
190
+ LOGGER.info(f'\n{prefix} export failure: {e}')
191
+ return None, None
192
+
193
+
194
+ def export_engine(model, im, file, train, half, simplify, workspace=4, verbose=False, prefix=colorstr('TensorRT:')):
195
+ # YOLOv5 TensorRT export https://developer.nvidia.com/tensorrt
196
+ try:
197
+ check_requirements(('tensorrt',))
198
+ import tensorrt as trt
199
+
200
+ if trt.__version__[0] == '7': # TensorRT 7 handling https://github.com/ultralytics/yolov5/issues/6012
201
+ grid = model.model[-1].anchor_grid
202
+ model.model[-1].anchor_grid = [a[..., :1, :1, :] for a in grid]
203
+ export_onnx(model, im, file, 12, train, False, simplify) # opset 12
204
+ model.model[-1].anchor_grid = grid
205
+ else: # TensorRT >= 8
206
+ check_version(trt.__version__, '8.0.0', hard=True) # require tensorrt>=8.0.0
207
+ export_onnx(model, im, file, 13, train, False, simplify) # opset 13
208
+ onnx = file.with_suffix('.onnx')
209
+
210
+ LOGGER.info(f'\n{prefix} starting export with TensorRT {trt.__version__}...')
211
+ assert im.device.type != 'cpu', 'export running on CPU but must be on GPU, i.e. `python export.py --device 0`'
212
+ assert onnx.exists(), f'failed to export ONNX file: {onnx}'
213
+ f = file.with_suffix('.engine') # TensorRT engine file
214
+ logger = trt.Logger(trt.Logger.INFO)
215
+ if verbose:
216
+ logger.min_severity = trt.Logger.Severity.VERBOSE
217
+
218
+ builder = trt.Builder(logger)
219
+ config = builder.create_builder_config()
220
+ config.max_workspace_size = workspace * 1 << 30
221
+
222
+ flag = (1 << int(trt.NetworkDefinitionCreationFlag.EXPLICIT_BATCH))
223
+ network = builder.create_network(flag)
224
+ parser = trt.OnnxParser(network, logger)
225
+ if not parser.parse_from_file(str(onnx)):
226
+ raise RuntimeError(f'failed to load ONNX file: {onnx}')
227
+
228
+ inputs = [network.get_input(i) for i in range(network.num_inputs)]
229
+ outputs = [network.get_output(i) for i in range(network.num_outputs)]
230
+ LOGGER.info(f'{prefix} Network Description:')
231
+ for inp in inputs:
232
+ LOGGER.info(f'{prefix}\tinput "{inp.name}" with shape {inp.shape} and dtype {inp.dtype}')
233
+ for out in outputs:
234
+ LOGGER.info(f'{prefix}\toutput "{out.name}" with shape {out.shape} and dtype {out.dtype}')
235
+
236
+ half &= builder.platform_has_fast_fp16
237
+ LOGGER.info(f'{prefix} building FP{16 if half else 32} engine in {f}')
238
+ if half:
239
+ config.set_flag(trt.BuilderFlag.FP16)
240
+ with builder.build_engine(network, config) as engine, open(f, 'wb') as t:
241
+ t.write(engine.serialize())
242
+ LOGGER.info(f'{prefix} export success, saved as {f} ({file_size(f):.1f} MB)')
243
+ return f
244
+ except Exception as e:
245
+ LOGGER.info(f'\n{prefix} export failure: {e}')
246
+
247
+
248
+ def export_saved_model(model, im, file, dynamic,
249
+ tf_nms=False, agnostic_nms=False, topk_per_class=100, topk_all=100, iou_thres=0.45,
250
+ conf_thres=0.25, prefix=colorstr('TensorFlow SavedModel:')):
251
+ # YOLOv5 TensorFlow SavedModel export
252
+ try:
253
+ import tensorflow as tf
254
+ from tensorflow import keras
255
+
256
+ from models.tf import TFDetect, TFModel
257
+
258
+ LOGGER.info(f'\n{prefix} starting export with tensorflow {tf.__version__}...')
259
+ f = str(file).replace('.pt', '_saved_model')
260
+ batch_size, ch, *imgsz = list(im.shape) # BCHW
261
+
262
+ tf_model = TFModel(cfg=model.yaml, model=model, nc=model.nc, imgsz=imgsz)
263
+ im = tf.zeros((batch_size, *imgsz, 3)) # BHWC order for TensorFlow
264
+ _ = tf_model.predict(im, tf_nms, agnostic_nms, topk_per_class, topk_all, iou_thres, conf_thres)
265
+ inputs = keras.Input(shape=(*imgsz, 3), batch_size=None if dynamic else batch_size)
266
+ outputs = tf_model.predict(inputs, tf_nms, agnostic_nms, topk_per_class, topk_all, iou_thres, conf_thres)
267
+ keras_model = keras.Model(inputs=inputs, outputs=outputs)
268
+ keras_model.trainable = False
269
+ keras_model.summary()
270
+ keras_model.save(f, save_format='tf')
271
+
272
+ LOGGER.info(f'{prefix} export success, saved as {f} ({file_size(f):.1f} MB)')
273
+ return keras_model, f
274
+ except Exception as e:
275
+ LOGGER.info(f'\n{prefix} export failure: {e}')
276
+ return None, None
277
+
278
+
279
+ def export_pb(keras_model, im, file, prefix=colorstr('TensorFlow GraphDef:')):
280
+ # YOLOv5 TensorFlow GraphDef *.pb export https://github.com/leimao/Frozen_Graph_TensorFlow
281
+ try:
282
+ import tensorflow as tf
283
+ from tensorflow.python.framework.convert_to_constants import convert_variables_to_constants_v2
284
+
285
+ LOGGER.info(f'\n{prefix} starting export with tensorflow {tf.__version__}...')
286
+ f = file.with_suffix('.pb')
287
+
288
+ m = tf.function(lambda x: keras_model(x)) # full model
289
+ m = m.get_concrete_function(tf.TensorSpec(keras_model.inputs[0].shape, keras_model.inputs[0].dtype))
290
+ frozen_func = convert_variables_to_constants_v2(m)
291
+ frozen_func.graph.as_graph_def()
292
+ tf.io.write_graph(graph_or_graph_def=frozen_func.graph, logdir=str(f.parent), name=f.name, as_text=False)
293
+
294
+ LOGGER.info(f'{prefix} export success, saved as {f} ({file_size(f):.1f} MB)')
295
+ return f
296
+ except Exception as e:
297
+ LOGGER.info(f'\n{prefix} export failure: {e}')
298
+
299
+
300
+ def export_tflite(keras_model, im, file, int8, data, ncalib, prefix=colorstr('TensorFlow Lite:')):
301
+ # YOLOv5 TensorFlow Lite export
302
+ try:
303
+ import tensorflow as tf
304
+
305
+ LOGGER.info(f'\n{prefix} starting export with tensorflow {tf.__version__}...')
306
+ batch_size, ch, *imgsz = list(im.shape) # BCHW
307
+ f = str(file).replace('.pt', '-fp16.tflite')
308
+
309
+ converter = tf.lite.TFLiteConverter.from_keras_model(keras_model)
310
+ converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS]
311
+ converter.target_spec.supported_types = [tf.float16]
312
+ converter.optimizations = [tf.lite.Optimize.DEFAULT]
313
+ if int8:
314
+ from models.tf import representative_dataset_gen
315
+ dataset = LoadImages(check_dataset(data)['train'], img_size=imgsz, auto=False) # representative data
316
+ converter.representative_dataset = lambda: representative_dataset_gen(dataset, ncalib)
317
+ converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8]
318
+ converter.target_spec.supported_types = []
319
+ converter.inference_input_type = tf.uint8 # or tf.int8
320
+ converter.inference_output_type = tf.uint8 # or tf.int8
321
+ converter.experimental_new_quantizer = False
322
+ f = str(file).replace('.pt', '-int8.tflite')
323
+
324
+ tflite_model = converter.convert()
325
+ open(f, "wb").write(tflite_model)
326
+ LOGGER.info(f'{prefix} export success, saved as {f} ({file_size(f):.1f} MB)')
327
+ return f
328
+ except Exception as e:
329
+ LOGGER.info(f'\n{prefix} export failure: {e}')
330
+
331
+
332
+ def export_edgetpu(keras_model, im, file, prefix=colorstr('Edge TPU:')):
333
+ # YOLOv5 Edge TPU export https://coral.ai/docs/edgetpu/models-intro/
334
+ try:
335
+ cmd = 'edgetpu_compiler --version'
336
+ help_url = 'https://coral.ai/docs/edgetpu/compiler/'
337
+ assert platform.system() == 'Linux', f'export only supported on Linux. See {help_url}'
338
+ if subprocess.run(cmd + ' >/dev/null', shell=True).returncode != 0:
339
+ LOGGER.info(f'\n{prefix} export requires Edge TPU compiler. Attempting install from {help_url}')
340
+ sudo = subprocess.run('sudo --version >/dev/null', shell=True).returncode == 0 # sudo installed on system
341
+ for c in ['curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -',
342
+ 'echo "deb https://packages.cloud.google.com/apt coral-edgetpu-stable main" | sudo tee /etc/apt/sources.list.d/coral-edgetpu.list',
343
+ 'sudo apt-get update',
344
+ 'sudo apt-get install edgetpu-compiler']:
345
+ subprocess.run(c if sudo else c.replace('sudo ', ''), shell=True, check=True)
346
+ ver = subprocess.run(cmd, shell=True, capture_output=True, check=True).stdout.decode().split()[-1]
347
+
348
+ LOGGER.info(f'\n{prefix} starting export with Edge TPU compiler {ver}...')
349
+ f = str(file).replace('.pt', '-int8_edgetpu.tflite') # Edge TPU model
350
+ f_tfl = str(file).replace('.pt', '-int8.tflite') # TFLite model
351
+
352
+ cmd = f"edgetpu_compiler -s {f_tfl}"
353
+ subprocess.run(cmd, shell=True, check=True)
354
+
355
+ LOGGER.info(f'{prefix} export success, saved as {f} ({file_size(f):.1f} MB)')
356
+ return f
357
+ except Exception as e:
358
+ LOGGER.info(f'\n{prefix} export failure: {e}')
359
+
360
+
361
+ def export_tfjs(keras_model, im, file, prefix=colorstr('TensorFlow.js:')):
362
+ # YOLOv5 TensorFlow.js export
363
+ try:
364
+ check_requirements(('tensorflowjs',))
365
+ import re
366
+
367
+ import tensorflowjs as tfjs
368
+
369
+ LOGGER.info(f'\n{prefix} starting export with tensorflowjs {tfjs.__version__}...')
370
+ f = str(file).replace('.pt', '_web_model') # js dir
371
+ f_pb = file.with_suffix('.pb') # *.pb path
372
+ f_json = f + '/model.json' # *.json path
373
+
374
+ cmd = f'tensorflowjs_converter --input_format=tf_frozen_model ' \
375
+ f'--output_node_names="Identity,Identity_1,Identity_2,Identity_3" {f_pb} {f}'
376
+ subprocess.run(cmd, shell=True)
377
+
378
+ json = open(f_json).read()
379
+ with open(f_json, 'w') as j: # sort JSON Identity_* in ascending order
380
+ subst = re.sub(
381
+ r'{"outputs": {"Identity.?.?": {"name": "Identity.?.?"}, '
382
+ r'"Identity.?.?": {"name": "Identity.?.?"}, '
383
+ r'"Identity.?.?": {"name": "Identity.?.?"}, '
384
+ r'"Identity.?.?": {"name": "Identity.?.?"}}}',
385
+ r'{"outputs": {"Identity": {"name": "Identity"}, '
386
+ r'"Identity_1": {"name": "Identity_1"}, '
387
+ r'"Identity_2": {"name": "Identity_2"}, '
388
+ r'"Identity_3": {"name": "Identity_3"}}}',
389
+ json)
390
+ j.write(subst)
391
+
392
+ LOGGER.info(f'{prefix} export success, saved as {f} ({file_size(f):.1f} MB)')
393
+ return f
394
+ except Exception as e:
395
+ LOGGER.info(f'\n{prefix} export failure: {e}')
396
+
397
+
398
+ @torch.no_grad()
399
+ def run(data=ROOT / 'data/coco128.yaml', # 'dataset.yaml path'
400
+ weights=ROOT / 'yolov5s.pt', # weights path
401
+ imgsz=(640, 640), # image (height, width)
402
+ batch_size=1, # batch size
403
+ device='cpu', # cuda device, i.e. 0 or 0,1,2,3 or cpu
404
+ include=('torchscript', 'onnx'), # include formats
405
+ half=False, # FP16 half-precision export
406
+ inplace=False, # set YOLOv5 Detect() inplace=True
407
+ train=False, # model.train() mode
408
+ optimize=False, # TorchScript: optimize for mobile
409
+ int8=False, # CoreML/TF INT8 quantization
410
+ dynamic=False, # ONNX/TF: dynamic axes
411
+ simplify=False, # ONNX: simplify model
412
+ opset=12, # ONNX: opset version
413
+ verbose=False, # TensorRT: verbose log
414
+ workspace=4, # TensorRT: workspace size (GB)
415
+ nms=False, # TF: add NMS to model
416
+ agnostic_nms=False, # TF: add agnostic NMS to model
417
+ topk_per_class=100, # TF.js NMS: topk per class to keep
418
+ topk_all=100, # TF.js NMS: topk for all classes to keep
419
+ iou_thres=0.45, # TF.js NMS: IoU threshold
420
+ conf_thres=0.25 # TF.js NMS: confidence threshold
421
+ ):
422
+ t = time.time()
423
+ include = [x.lower() for x in include]
424
+ tf_exports = list(x in include for x in ('saved_model', 'pb', 'tflite', 'edgetpu', 'tfjs')) # TensorFlow exports
425
+ file = Path(url2file(weights) if str(weights).startswith(('http:/', 'https:/')) else weights)
426
+
427
+ # Load PyTorch model
428
+ device = select_device(device)
429
+ assert not (device.type == 'cpu' and half), '--half only compatible with GPU export, i.e. use --device 0'
430
+ model = attempt_load(weights, map_location=device, inplace=True, fuse=True) # load FP32 model
431
+ nc, names = model.nc, model.names # number of classes, class names
432
+
433
+ # Checks
434
+ imgsz *= 2 if len(imgsz) == 1 else 1 # expand
435
+ opset = 12 if ('openvino' in include) else opset # OpenVINO requires opset <= 12
436
+ assert nc == len(names), f'Model class count {nc} != len(names) {len(names)}'
437
+
438
+ # Input
439
+ gs = int(max(model.stride)) # grid size (max stride)
440
+ imgsz = [check_img_size(x, gs) for x in imgsz] # verify img_size are gs-multiples
441
+ im = torch.zeros(batch_size, 3, *imgsz).to(device) # image size(1,3,320,192) BCHW iDetection
442
+
443
+ # Update model
444
+ if half:
445
+ im, model = im.half(), model.half() # to FP16
446
+ model.train() if train else model.eval() # training mode = no Detect() layer grid construction
447
+ for k, m in model.named_modules():
448
+ if isinstance(m, Conv): # assign export-friendly activations
449
+ if isinstance(m.act, nn.SiLU):
450
+ m.act = SiLU()
451
+ elif isinstance(m, Detect):
452
+ m.inplace = inplace
453
+ m.onnx_dynamic = dynamic
454
+ if hasattr(m, 'forward_export'):
455
+ m.forward = m.forward_export # assign custom forward (optional)
456
+
457
+ for _ in range(2):
458
+ y = model(im) # dry runs
459
+ shape = tuple(y[0].shape) # model output shape
460
+ LOGGER.info(f"\n{colorstr('PyTorch:')} starting from {file} with output shape {shape} ({file_size(file):.1f} MB)")
461
+
462
+ # Exports
463
+ f = [''] * 10 # exported filenames
464
+ warnings.filterwarnings(action='ignore', category=torch.jit.TracerWarning) # suppress TracerWarning
465
+ if 'torchscript' in include:
466
+ f[0] = export_torchscript(model, im, file, optimize)
467
+ if 'engine' in include: # TensorRT required before ONNX
468
+ f[1] = export_engine(model, im, file, train, half, simplify, workspace, verbose)
469
+ if ('onnx' in include) or ('openvino' in include): # OpenVINO requires ONNX
470
+ f[2] = export_onnx(model, im, file, opset, train, dynamic, simplify)
471
+ if 'openvino' in include:
472
+ f[3] = export_openvino(model, im, file)
473
+ if 'coreml' in include:
474
+ _, f[4] = export_coreml(model, im, file)
475
+
476
+ # TensorFlow Exports
477
+ if any(tf_exports):
478
+ pb, tflite, edgetpu, tfjs = tf_exports[1:]
479
+ if int8 or edgetpu: # TFLite --int8 bug https://github.com/ultralytics/yolov5/issues/5707
480
+ check_requirements(('flatbuffers==1.12',)) # required before `import tensorflow`
481
+ assert not (tflite and tfjs), 'TFLite and TF.js models must be exported separately, please pass only one type.'
482
+ model, f[5] = export_saved_model(model, im, file, dynamic, tf_nms=nms or agnostic_nms or tfjs,
483
+ agnostic_nms=agnostic_nms or tfjs, topk_per_class=topk_per_class,
484
+ topk_all=topk_all, conf_thres=conf_thres, iou_thres=iou_thres) # keras model
485
+ if pb or tfjs: # pb prerequisite to tfjs
486
+ f[6] = export_pb(model, im, file)
487
+ if tflite or edgetpu:
488
+ f[7] = export_tflite(model, im, file, int8=int8 or edgetpu, data=data, ncalib=100)
489
+ if edgetpu:
490
+ f[8] = export_edgetpu(model, im, file)
491
+ if tfjs:
492
+ f[9] = export_tfjs(model, im, file)
493
+
494
+ # Finish
495
+ f = [str(x) for x in f if x] # filter out '' and None
496
+ if any(f):
497
+ LOGGER.info(f'\nExport complete ({time.time() - t:.2f}s)'
498
+ f"\nResults saved to {colorstr('bold', file.parent.resolve())}"
499
+ f"\nDetect: python detect.py --weights {f[-1]}"
500
+ f"\nPyTorch Hub: model = torch.hub.load('ultralytics/yolov5', 'custom', '{f[-1]}')"
501
+ f"\nValidate: python val.py --weights {f[-1]}"
502
+ f"\nVisualize: https://netron.app")
503
+ return f # return list of exported files/dirs
504
+
505
+
506
+ def parse_opt():
507
+ parser = argparse.ArgumentParser()
508
+ parser.add_argument('--data', type=str, default=ROOT / 'data/coco128.yaml', help='dataset.yaml path')
509
+ parser.add_argument('--weights', nargs='+', type=str, default=ROOT / 'yolov5s.pt', help='model.pt path(s)')
510
+ parser.add_argument('--imgsz', '--img', '--img-size', nargs='+', type=int, default=[640, 640], help='image (h, w)')
511
+ parser.add_argument('--batch-size', type=int, default=1, help='batch size')
512
+ parser.add_argument('--device', default='cpu', help='cuda device, i.e. 0 or 0,1,2,3 or cpu')
513
+ parser.add_argument('--half', action='store_true', help='FP16 half-precision export')
514
+ parser.add_argument('--inplace', action='store_true', help='set YOLOv5 Detect() inplace=True')
515
+ parser.add_argument('--train', action='store_true', help='model.train() mode')
516
+ parser.add_argument('--optimize', action='store_true', help='TorchScript: optimize for mobile')
517
+ parser.add_argument('--int8', action='store_true', help='CoreML/TF INT8 quantization')
518
+ parser.add_argument('--dynamic', action='store_true', help='ONNX/TF: dynamic axes')
519
+ parser.add_argument('--simplify', action='store_true', help='ONNX: simplify model')
520
+ parser.add_argument('--opset', type=int, default=12, help='ONNX: opset version')
521
+ parser.add_argument('--verbose', action='store_true', help='TensorRT: verbose log')
522
+ parser.add_argument('--workspace', type=int, default=4, help='TensorRT: workspace size (GB)')
523
+ parser.add_argument('--nms', action='store_true', help='TF: add NMS to model')
524
+ parser.add_argument('--agnostic-nms', action='store_true', help='TF: add agnostic NMS to model')
525
+ parser.add_argument('--topk-per-class', type=int, default=100, help='TF.js NMS: topk per class to keep')
526
+ parser.add_argument('--topk-all', type=int, default=100, help='TF.js NMS: topk for all classes to keep')
527
+ parser.add_argument('--iou-thres', type=float, default=0.45, help='TF.js NMS: IoU threshold')
528
+ parser.add_argument('--conf-thres', type=float, default=0.25, help='TF.js NMS: confidence threshold')
529
+ parser.add_argument('--include', nargs='+',
530
+ default=['torchscript', 'onnx'],
531
+ help='torchscript, onnx, openvino, engine, coreml, saved_model, pb, tflite, edgetpu, tfjs')
532
+ opt = parser.parse_args()
533
+ print_args(FILE.stem, opt)
534
+ return opt
535
+
536
+
537
+ def main(opt):
538
+ for opt.weights in (opt.weights if isinstance(opt.weights, list) else [opt.weights]):
539
+ run(**vars(opt))
540
+
541
+
542
+ if __name__ == "__main__":
543
+ opt = parse_opt()
544
+ main(opt)
yolov5/models/__init__.py ADDED
File without changes
yolov5/models/__pycache__/__init__.cpython-36.pyc ADDED
Binary file (160 Bytes). View file
 
yolov5/models/__pycache__/__init__.cpython-39.pyc ADDED
Binary file (171 Bytes). View file
 
yolov5/models/__pycache__/common.cpython-36.pyc ADDED
Binary file (30.5 kB). View file
 
yolov5/models/__pycache__/common.cpython-39.pyc ADDED
Binary file (29.9 kB). View file
 
yolov5/models/__pycache__/experimental.cpython-36.pyc ADDED
Binary file (4.97 kB). View file
 
yolov5/models/__pycache__/experimental.cpython-39.pyc ADDED
Binary file (4.91 kB). View file
 
yolov5/models/__pycache__/yolo.cpython-36.pyc ADDED
Binary file (12.7 kB). View file
 
yolov5/models/__pycache__/yolo.cpython-39.pyc ADDED
Binary file (12.6 kB). View file
 
yolov5/models/common.py ADDED
@@ -0,0 +1,674 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # YOLOv5 πŸš€ by Ultralytics, GPL-3.0 license
2
+ """
3
+ Common modules
4
+ """
5
+
6
+ import json
7
+ import math
8
+ import platform
9
+ import warnings
10
+ from collections import OrderedDict, namedtuple
11
+ from copy import copy
12
+ from pathlib import Path
13
+
14
+ import cv2
15
+ import numpy as np
16
+ import pandas as pd
17
+ import requests
18
+ import torch
19
+ import torch.nn as nn
20
+ import yaml
21
+ from PIL import Image
22
+ from torch.cuda import amp
23
+
24
+ from yolov5.utils.datasets import exif_transpose
25
+ from yolov5.utils.augmentations import letterbox
26
+ from yolov5.utils.general import (LOGGER, check_requirements, check_suffix, check_version, colorstr, increment_path,
27
+ make_divisible, non_max_suppression, scale_coords, xywh2xyxy, xyxy2xywh)
28
+ from yolov5.utils.plots import Annotator, colors, save_one_box
29
+ from yolov5.utils.torch_utils import copy_attr, time_sync
30
+
31
+
32
+ def autopad(k, p=None): # kernel, padding
33
+ # Pad to 'same'
34
+ if p is None:
35
+ p = k // 2 if isinstance(k, int) else [x // 2 for x in k] # auto-pad
36
+ return p
37
+
38
+
39
+ class Conv(nn.Module):
40
+ # Standard convolution
41
+ def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True): # ch_in, ch_out, kernel, stride, padding, groups
42
+ super().__init__()
43
+ self.conv = nn.Conv2d(c1, c2, k, s, autopad(k, p), groups=g, bias=False)
44
+ self.bn = nn.BatchNorm2d(c2)
45
+ self.act = nn.SiLU() if act is True else (act if isinstance(act, nn.Module) else nn.Identity())
46
+
47
+ def forward(self, x):
48
+ return self.act(self.bn(self.conv(x)))
49
+
50
+ def forward_fuse(self, x):
51
+ return self.act(self.conv(x))
52
+
53
+
54
+ class DWConv(Conv):
55
+ # Depth-wise convolution class
56
+ def __init__(self, c1, c2, k=1, s=1, act=True): # ch_in, ch_out, kernel, stride, padding, groups
57
+ super().__init__(c1, c2, k, s, g=math.gcd(c1, c2), act=act)
58
+
59
+
60
+ class TransformerLayer(nn.Module):
61
+ # Transformer layer https://arxiv.org/abs/2010.11929 (LayerNorm layers removed for better performance)
62
+ def __init__(self, c, num_heads):
63
+ super().__init__()
64
+ self.q = nn.Linear(c, c, bias=False)
65
+ self.k = nn.Linear(c, c, bias=False)
66
+ self.v = nn.Linear(c, c, bias=False)
67
+ self.ma = nn.MultiheadAttention(embed_dim=c, num_heads=num_heads)
68
+ self.fc1 = nn.Linear(c, c, bias=False)
69
+ self.fc2 = nn.Linear(c, c, bias=False)
70
+
71
+ def forward(self, x):
72
+ x = self.ma(self.q(x), self.k(x), self.v(x))[0] + x
73
+ x = self.fc2(self.fc1(x)) + x
74
+ return x
75
+
76
+
77
+ class TransformerBlock(nn.Module):
78
+ # Vision Transformer https://arxiv.org/abs/2010.11929
79
+ def __init__(self, c1, c2, num_heads, num_layers):
80
+ super().__init__()
81
+ self.conv = None
82
+ if c1 != c2:
83
+ self.conv = Conv(c1, c2)
84
+ self.linear = nn.Linear(c2, c2) # learnable position embedding
85
+ self.tr = nn.Sequential(*(TransformerLayer(c2, num_heads) for _ in range(num_layers)))
86
+ self.c2 = c2
87
+
88
+ def forward(self, x):
89
+ if self.conv is not None:
90
+ x = self.conv(x)
91
+ b, _, w, h = x.shape
92
+ p = x.flatten(2).permute(2, 0, 1)
93
+ return self.tr(p + self.linear(p)).permute(1, 2, 0).reshape(b, self.c2, w, h)
94
+
95
+
96
+ class Bottleneck(nn.Module):
97
+ # Standard bottleneck
98
+ def __init__(self, c1, c2, shortcut=True, g=1, e=0.5): # ch_in, ch_out, shortcut, groups, expansion
99
+ super().__init__()
100
+ c_ = int(c2 * e) # hidden channels
101
+ self.cv1 = Conv(c1, c_, 1, 1)
102
+ self.cv2 = Conv(c_, c2, 3, 1, g=g)
103
+ self.add = shortcut and c1 == c2
104
+
105
+ def forward(self, x):
106
+ return x + self.cv2(self.cv1(x)) if self.add else self.cv2(self.cv1(x))
107
+
108
+
109
+ class BottleneckCSP(nn.Module):
110
+ # CSP Bottleneck https://github.com/WongKinYiu/CrossStagePartialNetworks
111
+ def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): # ch_in, ch_out, number, shortcut, groups, expansion
112
+ super().__init__()
113
+ c_ = int(c2 * e) # hidden channels
114
+ self.cv1 = Conv(c1, c_, 1, 1)
115
+ self.cv2 = nn.Conv2d(c1, c_, 1, 1, bias=False)
116
+ self.cv3 = nn.Conv2d(c_, c_, 1, 1, bias=False)
117
+ self.cv4 = Conv(2 * c_, c2, 1, 1)
118
+ self.bn = nn.BatchNorm2d(2 * c_) # applied to cat(cv2, cv3)
119
+ self.act = nn.SiLU()
120
+ self.m = nn.Sequential(*(Bottleneck(c_, c_, shortcut, g, e=1.0) for _ in range(n)))
121
+
122
+ def forward(self, x):
123
+ y1 = self.cv3(self.m(self.cv1(x)))
124
+ y2 = self.cv2(x)
125
+ return self.cv4(self.act(self.bn(torch.cat((y1, y2), dim=1))))
126
+
127
+
128
+ class C3(nn.Module):
129
+ # CSP Bottleneck with 3 convolutions
130
+ def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): # ch_in, ch_out, number, shortcut, groups, expansion
131
+ super().__init__()
132
+ c_ = int(c2 * e) # hidden channels
133
+ self.cv1 = Conv(c1, c_, 1, 1)
134
+ self.cv2 = Conv(c1, c_, 1, 1)
135
+ self.cv3 = Conv(2 * c_, c2, 1) # act=FReLU(c2)
136
+ self.m = nn.Sequential(*(Bottleneck(c_, c_, shortcut, g, e=1.0) for _ in range(n)))
137
+ # self.m = nn.Sequential(*[CrossConv(c_, c_, 3, 1, g, 1.0, shortcut) for _ in range(n)])
138
+
139
+ def forward(self, x):
140
+ return self.cv3(torch.cat((self.m(self.cv1(x)), self.cv2(x)), dim=1))
141
+
142
+
143
+ class C3TR(C3):
144
+ # C3 module with TransformerBlock()
145
+ def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5):
146
+ super().__init__(c1, c2, n, shortcut, g, e)
147
+ c_ = int(c2 * e)
148
+ self.m = TransformerBlock(c_, c_, 4, n)
149
+
150
+
151
+ class C3SPP(C3):
152
+ # C3 module with SPP()
153
+ def __init__(self, c1, c2, k=(5, 9, 13), n=1, shortcut=True, g=1, e=0.5):
154
+ super().__init__(c1, c2, n, shortcut, g, e)
155
+ c_ = int(c2 * e)
156
+ self.m = SPP(c_, c_, k)
157
+
158
+
159
+ class C3Ghost(C3):
160
+ # C3 module with GhostBottleneck()
161
+ def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5):
162
+ super().__init__(c1, c2, n, shortcut, g, e)
163
+ c_ = int(c2 * e) # hidden channels
164
+ self.m = nn.Sequential(*(GhostBottleneck(c_, c_) for _ in range(n)))
165
+
166
+
167
+ class SPP(nn.Module):
168
+ # Spatial Pyramid Pooling (SPP) layer https://arxiv.org/abs/1406.4729
169
+ def __init__(self, c1, c2, k=(5, 9, 13)):
170
+ super().__init__()
171
+ c_ = c1 // 2 # hidden channels
172
+ self.cv1 = Conv(c1, c_, 1, 1)
173
+ self.cv2 = Conv(c_ * (len(k) + 1), c2, 1, 1)
174
+ self.m = nn.ModuleList([nn.MaxPool2d(kernel_size=x, stride=1, padding=x // 2) for x in k])
175
+
176
+ def forward(self, x):
177
+ x = self.cv1(x)
178
+ with warnings.catch_warnings():
179
+ warnings.simplefilter('ignore') # suppress torch 1.9.0 max_pool2d() warning
180
+ return self.cv2(torch.cat([x] + [m(x) for m in self.m], 1))
181
+
182
+
183
+ class SPPF(nn.Module):
184
+ # Spatial Pyramid Pooling - Fast (SPPF) layer for YOLOv5 by Glenn Jocher
185
+ def __init__(self, c1, c2, k=5): # equivalent to SPP(k=(5, 9, 13))
186
+ super().__init__()
187
+ c_ = c1 // 2 # hidden channels
188
+ self.cv1 = Conv(c1, c_, 1, 1)
189
+ self.cv2 = Conv(c_ * 4, c2, 1, 1)
190
+ self.m = nn.MaxPool2d(kernel_size=k, stride=1, padding=k // 2)
191
+
192
+ def forward(self, x):
193
+ x = self.cv1(x)
194
+ with warnings.catch_warnings():
195
+ warnings.simplefilter('ignore') # suppress torch 1.9.0 max_pool2d() warning
196
+ y1 = self.m(x)
197
+ y2 = self.m(y1)
198
+ return self.cv2(torch.cat([x, y1, y2, self.m(y2)], 1))
199
+
200
+
201
+ class Focus(nn.Module):
202
+ # Focus wh information into c-space
203
+ def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True): # ch_in, ch_out, kernel, stride, padding, groups
204
+ super().__init__()
205
+ self.conv = Conv(c1 * 4, c2, k, s, p, g, act)
206
+ # self.contract = Contract(gain=2)
207
+
208
+ def forward(self, x): # x(b,c,w,h) -> y(b,4c,w/2,h/2)
209
+ return self.conv(torch.cat([x[..., ::2, ::2], x[..., 1::2, ::2], x[..., ::2, 1::2], x[..., 1::2, 1::2]], 1))
210
+ # return self.conv(self.contract(x))
211
+
212
+
213
+ class GhostConv(nn.Module):
214
+ # Ghost Convolution https://github.com/huawei-noah/ghostnet
215
+ def __init__(self, c1, c2, k=1, s=1, g=1, act=True): # ch_in, ch_out, kernel, stride, groups
216
+ super().__init__()
217
+ c_ = c2 // 2 # hidden channels
218
+ self.cv1 = Conv(c1, c_, k, s, None, g, act)
219
+ self.cv2 = Conv(c_, c_, 5, 1, None, c_, act)
220
+
221
+ def forward(self, x):
222
+ y = self.cv1(x)
223
+ return torch.cat([y, self.cv2(y)], 1)
224
+
225
+
226
+ class GhostBottleneck(nn.Module):
227
+ # Ghost Bottleneck https://github.com/huawei-noah/ghostnet
228
+ def __init__(self, c1, c2, k=3, s=1): # ch_in, ch_out, kernel, stride
229
+ super().__init__()
230
+ c_ = c2 // 2
231
+ self.conv = nn.Sequential(GhostConv(c1, c_, 1, 1), # pw
232
+ DWConv(c_, c_, k, s, act=False) if s == 2 else nn.Identity(), # dw
233
+ GhostConv(c_, c2, 1, 1, act=False)) # pw-linear
234
+ self.shortcut = nn.Sequential(DWConv(c1, c1, k, s, act=False),
235
+ Conv(c1, c2, 1, 1, act=False)) if s == 2 else nn.Identity()
236
+
237
+ def forward(self, x):
238
+ return self.conv(x) + self.shortcut(x)
239
+
240
+
241
+ class Contract(nn.Module):
242
+ # Contract width-height into channels, i.e. x(1,64,80,80) to x(1,256,40,40)
243
+ def __init__(self, gain=2):
244
+ super().__init__()
245
+ self.gain = gain
246
+
247
+ def forward(self, x):
248
+ b, c, h, w = x.size() # assert (h / s == 0) and (W / s == 0), 'Indivisible gain'
249
+ s = self.gain
250
+ x = x.view(b, c, h // s, s, w // s, s) # x(1,64,40,2,40,2)
251
+ x = x.permute(0, 3, 5, 1, 2, 4).contiguous() # x(1,2,2,64,40,40)
252
+ return x.view(b, c * s * s, h // s, w // s) # x(1,256,40,40)
253
+
254
+
255
+ class Expand(nn.Module):
256
+ # Expand channels into width-height, i.e. x(1,64,80,80) to x(1,16,160,160)
257
+ def __init__(self, gain=2):
258
+ super().__init__()
259
+ self.gain = gain
260
+
261
+ def forward(self, x):
262
+ b, c, h, w = x.size() # assert C / s ** 2 == 0, 'Indivisible gain'
263
+ s = self.gain
264
+ x = x.view(b, s, s, c // s ** 2, h, w) # x(1,2,2,16,80,80)
265
+ x = x.permute(0, 3, 4, 1, 5, 2).contiguous() # x(1,16,80,2,80,2)
266
+ return x.view(b, c // s ** 2, h * s, w * s) # x(1,16,160,160)
267
+
268
+
269
+ class Concat(nn.Module):
270
+ # Concatenate a list of tensors along dimension
271
+ def __init__(self, dimension=1):
272
+ super().__init__()
273
+ self.d = dimension
274
+
275
+ def forward(self, x):
276
+ return torch.cat(x, self.d)
277
+
278
+
279
+ class DetectMultiBackend(nn.Module):
280
+ # YOLOv5 MultiBackend class for python inference on various backends
281
+ def __init__(self, weights='yolov5s.pt', device=None, dnn=False, data=None):
282
+ # Usage:
283
+ # PyTorch: weights = *.pt
284
+ # TorchScript: *.torchscript
285
+ # CoreML: *.mlmodel
286
+ # OpenVINO: *.xml
287
+ # TensorFlow: *_saved_model
288
+ # TensorFlow: *.pb
289
+ # TensorFlow Lite: *.tflite
290
+ # TensorFlow Edge TPU: *_edgetpu.tflite
291
+ # ONNX Runtime: *.onnx
292
+ # OpenCV DNN: *.onnx with dnn=True
293
+ # TensorRT: *.engine
294
+ from yolov5.models.experimental import attempt_download, attempt_load # scoped to avoid circular import
295
+
296
+ super().__init__()
297
+ w = str(weights[0] if isinstance(weights, list) else weights)
298
+ pt, jit, onnx, xml, engine, coreml, saved_model, pb, tflite, edgetpu, tfjs = self.model_type(w) # get backend
299
+ stride, names = 64, [f'class{i}' for i in range(1000)] # assign defaults
300
+ w = attempt_download(w) # download if not local
301
+ if data: # data.yaml path (optional)
302
+ with open(data, errors='ignore') as f:
303
+ names = yaml.safe_load(f)['names'] # class names
304
+
305
+ if pt: # PyTorch
306
+ model = attempt_load(weights if isinstance(weights, list) else w, map_location=device)
307
+ stride = max(int(model.stride.max()), 32) # model stride
308
+ names = model.module.names if hasattr(model, 'module') else model.names # get class names
309
+ self.model = model # explicitly assign for to(), cpu(), cuda(), half()
310
+ elif jit: # TorchScript
311
+ LOGGER.info(f'Loading {w} for TorchScript inference...')
312
+ extra_files = {'config.txt': ''} # model metadata
313
+ model = torch.jit.load(w, _extra_files=extra_files)
314
+ if extra_files['config.txt']:
315
+ d = json.loads(extra_files['config.txt']) # extra_files dict
316
+ stride, names = int(d['stride']), d['names']
317
+ elif dnn: # ONNX OpenCV DNN
318
+ LOGGER.info(f'Loading {w} for ONNX OpenCV DNN inference...')
319
+ check_requirements(('opencv-python>=4.5.4',))
320
+ net = cv2.dnn.readNetFromONNX(w)
321
+ elif onnx: # ONNX Runtime
322
+ LOGGER.info(f'Loading {w} for ONNX Runtime inference...')
323
+ cuda = torch.cuda.is_available()
324
+ check_requirements(('onnx', 'onnxruntime-gpu' if cuda else 'onnxruntime'))
325
+ import onnxruntime
326
+ providers = ['CUDAExecutionProvider', 'CPUExecutionProvider'] if cuda else ['CPUExecutionProvider']
327
+ session = onnxruntime.InferenceSession(w, providers=providers)
328
+ elif xml: # OpenVINO
329
+ LOGGER.info(f'Loading {w} for OpenVINO inference...')
330
+ check_requirements(('openvino-dev',)) # requires openvino-dev: https://pypi.org/project/openvino-dev/
331
+ import openvino.inference_engine as ie
332
+ core = ie.IECore()
333
+ if not Path(w).is_file(): # if not *.xml
334
+ w = next(Path(w).glob('*.xml')) # get *.xml file from *_openvino_model dir
335
+ network = core.read_network(model=w, weights=Path(w).with_suffix('.bin')) # *.xml, *.bin paths
336
+ executable_network = core.load_network(network, device_name='CPU', num_requests=1)
337
+ elif engine: # TensorRT
338
+ LOGGER.info(f'Loading {w} for TensorRT inference...')
339
+ import tensorrt as trt # https://developer.nvidia.com/nvidia-tensorrt-download
340
+ check_version(trt.__version__, '7.0.0', hard=True) # require tensorrt>=7.0.0
341
+ Binding = namedtuple('Binding', ('name', 'dtype', 'shape', 'data', 'ptr'))
342
+ logger = trt.Logger(trt.Logger.INFO)
343
+ with open(w, 'rb') as f, trt.Runtime(logger) as runtime:
344
+ model = runtime.deserialize_cuda_engine(f.read())
345
+ bindings = OrderedDict()
346
+ for index in range(model.num_bindings):
347
+ name = model.get_binding_name(index)
348
+ dtype = trt.nptype(model.get_binding_dtype(index))
349
+ shape = tuple(model.get_binding_shape(index))
350
+ data = torch.from_numpy(np.empty(shape, dtype=np.dtype(dtype))).to(device)
351
+ bindings[name] = Binding(name, dtype, shape, data, int(data.data_ptr()))
352
+ binding_addrs = OrderedDict((n, d.ptr) for n, d in bindings.items())
353
+ context = model.create_execution_context()
354
+ batch_size = bindings['images'].shape[0]
355
+ elif coreml: # CoreML
356
+ LOGGER.info(f'Loading {w} for CoreML inference...')
357
+ import coremltools as ct
358
+ model = ct.models.MLModel(w)
359
+ else: # TensorFlow (SavedModel, GraphDef, Lite, Edge TPU)
360
+ if saved_model: # SavedModel
361
+ LOGGER.info(f'Loading {w} for TensorFlow SavedModel inference...')
362
+ import tensorflow as tf
363
+ model = tf.keras.models.load_model(w)
364
+ elif pb: # GraphDef https://www.tensorflow.org/guide/migrate#a_graphpb_or_graphpbtxt
365
+ LOGGER.info(f'Loading {w} for TensorFlow GraphDef inference...')
366
+ import tensorflow as tf
367
+
368
+ def wrap_frozen_graph(gd, inputs, outputs):
369
+ x = tf.compat.v1.wrap_function(lambda: tf.compat.v1.import_graph_def(gd, name=""), []) # wrapped
370
+ return x.prune(tf.nest.map_structure(x.graph.as_graph_element, inputs),
371
+ tf.nest.map_structure(x.graph.as_graph_element, outputs))
372
+
373
+ graph_def = tf.Graph().as_graph_def()
374
+ graph_def.ParseFromString(open(w, 'rb').read())
375
+ frozen_func = wrap_frozen_graph(gd=graph_def, inputs="x:0", outputs="Identity:0")
376
+ elif tflite: # https://www.tensorflow.org/lite/guide/python#install_tensorflow_lite_for_python
377
+ try: # https://coral.ai/docs/edgetpu/tflite-python/#update-existing-tf-lite-code-for-the-edge-tpu
378
+ from tflite_runtime.interpreter import Interpreter, load_delegate
379
+ except ImportError:
380
+ import tensorflow as tf
381
+ Interpreter, load_delegate = tf.lite.Interpreter, tf.lite.experimental.load_delegate,
382
+ if 'edgetpu' in w.lower(): # Edge TPU https://coral.ai/software/#edgetpu-runtime
383
+ LOGGER.info(f'Loading {w} for TensorFlow Lite Edge TPU inference...')
384
+ delegate = {'Linux': 'libedgetpu.so.1',
385
+ 'Darwin': 'libedgetpu.1.dylib',
386
+ 'Windows': 'edgetpu.dll'}[platform.system()]
387
+ interpreter = Interpreter(model_path=w, experimental_delegates=[load_delegate(delegate)])
388
+ else: # Lite
389
+ LOGGER.info(f'Loading {w} for TensorFlow Lite inference...')
390
+ interpreter = Interpreter(model_path=w) # load TFLite model
391
+ interpreter.allocate_tensors() # allocate
392
+ input_details = interpreter.get_input_details() # inputs
393
+ output_details = interpreter.get_output_details() # outputs
394
+ self.__dict__.update(locals()) # assign all variables to self
395
+
396
+ def forward(self, im, augment=False, visualize=False, val=False):
397
+ # YOLOv5 MultiBackend inference
398
+ b, ch, h, w = im.shape # batch, channel, height, width
399
+ if self.pt or self.jit: # PyTorch
400
+ y = self.model(im) if self.jit else self.model(im, augment=augment, visualize=visualize)
401
+ return y if val else y[0]
402
+ elif self.dnn: # ONNX OpenCV DNN
403
+ im = im.cpu().numpy() # torch to numpy
404
+ self.net.setInput(im)
405
+ y = self.net.forward()
406
+ elif self.onnx: # ONNX Runtime
407
+ im = im.cpu().numpy() # torch to numpy
408
+ y = self.session.run([self.session.get_outputs()[0].name], {self.session.get_inputs()[0].name: im})[0]
409
+ elif self.xml: # OpenVINO
410
+ im = im.cpu().numpy() # FP32
411
+ desc = self.ie.TensorDesc(precision='FP32', dims=im.shape, layout='NCHW') # Tensor Description
412
+ request = self.executable_network.requests[0] # inference request
413
+ request.set_blob(blob_name='images', blob=self.ie.Blob(desc, im)) # name=next(iter(request.input_blobs))
414
+ request.infer()
415
+ y = request.output_blobs['output'].buffer # name=next(iter(request.output_blobs))
416
+ elif self.engine: # TensorRT
417
+ assert im.shape == self.bindings['images'].shape, (im.shape, self.bindings['images'].shape)
418
+ self.binding_addrs['images'] = int(im.data_ptr())
419
+ self.context.execute_v2(list(self.binding_addrs.values()))
420
+ y = self.bindings['output'].data
421
+ elif self.coreml: # CoreML
422
+ im = im.permute(0, 2, 3, 1).cpu().numpy() # torch BCHW to numpy BHWC shape(1,320,192,3)
423
+ im = Image.fromarray((im[0] * 255).astype('uint8'))
424
+ # im = im.resize((192, 320), Image.ANTIALIAS)
425
+ y = self.model.predict({'image': im}) # coordinates are xywh normalized
426
+ if 'confidence' in y:
427
+ box = xywh2xyxy(y['coordinates'] * [[w, h, w, h]]) # xyxy pixels
428
+ conf, cls = y['confidence'].max(1), y['confidence'].argmax(1).astype(np.float)
429
+ y = np.concatenate((box, conf.reshape(-1, 1), cls.reshape(-1, 1)), 1)
430
+ else:
431
+ y = y[sorted(y)[-1]] # last output
432
+ else: # TensorFlow (SavedModel, GraphDef, Lite, Edge TPU)
433
+ im = im.permute(0, 2, 3, 1).cpu().numpy() # torch BCHW to numpy BHWC shape(1,320,192,3)
434
+ if self.saved_model: # SavedModel
435
+ y = self.model(im, training=False).numpy()
436
+ elif self.pb: # GraphDef
437
+ y = self.frozen_func(x=self.tf.constant(im)).numpy()
438
+ elif self.tflite: # Lite
439
+ input, output = self.input_details[0], self.output_details[0]
440
+ int8 = input['dtype'] == np.uint8 # is TFLite quantized uint8 model
441
+ if int8:
442
+ scale, zero_point = input['quantization']
443
+ im = (im / scale + zero_point).astype(np.uint8) # de-scale
444
+ self.interpreter.set_tensor(input['index'], im)
445
+ self.interpreter.invoke()
446
+ y = self.interpreter.get_tensor(output['index'])
447
+ if int8:
448
+ scale, zero_point = output['quantization']
449
+ y = (y.astype(np.float32) - zero_point) * scale # re-scale
450
+ y[..., :4] *= [w, h, w, h] # xywh normalized to pixels
451
+
452
+ y = torch.tensor(y) if isinstance(y, np.ndarray) else y
453
+ return (y, []) if val else y
454
+
455
+ def warmup(self, imgsz=(1, 3, 640, 640), half=False):
456
+ # Warmup model by running inference once
457
+ if self.pt or self.jit or self.onnx or self.engine: # warmup types
458
+ if isinstance(self.device, torch.device) and self.device.type != 'cpu': # only warmup GPU models
459
+ im = torch.zeros(*imgsz).to(self.device).type(torch.half if half else torch.float) # input image
460
+ self.forward(im) # warmup
461
+
462
+ @staticmethod
463
+ def model_type(p='path/to/model.pt'):
464
+ # Return model type from model path, i.e. path='path/to/model.onnx' -> type=onnx
465
+ from yolov5.export import export_formats
466
+ suffixes = list(export_formats().Suffix) + ['.xml'] # export suffixes
467
+ check_suffix(p, suffixes) # checks
468
+ p = Path(p).name # eliminate trailing separators
469
+ pt, jit, onnx, xml, engine, coreml, saved_model, pb, tflite, edgetpu, tfjs, xml2 = (s in p for s in suffixes)
470
+ xml |= xml2 # *_openvino_model or *.xml
471
+ tflite &= not edgetpu # *.tflite
472
+ return pt, jit, onnx, xml, engine, coreml, saved_model, pb, tflite, edgetpu, tfjs
473
+
474
+
475
+ class AutoShape(nn.Module):
476
+ # YOLOv5 input-robust model wrapper for passing cv2/np/PIL/torch inputs. Includes preprocessing, inference and NMS
477
+ conf = 0.25 # NMS confidence threshold
478
+ iou = 0.45 # NMS IoU threshold
479
+ agnostic = False # NMS class-agnostic
480
+ multi_label = False # NMS multiple labels per box
481
+ classes = None # (optional list) filter by class, i.e. = [0, 15, 16] for COCO persons, cats and dogs
482
+ max_det = 1000 # maximum number of detections per image
483
+ amp = False # Automatic Mixed Precision (AMP) inference
484
+
485
+ def __init__(self, model):
486
+ super().__init__()
487
+ LOGGER.info('Adding AutoShape... ')
488
+ copy_attr(self, model, include=('yaml', 'nc', 'hyp', 'names', 'stride', 'abc'), exclude=()) # copy attributes
489
+ self.dmb = isinstance(model, DetectMultiBackend) # DetectMultiBackend() instance
490
+ self.pt = not self.dmb or model.pt # PyTorch model
491
+ self.model = model.eval()
492
+
493
+ def _apply(self, fn):
494
+ # Apply to(), cpu(), cuda(), half() to model tensors that are not parameters or registered buffers
495
+ self = super()._apply(fn)
496
+ if self.pt:
497
+ m = self.model.model.model[-1] if self.dmb else self.model.model[-1] # Detect()
498
+ m.stride = fn(m.stride)
499
+ m.grid = list(map(fn, m.grid))
500
+ if isinstance(m.anchor_grid, list):
501
+ m.anchor_grid = list(map(fn, m.anchor_grid))
502
+ return self
503
+
504
+ @torch.no_grad()
505
+ def forward(self, imgs, size=640, augment=False, profile=False):
506
+ # Inference from various sources. For height=640, width=1280, RGB images example inputs are:
507
+ # file: imgs = 'data/images/zidane.jpg' # str or PosixPath
508
+ # URI: = 'https://ultralytics.com/images/zidane.jpg'
509
+ # OpenCV: = cv2.imread('image.jpg')[:,:,::-1] # HWC BGR to RGB x(640,1280,3)
510
+ # PIL: = Image.open('image.jpg') or ImageGrab.grab() # HWC x(640,1280,3)
511
+ # numpy: = np.zeros((640,1280,3)) # HWC
512
+ # torch: = torch.zeros(16,3,320,640) # BCHW (scaled to size=640, 0-1 values)
513
+ # multiple: = [Image.open('image1.jpg'), Image.open('image2.jpg'), ...] # list of images
514
+
515
+ t = [time_sync()]
516
+ p = next(self.model.parameters()) if self.pt else torch.zeros(1) # for device and type
517
+ autocast = self.amp and (p.device.type != 'cpu') # Automatic Mixed Precision (AMP) inference
518
+ if isinstance(imgs, torch.Tensor): # torch
519
+ with amp.autocast(enabled=autocast):
520
+ return self.model(imgs.to(p.device).type_as(p), augment, profile) # inference
521
+
522
+ # Pre-process
523
+ n, imgs = (len(imgs), imgs) if isinstance(imgs, list) else (1, [imgs]) # number of images, list of images
524
+ shape0, shape1, files = [], [], [] # image and inference shapes, filenames
525
+ for i, im in enumerate(imgs):
526
+ f = f'image{i}' # filename
527
+ if isinstance(im, (str, Path)): # filename or uri
528
+ im, f = Image.open(requests.get(im, stream=True).raw if str(im).startswith('http') else im), im
529
+ im = np.asarray(exif_transpose(im))
530
+ elif isinstance(im, Image.Image): # PIL Image
531
+ im, f = np.asarray(exif_transpose(im)), getattr(im, 'filename', f) or f
532
+ files.append(Path(f).with_suffix('.jpg').name)
533
+ if im.shape[0] < 5: # image in CHW
534
+ im = im.transpose((1, 2, 0)) # reverse dataloader .transpose(2, 0, 1)
535
+ im = im[..., :3] if im.ndim == 3 else np.tile(im[..., None], 3) # enforce 3ch input
536
+ s = im.shape[:2] # HWC
537
+ shape0.append(s) # image shape
538
+ g = (size / max(s)) # gain
539
+ shape1.append([y * g for y in s])
540
+ imgs[i] = im if im.data.contiguous else np.ascontiguousarray(im) # update
541
+ shape1 = [make_divisible(x, self.stride) for x in np.stack(shape1, 0).max(0)] # inference shape
542
+ x = [letterbox(im, new_shape=shape1 if self.pt else size, auto=False)[0] for im in imgs] # pad
543
+ x = np.stack(x, 0) if n > 1 else x[0][None] # stack
544
+ x = np.ascontiguousarray(x.transpose((0, 3, 1, 2))) # BHWC to BCHW
545
+ x = torch.from_numpy(x).to(p.device).type_as(p) / 255 # uint8 to fp16/32
546
+ t.append(time_sync())
547
+
548
+ with amp.autocast(enabled=autocast):
549
+ # Inference
550
+ y = self.model(x, augment, profile) # forward
551
+ t.append(time_sync())
552
+
553
+ # Post-process
554
+ y = non_max_suppression(y if self.dmb else y[0], self.conf, iou_thres=self.iou, classes=self.classes,
555
+ agnostic=self.agnostic, multi_label=self.multi_label, max_det=self.max_det) # NMS
556
+ for i in range(n):
557
+ scale_coords(shape1, y[i][:, :4], shape0[i])
558
+
559
+ t.append(time_sync())
560
+ return Detections(imgs, y, files, t, self.names, x.shape)
561
+
562
+
563
+ class Detections:
564
+ # YOLOv5 detections class for inference results
565
+ def __init__(self, imgs, pred, files, times=(0, 0, 0, 0), names=None, shape=None):
566
+ super().__init__()
567
+ d = pred[0].device # device
568
+ gn = [torch.tensor([*(im.shape[i] for i in [1, 0, 1, 0]), 1, 1], device=d) for im in imgs] # normalizations
569
+ self.imgs = imgs # list of images as numpy arrays
570
+ self.pred = pred # list of tensors pred[0] = (xyxy, conf, cls)
571
+ self.names = names # class names
572
+ self.files = files # image filenames
573
+ self.times = times # profiling times
574
+ self.xyxy = pred # xyxy pixels
575
+ self.xywh = [xyxy2xywh(x) for x in pred] # xywh pixels
576
+ self.xyxyn = [x / g for x, g in zip(self.xyxy, gn)] # xyxy normalized
577
+ self.xywhn = [x / g for x, g in zip(self.xywh, gn)] # xywh normalized
578
+ self.n = len(self.pred) # number of images (batch size)
579
+ self.t = tuple((times[i + 1] - times[i]) * 1000 / self.n for i in range(3)) # timestamps (ms)
580
+ self.s = shape # inference BCHW shape
581
+
582
+ def display(self, pprint=False, show=False, save=False, crop=False, render=False, save_dir=Path('')):
583
+ crops = []
584
+ for i, (im, pred) in enumerate(zip(self.imgs, self.pred)):
585
+ s = f'image {i + 1}/{len(self.pred)}: {im.shape[0]}x{im.shape[1]} ' # string
586
+ if pred.shape[0]:
587
+ for c in pred[:, -1].unique():
588
+ n = (pred[:, -1] == c).sum() # detections per class
589
+ s += f"{n} {self.names[int(c)]}{'s' * (n > 1)}, " # add to string
590
+ if show or save or render or crop:
591
+ annotator = Annotator(im, example=str(self.names))
592
+ for *box, conf, cls in reversed(pred): # xyxy, confidence, class
593
+ label = f'{self.names[int(cls)]} {conf:.2f}'
594
+ if crop:
595
+ file = save_dir / 'crops' / self.names[int(cls)] / self.files[i] if save else None
596
+ crops.append({'box': box, 'conf': conf, 'cls': cls, 'label': label,
597
+ 'im': save_one_box(box, im, file=file, save=save)})
598
+ else: # all others
599
+ annotator.box_label(box, label, color=colors(cls))
600
+ im = annotator.im
601
+ else:
602
+ s += '(no detections)'
603
+
604
+ im = Image.fromarray(im.astype(np.uint8)) if isinstance(im, np.ndarray) else im # from np
605
+ if pprint:
606
+ LOGGER.info(s.rstrip(', '))
607
+ if show:
608
+ im.show(self.files[i]) # show
609
+ if save:
610
+ f = self.files[i]
611
+ im.save(save_dir / f) # save
612
+ if i == self.n - 1:
613
+ LOGGER.info(f"Saved {self.n} image{'s' * (self.n > 1)} to {colorstr('bold', save_dir)}")
614
+ if render:
615
+ self.imgs[i] = np.asarray(im)
616
+ if crop:
617
+ if save:
618
+ LOGGER.info(f'Saved results to {save_dir}\n')
619
+ return crops
620
+
621
+ def print(self):
622
+ self.display(pprint=True) # print results
623
+ LOGGER.info(f'Speed: %.1fms pre-process, %.1fms inference, %.1fms NMS per image at shape {tuple(self.s)}' %
624
+ self.t)
625
+
626
+ def show(self):
627
+ self.display(show=True) # show results
628
+
629
+ def save(self, save_dir='runs/detect/exp'):
630
+ save_dir = increment_path(save_dir, exist_ok=save_dir != 'runs/detect/exp', mkdir=True) # increment save_dir
631
+ self.display(save=True, save_dir=save_dir) # save results
632
+
633
+ def crop(self, save=True, save_dir='runs/detect/exp'):
634
+ save_dir = increment_path(save_dir, exist_ok=save_dir != 'runs/detect/exp', mkdir=True) if save else None
635
+ return self.display(crop=True, save=save, save_dir=save_dir) # crop results
636
+
637
+ def render(self):
638
+ self.display(render=True) # render results
639
+ return self.imgs
640
+
641
+ def pandas(self):
642
+ # return detections as pandas DataFrames, i.e. print(results.pandas().xyxy[0])
643
+ new = copy(self) # return copy
644
+ ca = 'xmin', 'ymin', 'xmax', 'ymax', 'confidence', 'class', 'name' # xyxy columns
645
+ cb = 'xcenter', 'ycenter', 'width', 'height', 'confidence', 'class', 'name' # xywh columns
646
+ for k, c in zip(['xyxy', 'xyxyn', 'xywh', 'xywhn'], [ca, ca, cb, cb]):
647
+ a = [[x[:5] + [int(x[5]), self.names[int(x[5])]] for x in x.tolist()] for x in getattr(self, k)] # update
648
+ setattr(new, k, [pd.DataFrame(x, columns=c) for x in a])
649
+ return new
650
+
651
+ def tolist(self):
652
+ # return a list of Detections objects, i.e. 'for result in results.tolist():'
653
+ r = range(self.n) # iterable
654
+ x = [Detections([self.imgs[i]], [self.pred[i]], [self.files[i]], self.times, self.names, self.s) for i in r]
655
+ # for d in x:
656
+ # for k in ['imgs', 'pred', 'xyxy', 'xyxyn', 'xywh', 'xywhn']:
657
+ # setattr(d, k, getattr(d, k)[0]) # pop out of list
658
+ return x
659
+
660
+ def __len__(self):
661
+ return self.n
662
+
663
+
664
+ class Classify(nn.Module):
665
+ # Classification head, i.e. x(b,c1,20,20) to x(b,c2)
666
+ def __init__(self, c1, c2, k=1, s=1, p=None, g=1): # ch_in, ch_out, kernel, stride, padding, groups
667
+ super().__init__()
668
+ self.aap = nn.AdaptiveAvgPool2d(1) # to x(b,c1,1,1)
669
+ self.conv = nn.Conv2d(c1, c2, k, s, autopad(k, p), groups=g) # to x(b,c2,1,1)
670
+ self.flat = nn.Flatten()
671
+
672
+ def forward(self, x):
673
+ z = torch.cat([self.aap(y) for y in (x if isinstance(x, list) else [x])], 1) # cat if list
674
+ return self.flat(self.conv(z)) # flatten to x(b,c2)
yolov5/models/experimental.py ADDED
@@ -0,0 +1,120 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # YOLOv5 πŸš€ by Ultralytics, GPL-3.0 license
2
+ """
3
+ Experimental modules
4
+ """
5
+ import math
6
+
7
+ import numpy as np
8
+ import torch
9
+ import torch.nn as nn
10
+
11
+ from yolov5.models.common import Conv
12
+ from yolov5.utils.downloads import attempt_download
13
+
14
+
15
+ class CrossConv(nn.Module):
16
+ # Cross Convolution Downsample
17
+ def __init__(self, c1, c2, k=3, s=1, g=1, e=1.0, shortcut=False):
18
+ # ch_in, ch_out, kernel, stride, groups, expansion, shortcut
19
+ super().__init__()
20
+ c_ = int(c2 * e) # hidden channels
21
+ self.cv1 = Conv(c1, c_, (1, k), (1, s))
22
+ self.cv2 = Conv(c_, c2, (k, 1), (s, 1), g=g)
23
+ self.add = shortcut and c1 == c2
24
+
25
+ def forward(self, x):
26
+ return x + self.cv2(self.cv1(x)) if self.add else self.cv2(self.cv1(x))
27
+
28
+
29
+ class Sum(nn.Module):
30
+ # Weighted sum of 2 or more layers https://arxiv.org/abs/1911.09070
31
+ def __init__(self, n, weight=False): # n: number of inputs
32
+ super().__init__()
33
+ self.weight = weight # apply weights boolean
34
+ self.iter = range(n - 1) # iter object
35
+ if weight:
36
+ self.w = nn.Parameter(-torch.arange(1.0, n) / 2, requires_grad=True) # layer weights
37
+
38
+ def forward(self, x):
39
+ y = x[0] # no weight
40
+ if self.weight:
41
+ w = torch.sigmoid(self.w) * 2
42
+ for i in self.iter:
43
+ y = y + x[i + 1] * w[i]
44
+ else:
45
+ for i in self.iter:
46
+ y = y + x[i + 1]
47
+ return y
48
+
49
+
50
+ class MixConv2d(nn.Module):
51
+ # Mixed Depth-wise Conv https://arxiv.org/abs/1907.09595
52
+ def __init__(self, c1, c2, k=(1, 3), s=1, equal_ch=True): # ch_in, ch_out, kernel, stride, ch_strategy
53
+ super().__init__()
54
+ n = len(k) # number of convolutions
55
+ if equal_ch: # equal c_ per group
56
+ i = torch.linspace(0, n - 1E-6, c2).floor() # c2 indices
57
+ c_ = [(i == g).sum() for g in range(n)] # intermediate channels
58
+ else: # equal weight.numel() per group
59
+ b = [c2] + [0] * n
60
+ a = np.eye(n + 1, n, k=-1)
61
+ a -= np.roll(a, 1, axis=1)
62
+ a *= np.array(k) ** 2
63
+ a[0] = 1
64
+ c_ = np.linalg.lstsq(a, b, rcond=None)[0].round() # solve for equal weight indices, ax = b
65
+
66
+ self.m = nn.ModuleList(
67
+ [nn.Conv2d(c1, int(c_), k, s, k // 2, groups=math.gcd(c1, int(c_)), bias=False) for k, c_ in zip(k, c_)])
68
+ self.bn = nn.BatchNorm2d(c2)
69
+ self.act = nn.SiLU()
70
+
71
+ def forward(self, x):
72
+ return self.act(self.bn(torch.cat([m(x) for m in self.m], 1)))
73
+
74
+
75
+ class Ensemble(nn.ModuleList):
76
+ # Ensemble of models
77
+ def __init__(self):
78
+ super().__init__()
79
+
80
+ def forward(self, x, augment=False, profile=False, visualize=False):
81
+ y = []
82
+ for module in self:
83
+ y.append(module(x, augment, profile, visualize)[0])
84
+ # y = torch.stack(y).max(0)[0] # max ensemble
85
+ # y = torch.stack(y).mean(0) # mean ensemble
86
+ y = torch.cat(y, 1) # nms ensemble
87
+ return y, None # inference, train output
88
+
89
+
90
+ def attempt_load(weights, map_location=None, inplace=True, fuse=True):
91
+ from models.yolo import Detect, Model
92
+
93
+ # Loads an ensemble of models weights=[a,b,c] or a single model weights=[a] or weights=a
94
+ model = Ensemble()
95
+ for w in weights if isinstance(weights, list) else [weights]:
96
+ ckpt = torch.load(attempt_download(w), map_location=map_location) # load
97
+ if fuse:
98
+ model.append(ckpt['ema' if ckpt.get('ema') else 'model'].float().fuse().eval()) # FP32 model
99
+ else:
100
+ model.append(ckpt['ema' if ckpt.get('ema') else 'model'].float().eval()) # without layer fuse
101
+
102
+ # Compatibility updates
103
+ for m in model.modules():
104
+ if type(m) in [nn.Hardswish, nn.LeakyReLU, nn.ReLU, nn.ReLU6, nn.SiLU, Detect, Model]:
105
+ m.inplace = inplace # pytorch 1.7.0 compatibility
106
+ if type(m) is Detect:
107
+ if not isinstance(m.anchor_grid, list): # new Detect Layer compatibility
108
+ delattr(m, 'anchor_grid')
109
+ setattr(m, 'anchor_grid', [torch.zeros(1)] * m.nl)
110
+ elif type(m) is Conv:
111
+ m._non_persistent_buffers_set = set() # pytorch 1.6.0 compatibility
112
+
113
+ if len(model) == 1:
114
+ return model[-1] # return model
115
+ else:
116
+ print(f'Ensemble created with {weights}\n')
117
+ for k in ['names']:
118
+ setattr(model, k, getattr(model[-1], k))
119
+ model.stride = model[torch.argmax(torch.tensor([m.stride.max() for m in model])).int()].stride # max stride
120
+ return model # return ensemble
yolov5/models/hub/anchors.yaml ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # YOLOv5 πŸš€ by Ultralytics, GPL-3.0 license
2
+ # Default anchors for COCO data
3
+
4
+
5
+ # P5 -------------------------------------------------------------------------------------------------------------------
6
+ # P5-640:
7
+ anchors_p5_640:
8
+ - [10,13, 16,30, 33,23] # P3/8
9
+ - [30,61, 62,45, 59,119] # P4/16
10
+ - [116,90, 156,198, 373,326] # P5/32
11
+
12
+
13
+ # P6 -------------------------------------------------------------------------------------------------------------------
14
+ # P6-640: thr=0.25: 0.9964 BPR, 5.54 anchors past thr, n=12, img_size=640, metric_all=0.281/0.716-mean/best, past_thr=0.469-mean: 9,11, 21,19, 17,41, 43,32, 39,70, 86,64, 65,131, 134,130, 120,265, 282,180, 247,354, 512,387
15
+ anchors_p6_640:
16
+ - [9,11, 21,19, 17,41] # P3/8
17
+ - [43,32, 39,70, 86,64] # P4/16
18
+ - [65,131, 134,130, 120,265] # P5/32
19
+ - [282,180, 247,354, 512,387] # P6/64
20
+
21
+ # P6-1280: thr=0.25: 0.9950 BPR, 5.55 anchors past thr, n=12, img_size=1280, metric_all=0.281/0.714-mean/best, past_thr=0.468-mean: 19,27, 44,40, 38,94, 96,68, 86,152, 180,137, 140,301, 303,264, 238,542, 436,615, 739,380, 925,792
22
+ anchors_p6_1280:
23
+ - [19,27, 44,40, 38,94] # P3/8
24
+ - [96,68, 86,152, 180,137] # P4/16
25
+ - [140,301, 303,264, 238,542] # P5/32
26
+ - [436,615, 739,380, 925,792] # P6/64
27
+
28
+ # P6-1920: thr=0.25: 0.9950 BPR, 5.55 anchors past thr, n=12, img_size=1920, metric_all=0.281/0.714-mean/best, past_thr=0.468-mean: 28,41, 67,59, 57,141, 144,103, 129,227, 270,205, 209,452, 455,396, 358,812, 653,922, 1109,570, 1387,1187
29
+ anchors_p6_1920:
30
+ - [28,41, 67,59, 57,141] # P3/8
31
+ - [144,103, 129,227, 270,205] # P4/16
32
+ - [209,452, 455,396, 358,812] # P5/32
33
+ - [653,922, 1109,570, 1387,1187] # P6/64
34
+
35
+
36
+ # P7 -------------------------------------------------------------------------------------------------------------------
37
+ # P7-640: thr=0.25: 0.9962 BPR, 6.76 anchors past thr, n=15, img_size=640, metric_all=0.275/0.733-mean/best, past_thr=0.466-mean: 11,11, 13,30, 29,20, 30,46, 61,38, 39,92, 78,80, 146,66, 79,163, 149,150, 321,143, 157,303, 257,402, 359,290, 524,372
38
+ anchors_p7_640:
39
+ - [11,11, 13,30, 29,20] # P3/8
40
+ - [30,46, 61,38, 39,92] # P4/16
41
+ - [78,80, 146,66, 79,163] # P5/32
42
+ - [149,150, 321,143, 157,303] # P6/64
43
+ - [257,402, 359,290, 524,372] # P7/128
44
+
45
+ # P7-1280: thr=0.25: 0.9968 BPR, 6.71 anchors past thr, n=15, img_size=1280, metric_all=0.273/0.732-mean/best, past_thr=0.463-mean: 19,22, 54,36, 32,77, 70,83, 138,71, 75,173, 165,159, 148,334, 375,151, 334,317, 251,626, 499,474, 750,326, 534,814, 1079,818
46
+ anchors_p7_1280:
47
+ - [19,22, 54,36, 32,77] # P3/8
48
+ - [70,83, 138,71, 75,173] # P4/16
49
+ - [165,159, 148,334, 375,151] # P5/32
50
+ - [334,317, 251,626, 499,474] # P6/64
51
+ - [750,326, 534,814, 1079,818] # P7/128
52
+
53
+ # P7-1920: thr=0.25: 0.9968 BPR, 6.71 anchors past thr, n=15, img_size=1920, metric_all=0.273/0.732-mean/best, past_thr=0.463-mean: 29,34, 81,55, 47,115, 105,124, 207,107, 113,259, 247,238, 222,500, 563,227, 501,476, 376,939, 749,711, 1126,489, 801,1222, 1618,1227
54
+ anchors_p7_1920:
55
+ - [29,34, 81,55, 47,115] # P3/8
56
+ - [105,124, 207,107, 113,259] # P4/16
57
+ - [247,238, 222,500, 563,227] # P5/32
58
+ - [501,476, 376,939, 749,711] # P6/64
59
+ - [1126,489, 801,1222, 1618,1227] # P7/128
yolov5/models/hub/yolov3-spp.yaml ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # YOLOv5 πŸš€ by Ultralytics, GPL-3.0 license
2
+
3
+ # Parameters
4
+ nc: 80 # number of classes
5
+ depth_multiple: 1.0 # model depth multiple
6
+ width_multiple: 1.0 # layer channel multiple
7
+ anchors:
8
+ - [10,13, 16,30, 33,23] # P3/8
9
+ - [30,61, 62,45, 59,119] # P4/16
10
+ - [116,90, 156,198, 373,326] # P5/32
11
+
12
+ # darknet53 backbone
13
+ backbone:
14
+ # [from, number, module, args]
15
+ [[-1, 1, Conv, [32, 3, 1]], # 0
16
+ [-1, 1, Conv, [64, 3, 2]], # 1-P1/2
17
+ [-1, 1, Bottleneck, [64]],
18
+ [-1, 1, Conv, [128, 3, 2]], # 3-P2/4
19
+ [-1, 2, Bottleneck, [128]],
20
+ [-1, 1, Conv, [256, 3, 2]], # 5-P3/8
21
+ [-1, 8, Bottleneck, [256]],
22
+ [-1, 1, Conv, [512, 3, 2]], # 7-P4/16
23
+ [-1, 8, Bottleneck, [512]],
24
+ [-1, 1, Conv, [1024, 3, 2]], # 9-P5/32
25
+ [-1, 4, Bottleneck, [1024]], # 10
26
+ ]
27
+
28
+ # YOLOv3-SPP head
29
+ head:
30
+ [[-1, 1, Bottleneck, [1024, False]],
31
+ [-1, 1, SPP, [512, [5, 9, 13]]],
32
+ [-1, 1, Conv, [1024, 3, 1]],
33
+ [-1, 1, Conv, [512, 1, 1]],
34
+ [-1, 1, Conv, [1024, 3, 1]], # 15 (P5/32-large)
35
+
36
+ [-2, 1, Conv, [256, 1, 1]],
37
+ [-1, 1, nn.Upsample, [None, 2, 'nearest']],
38
+ [[-1, 8], 1, Concat, [1]], # cat backbone P4
39
+ [-1, 1, Bottleneck, [512, False]],
40
+ [-1, 1, Bottleneck, [512, False]],
41
+ [-1, 1, Conv, [256, 1, 1]],
42
+ [-1, 1, Conv, [512, 3, 1]], # 22 (P4/16-medium)
43
+
44
+ [-2, 1, Conv, [128, 1, 1]],
45
+ [-1, 1, nn.Upsample, [None, 2, 'nearest']],
46
+ [[-1, 6], 1, Concat, [1]], # cat backbone P3
47
+ [-1, 1, Bottleneck, [256, False]],
48
+ [-1, 2, Bottleneck, [256, False]], # 27 (P3/8-small)
49
+
50
+ [[27, 22, 15], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)
51
+ ]
yolov5/models/hub/yolov3-tiny.yaml ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # YOLOv5 πŸš€ by Ultralytics, GPL-3.0 license
2
+
3
+ # Parameters
4
+ nc: 80 # number of classes
5
+ depth_multiple: 1.0 # model depth multiple
6
+ width_multiple: 1.0 # layer channel multiple
7
+ anchors:
8
+ - [10,14, 23,27, 37,58] # P4/16
9
+ - [81,82, 135,169, 344,319] # P5/32
10
+
11
+ # YOLOv3-tiny backbone
12
+ backbone:
13
+ # [from, number, module, args]
14
+ [[-1, 1, Conv, [16, 3, 1]], # 0
15
+ [-1, 1, nn.MaxPool2d, [2, 2, 0]], # 1-P1/2
16
+ [-1, 1, Conv, [32, 3, 1]],
17
+ [-1, 1, nn.MaxPool2d, [2, 2, 0]], # 3-P2/4
18
+ [-1, 1, Conv, [64, 3, 1]],
19
+ [-1, 1, nn.MaxPool2d, [2, 2, 0]], # 5-P3/8
20
+ [-1, 1, Conv, [128, 3, 1]],
21
+ [-1, 1, nn.MaxPool2d, [2, 2, 0]], # 7-P4/16
22
+ [-1, 1, Conv, [256, 3, 1]],
23
+ [-1, 1, nn.MaxPool2d, [2, 2, 0]], # 9-P5/32
24
+ [-1, 1, Conv, [512, 3, 1]],
25
+ [-1, 1, nn.ZeroPad2d, [[0, 1, 0, 1]]], # 11
26
+ [-1, 1, nn.MaxPool2d, [2, 1, 0]], # 12
27
+ ]
28
+
29
+ # YOLOv3-tiny head
30
+ head:
31
+ [[-1, 1, Conv, [1024, 3, 1]],
32
+ [-1, 1, Conv, [256, 1, 1]],
33
+ [-1, 1, Conv, [512, 3, 1]], # 15 (P5/32-large)
34
+
35
+ [-2, 1, Conv, [128, 1, 1]],
36
+ [-1, 1, nn.Upsample, [None, 2, 'nearest']],
37
+ [[-1, 8], 1, Concat, [1]], # cat backbone P4
38
+ [-1, 1, Conv, [256, 3, 1]], # 19 (P4/16-medium)
39
+
40
+ [[19, 15], 1, Detect, [nc, anchors]], # Detect(P4, P5)
41
+ ]
yolov5/models/hub/yolov3.yaml ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # YOLOv5 πŸš€ by Ultralytics, GPL-3.0 license
2
+
3
+ # Parameters
4
+ nc: 80 # number of classes
5
+ depth_multiple: 1.0 # model depth multiple
6
+ width_multiple: 1.0 # layer channel multiple
7
+ anchors:
8
+ - [10,13, 16,30, 33,23] # P3/8
9
+ - [30,61, 62,45, 59,119] # P4/16
10
+ - [116,90, 156,198, 373,326] # P5/32
11
+
12
+ # darknet53 backbone
13
+ backbone:
14
+ # [from, number, module, args]
15
+ [[-1, 1, Conv, [32, 3, 1]], # 0
16
+ [-1, 1, Conv, [64, 3, 2]], # 1-P1/2
17
+ [-1, 1, Bottleneck, [64]],
18
+ [-1, 1, Conv, [128, 3, 2]], # 3-P2/4
19
+ [-1, 2, Bottleneck, [128]],
20
+ [-1, 1, Conv, [256, 3, 2]], # 5-P3/8
21
+ [-1, 8, Bottleneck, [256]],
22
+ [-1, 1, Conv, [512, 3, 2]], # 7-P4/16
23
+ [-1, 8, Bottleneck, [512]],
24
+ [-1, 1, Conv, [1024, 3, 2]], # 9-P5/32
25
+ [-1, 4, Bottleneck, [1024]], # 10
26
+ ]
27
+
28
+ # YOLOv3 head
29
+ head:
30
+ [[-1, 1, Bottleneck, [1024, False]],
31
+ [-1, 1, Conv, [512, [1, 1]]],
32
+ [-1, 1, Conv, [1024, 3, 1]],
33
+ [-1, 1, Conv, [512, 1, 1]],
34
+ [-1, 1, Conv, [1024, 3, 1]], # 15 (P5/32-large)
35
+
36
+ [-2, 1, Conv, [256, 1, 1]],
37
+ [-1, 1, nn.Upsample, [None, 2, 'nearest']],
38
+ [[-1, 8], 1, Concat, [1]], # cat backbone P4
39
+ [-1, 1, Bottleneck, [512, False]],
40
+ [-1, 1, Bottleneck, [512, False]],
41
+ [-1, 1, Conv, [256, 1, 1]],
42
+ [-1, 1, Conv, [512, 3, 1]], # 22 (P4/16-medium)
43
+
44
+ [-2, 1, Conv, [128, 1, 1]],
45
+ [-1, 1, nn.Upsample, [None, 2, 'nearest']],
46
+ [[-1, 6], 1, Concat, [1]], # cat backbone P3
47
+ [-1, 1, Bottleneck, [256, False]],
48
+ [-1, 2, Bottleneck, [256, False]], # 27 (P3/8-small)
49
+
50
+ [[27, 22, 15], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)
51
+ ]
yolov5/models/hub/yolov5-bifpn.yaml ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # YOLOv5 πŸš€ by Ultralytics, GPL-3.0 license
2
+
3
+ # Parameters
4
+ nc: 80 # number of classes
5
+ depth_multiple: 1.0 # model depth multiple
6
+ width_multiple: 1.0 # layer channel multiple
7
+ anchors:
8
+ - [10,13, 16,30, 33,23] # P3/8
9
+ - [30,61, 62,45, 59,119] # P4/16
10
+ - [116,90, 156,198, 373,326] # P5/32
11
+
12
+ # YOLOv5 v6.0 backbone
13
+ backbone:
14
+ # [from, number, module, args]
15
+ [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
16
+ [-1, 1, Conv, [128, 3, 2]], # 1-P2/4
17
+ [-1, 3, C3, [128]],
18
+ [-1, 1, Conv, [256, 3, 2]], # 3-P3/8
19
+ [-1, 6, C3, [256]],
20
+ [-1, 1, Conv, [512, 3, 2]], # 5-P4/16
21
+ [-1, 9, C3, [512]],
22
+ [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32
23
+ [-1, 3, C3, [1024]],
24
+ [-1, 1, SPPF, [1024, 5]], # 9
25
+ ]
26
+
27
+ # YOLOv5 v6.0 BiFPN head
28
+ head:
29
+ [[-1, 1, Conv, [512, 1, 1]],
30
+ [-1, 1, nn.Upsample, [None, 2, 'nearest']],
31
+ [[-1, 6], 1, Concat, [1]], # cat backbone P4
32
+ [-1, 3, C3, [512, False]], # 13
33
+
34
+ [-1, 1, Conv, [256, 1, 1]],
35
+ [-1, 1, nn.Upsample, [None, 2, 'nearest']],
36
+ [[-1, 4], 1, Concat, [1]], # cat backbone P3
37
+ [-1, 3, C3, [256, False]], # 17 (P3/8-small)
38
+
39
+ [-1, 1, Conv, [256, 3, 2]],
40
+ [[-1, 14, 6], 1, Concat, [1]], # cat P4 <--- BiFPN change
41
+ [-1, 3, C3, [512, False]], # 20 (P4/16-medium)
42
+
43
+ [-1, 1, Conv, [512, 3, 2]],
44
+ [[-1, 10], 1, Concat, [1]], # cat head P5
45
+ [-1, 3, C3, [1024, False]], # 23 (P5/32-large)
46
+
47
+ [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)
48
+ ]
yolov5/models/hub/yolov5-fpn.yaml ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # YOLOv5 πŸš€ by Ultralytics, GPL-3.0 license
2
+
3
+ # Parameters
4
+ nc: 80 # number of classes
5
+ depth_multiple: 1.0 # model depth multiple
6
+ width_multiple: 1.0 # layer channel multiple
7
+ anchors:
8
+ - [10,13, 16,30, 33,23] # P3/8
9
+ - [30,61, 62,45, 59,119] # P4/16
10
+ - [116,90, 156,198, 373,326] # P5/32
11
+
12
+ # YOLOv5 v6.0 backbone
13
+ backbone:
14
+ # [from, number, module, args]
15
+ [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
16
+ [-1, 1, Conv, [128, 3, 2]], # 1-P2/4
17
+ [-1, 3, C3, [128]],
18
+ [-1, 1, Conv, [256, 3, 2]], # 3-P3/8
19
+ [-1, 6, C3, [256]],
20
+ [-1, 1, Conv, [512, 3, 2]], # 5-P4/16
21
+ [-1, 9, C3, [512]],
22
+ [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32
23
+ [-1, 3, C3, [1024]],
24
+ [-1, 1, SPPF, [1024, 5]], # 9
25
+ ]
26
+
27
+ # YOLOv5 v6.0 FPN head
28
+ head:
29
+ [[-1, 3, C3, [1024, False]], # 10 (P5/32-large)
30
+
31
+ [-1, 1, nn.Upsample, [None, 2, 'nearest']],
32
+ [[-1, 6], 1, Concat, [1]], # cat backbone P4
33
+ [-1, 1, Conv, [512, 1, 1]],
34
+ [-1, 3, C3, [512, False]], # 14 (P4/16-medium)
35
+
36
+ [-1, 1, nn.Upsample, [None, 2, 'nearest']],
37
+ [[-1, 4], 1, Concat, [1]], # cat backbone P3
38
+ [-1, 1, Conv, [256, 1, 1]],
39
+ [-1, 3, C3, [256, False]], # 18 (P3/8-small)
40
+
41
+ [[18, 14, 10], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)
42
+ ]
yolov5/models/hub/yolov5-p2.yaml ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # YOLOv5 πŸš€ by Ultralytics, GPL-3.0 license
2
+
3
+ # Parameters
4
+ nc: 80 # number of classes
5
+ depth_multiple: 1.0 # model depth multiple
6
+ width_multiple: 1.0 # layer channel multiple
7
+ anchors: 3 # AutoAnchor evolves 3 anchors per P output layer
8
+
9
+ # YOLOv5 v6.0 backbone
10
+ backbone:
11
+ # [from, number, module, args]
12
+ [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
13
+ [-1, 1, Conv, [128, 3, 2]], # 1-P2/4
14
+ [-1, 3, C3, [128]],
15
+ [-1, 1, Conv, [256, 3, 2]], # 3-P3/8
16
+ [-1, 6, C3, [256]],
17
+ [-1, 1, Conv, [512, 3, 2]], # 5-P4/16
18
+ [-1, 9, C3, [512]],
19
+ [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32
20
+ [-1, 3, C3, [1024]],
21
+ [-1, 1, SPPF, [1024, 5]], # 9
22
+ ]
23
+
24
+ # YOLOv5 v6.0 head with (P2, P3, P4, P5) outputs
25
+ head:
26
+ [[-1, 1, Conv, [512, 1, 1]],
27
+ [-1, 1, nn.Upsample, [None, 2, 'nearest']],
28
+ [[-1, 6], 1, Concat, [1]], # cat backbone P4
29
+ [-1, 3, C3, [512, False]], # 13
30
+
31
+ [-1, 1, Conv, [256, 1, 1]],
32
+ [-1, 1, nn.Upsample, [None, 2, 'nearest']],
33
+ [[-1, 4], 1, Concat, [1]], # cat backbone P3
34
+ [-1, 3, C3, [256, False]], # 17 (P3/8-small)
35
+
36
+ [-1, 1, Conv, [128, 1, 1]],
37
+ [-1, 1, nn.Upsample, [None, 2, 'nearest']],
38
+ [[-1, 2], 1, Concat, [1]], # cat backbone P2
39
+ [-1, 1, C3, [128, False]], # 21 (P2/4-xsmall)
40
+
41
+ [-1, 1, Conv, [128, 3, 2]],
42
+ [[-1, 18], 1, Concat, [1]], # cat head P3
43
+ [-1, 3, C3, [256, False]], # 24 (P3/8-small)
44
+
45
+ [-1, 1, Conv, [256, 3, 2]],
46
+ [[-1, 14], 1, Concat, [1]], # cat head P4
47
+ [-1, 3, C3, [512, False]], # 27 (P4/16-medium)
48
+
49
+ [-1, 1, Conv, [512, 3, 2]],
50
+ [[-1, 10], 1, Concat, [1]], # cat head P5
51
+ [-1, 3, C3, [1024, False]], # 30 (P5/32-large)
52
+
53
+ [[21, 24, 27, 30], 1, Detect, [nc, anchors]], # Detect(P2, P3, P4, P5)
54
+ ]
yolov5/models/hub/yolov5-p34.yaml ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # YOLOv5 πŸš€ by Ultralytics, GPL-3.0 license
2
+
3
+ # Parameters
4
+ nc: 80 # number of classes
5
+ depth_multiple: 0.33 # model depth multiple
6
+ width_multiple: 0.50 # layer channel multiple
7
+ anchors: 3 # AutoAnchor evolves 3 anchors per P output layer
8
+
9
+ # YOLOv5 v6.0 backbone
10
+ backbone:
11
+ # [from, number, module, args]
12
+ [ [ -1, 1, Conv, [ 64, 6, 2, 2 ] ], # 0-P1/2
13
+ [ -1, 1, Conv, [ 128, 3, 2 ] ], # 1-P2/4
14
+ [ -1, 3, C3, [ 128 ] ],
15
+ [ -1, 1, Conv, [ 256, 3, 2 ] ], # 3-P3/8
16
+ [ -1, 6, C3, [ 256 ] ],
17
+ [ -1, 1, Conv, [ 512, 3, 2 ] ], # 5-P4/16
18
+ [ -1, 9, C3, [ 512 ] ],
19
+ [ -1, 1, Conv, [ 1024, 3, 2 ] ], # 7-P5/32
20
+ [ -1, 3, C3, [ 1024 ] ],
21
+ [ -1, 1, SPPF, [ 1024, 5 ] ], # 9
22
+ ]
23
+
24
+ # YOLOv5 v6.0 head with (P3, P4) outputs
25
+ head:
26
+ [ [ -1, 1, Conv, [ 512, 1, 1 ] ],
27
+ [ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ],
28
+ [ [ -1, 6 ], 1, Concat, [ 1 ] ], # cat backbone P4
29
+ [ -1, 3, C3, [ 512, False ] ], # 13
30
+
31
+ [ -1, 1, Conv, [ 256, 1, 1 ] ],
32
+ [ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ],
33
+ [ [ -1, 4 ], 1, Concat, [ 1 ] ], # cat backbone P3
34
+ [ -1, 3, C3, [ 256, False ] ], # 17 (P3/8-small)
35
+
36
+ [ -1, 1, Conv, [ 256, 3, 2 ] ],
37
+ [ [ -1, 14 ], 1, Concat, [ 1 ] ], # cat head P4
38
+ [ -1, 3, C3, [ 512, False ] ], # 20 (P4/16-medium)
39
+
40
+ [ [ 17, 20 ], 1, Detect, [ nc, anchors ] ], # Detect(P3, P4)
41
+ ]
yolov5/models/hub/yolov5-p6.yaml ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # YOLOv5 πŸš€ by Ultralytics, GPL-3.0 license
2
+
3
+ # Parameters
4
+ nc: 80 # number of classes
5
+ depth_multiple: 1.0 # model depth multiple
6
+ width_multiple: 1.0 # layer channel multiple
7
+ anchors: 3 # AutoAnchor evolves 3 anchors per P output layer
8
+
9
+ # YOLOv5 v6.0 backbone
10
+ backbone:
11
+ # [from, number, module, args]
12
+ [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
13
+ [-1, 1, Conv, [128, 3, 2]], # 1-P2/4
14
+ [-1, 3, C3, [128]],
15
+ [-1, 1, Conv, [256, 3, 2]], # 3-P3/8
16
+ [-1, 6, C3, [256]],
17
+ [-1, 1, Conv, [512, 3, 2]], # 5-P4/16
18
+ [-1, 9, C3, [512]],
19
+ [-1, 1, Conv, [768, 3, 2]], # 7-P5/32
20
+ [-1, 3, C3, [768]],
21
+ [-1, 1, Conv, [1024, 3, 2]], # 9-P6/64
22
+ [-1, 3, C3, [1024]],
23
+ [-1, 1, SPPF, [1024, 5]], # 11
24
+ ]
25
+
26
+ # YOLOv5 v6.0 head with (P3, P4, P5, P6) outputs
27
+ head:
28
+ [[-1, 1, Conv, [768, 1, 1]],
29
+ [-1, 1, nn.Upsample, [None, 2, 'nearest']],
30
+ [[-1, 8], 1, Concat, [1]], # cat backbone P5
31
+ [-1, 3, C3, [768, False]], # 15
32
+
33
+ [-1, 1, Conv, [512, 1, 1]],
34
+ [-1, 1, nn.Upsample, [None, 2, 'nearest']],
35
+ [[-1, 6], 1, Concat, [1]], # cat backbone P4
36
+ [-1, 3, C3, [512, False]], # 19
37
+
38
+ [-1, 1, Conv, [256, 1, 1]],
39
+ [-1, 1, nn.Upsample, [None, 2, 'nearest']],
40
+ [[-1, 4], 1, Concat, [1]], # cat backbone P3
41
+ [-1, 3, C3, [256, False]], # 23 (P3/8-small)
42
+
43
+ [-1, 1, Conv, [256, 3, 2]],
44
+ [[-1, 20], 1, Concat, [1]], # cat head P4
45
+ [-1, 3, C3, [512, False]], # 26 (P4/16-medium)
46
+
47
+ [-1, 1, Conv, [512, 3, 2]],
48
+ [[-1, 16], 1, Concat, [1]], # cat head P5
49
+ [-1, 3, C3, [768, False]], # 29 (P5/32-large)
50
+
51
+ [-1, 1, Conv, [768, 3, 2]],
52
+ [[-1, 12], 1, Concat, [1]], # cat head P6
53
+ [-1, 3, C3, [1024, False]], # 32 (P6/64-xlarge)
54
+
55
+ [[23, 26, 29, 32], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5, P6)
56
+ ]
yolov5/models/hub/yolov5-p7.yaml ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # YOLOv5 πŸš€ by Ultralytics, GPL-3.0 license
2
+
3
+ # Parameters
4
+ nc: 80 # number of classes
5
+ depth_multiple: 1.0 # model depth multiple
6
+ width_multiple: 1.0 # layer channel multiple
7
+ anchors: 3 # AutoAnchor evolves 3 anchors per P output layer
8
+
9
+ # YOLOv5 v6.0 backbone
10
+ backbone:
11
+ # [from, number, module, args]
12
+ [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
13
+ [-1, 1, Conv, [128, 3, 2]], # 1-P2/4
14
+ [-1, 3, C3, [128]],
15
+ [-1, 1, Conv, [256, 3, 2]], # 3-P3/8
16
+ [-1, 6, C3, [256]],
17
+ [-1, 1, Conv, [512, 3, 2]], # 5-P4/16
18
+ [-1, 9, C3, [512]],
19
+ [-1, 1, Conv, [768, 3, 2]], # 7-P5/32
20
+ [-1, 3, C3, [768]],
21
+ [-1, 1, Conv, [1024, 3, 2]], # 9-P6/64
22
+ [-1, 3, C3, [1024]],
23
+ [-1, 1, Conv, [1280, 3, 2]], # 11-P7/128
24
+ [-1, 3, C3, [1280]],
25
+ [-1, 1, SPPF, [1280, 5]], # 13
26
+ ]
27
+
28
+ # YOLOv5 v6.0 head with (P3, P4, P5, P6, P7) outputs
29
+ head:
30
+ [[-1, 1, Conv, [1024, 1, 1]],
31
+ [-1, 1, nn.Upsample, [None, 2, 'nearest']],
32
+ [[-1, 10], 1, Concat, [1]], # cat backbone P6
33
+ [-1, 3, C3, [1024, False]], # 17
34
+
35
+ [-1, 1, Conv, [768, 1, 1]],
36
+ [-1, 1, nn.Upsample, [None, 2, 'nearest']],
37
+ [[-1, 8], 1, Concat, [1]], # cat backbone P5
38
+ [-1, 3, C3, [768, False]], # 21
39
+
40
+ [-1, 1, Conv, [512, 1, 1]],
41
+ [-1, 1, nn.Upsample, [None, 2, 'nearest']],
42
+ [[-1, 6], 1, Concat, [1]], # cat backbone P4
43
+ [-1, 3, C3, [512, False]], # 25
44
+
45
+ [-1, 1, Conv, [256, 1, 1]],
46
+ [-1, 1, nn.Upsample, [None, 2, 'nearest']],
47
+ [[-1, 4], 1, Concat, [1]], # cat backbone P3
48
+ [-1, 3, C3, [256, False]], # 29 (P3/8-small)
49
+
50
+ [-1, 1, Conv, [256, 3, 2]],
51
+ [[-1, 26], 1, Concat, [1]], # cat head P4
52
+ [-1, 3, C3, [512, False]], # 32 (P4/16-medium)
53
+
54
+ [-1, 1, Conv, [512, 3, 2]],
55
+ [[-1, 22], 1, Concat, [1]], # cat head P5
56
+ [-1, 3, C3, [768, False]], # 35 (P5/32-large)
57
+
58
+ [-1, 1, Conv, [768, 3, 2]],
59
+ [[-1, 18], 1, Concat, [1]], # cat head P6
60
+ [-1, 3, C3, [1024, False]], # 38 (P6/64-xlarge)
61
+
62
+ [-1, 1, Conv, [1024, 3, 2]],
63
+ [[-1, 14], 1, Concat, [1]], # cat head P7
64
+ [-1, 3, C3, [1280, False]], # 41 (P7/128-xxlarge)
65
+
66
+ [[29, 32, 35, 38, 41], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5, P6, P7)
67
+ ]
yolov5/models/hub/yolov5-panet.yaml ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # YOLOv5 πŸš€ by Ultralytics, GPL-3.0 license
2
+
3
+ # Parameters
4
+ nc: 80 # number of classes
5
+ depth_multiple: 1.0 # model depth multiple
6
+ width_multiple: 1.0 # layer channel multiple
7
+ anchors:
8
+ - [10,13, 16,30, 33,23] # P3/8
9
+ - [30,61, 62,45, 59,119] # P4/16
10
+ - [116,90, 156,198, 373,326] # P5/32
11
+
12
+ # YOLOv5 v6.0 backbone
13
+ backbone:
14
+ # [from, number, module, args]
15
+ [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
16
+ [-1, 1, Conv, [128, 3, 2]], # 1-P2/4
17
+ [-1, 3, C3, [128]],
18
+ [-1, 1, Conv, [256, 3, 2]], # 3-P3/8
19
+ [-1, 6, C3, [256]],
20
+ [-1, 1, Conv, [512, 3, 2]], # 5-P4/16
21
+ [-1, 9, C3, [512]],
22
+ [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32
23
+ [-1, 3, C3, [1024]],
24
+ [-1, 1, SPPF, [1024, 5]], # 9
25
+ ]
26
+
27
+ # YOLOv5 v6.0 PANet head
28
+ head:
29
+ [[-1, 1, Conv, [512, 1, 1]],
30
+ [-1, 1, nn.Upsample, [None, 2, 'nearest']],
31
+ [[-1, 6], 1, Concat, [1]], # cat backbone P4
32
+ [-1, 3, C3, [512, False]], # 13
33
+
34
+ [-1, 1, Conv, [256, 1, 1]],
35
+ [-1, 1, nn.Upsample, [None, 2, 'nearest']],
36
+ [[-1, 4], 1, Concat, [1]], # cat backbone P3
37
+ [-1, 3, C3, [256, False]], # 17 (P3/8-small)
38
+
39
+ [-1, 1, Conv, [256, 3, 2]],
40
+ [[-1, 14], 1, Concat, [1]], # cat head P4
41
+ [-1, 3, C3, [512, False]], # 20 (P4/16-medium)
42
+
43
+ [-1, 1, Conv, [512, 3, 2]],
44
+ [[-1, 10], 1, Concat, [1]], # cat head P5
45
+ [-1, 3, C3, [1024, False]], # 23 (P5/32-large)
46
+
47
+ [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)
48
+ ]
yolov5/models/hub/yolov5l6.yaml ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # YOLOv5 πŸš€ by Ultralytics, GPL-3.0 license
2
+
3
+ # Parameters
4
+ nc: 80 # number of classes
5
+ depth_multiple: 1.0 # model depth multiple
6
+ width_multiple: 1.0 # layer channel multiple
7
+ anchors:
8
+ - [19,27, 44,40, 38,94] # P3/8
9
+ - [96,68, 86,152, 180,137] # P4/16
10
+ - [140,301, 303,264, 238,542] # P5/32
11
+ - [436,615, 739,380, 925,792] # P6/64
12
+
13
+ # YOLOv5 v6.0 backbone
14
+ backbone:
15
+ # [from, number, module, args]
16
+ [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
17
+ [-1, 1, Conv, [128, 3, 2]], # 1-P2/4
18
+ [-1, 3, C3, [128]],
19
+ [-1, 1, Conv, [256, 3, 2]], # 3-P3/8
20
+ [-1, 6, C3, [256]],
21
+ [-1, 1, Conv, [512, 3, 2]], # 5-P4/16
22
+ [-1, 9, C3, [512]],
23
+ [-1, 1, Conv, [768, 3, 2]], # 7-P5/32
24
+ [-1, 3, C3, [768]],
25
+ [-1, 1, Conv, [1024, 3, 2]], # 9-P6/64
26
+ [-1, 3, C3, [1024]],
27
+ [-1, 1, SPPF, [1024, 5]], # 11
28
+ ]
29
+
30
+ # YOLOv5 v6.0 head
31
+ head:
32
+ [[-1, 1, Conv, [768, 1, 1]],
33
+ [-1, 1, nn.Upsample, [None, 2, 'nearest']],
34
+ [[-1, 8], 1, Concat, [1]], # cat backbone P5
35
+ [-1, 3, C3, [768, False]], # 15
36
+
37
+ [-1, 1, Conv, [512, 1, 1]],
38
+ [-1, 1, nn.Upsample, [None, 2, 'nearest']],
39
+ [[-1, 6], 1, Concat, [1]], # cat backbone P4
40
+ [-1, 3, C3, [512, False]], # 19
41
+
42
+ [-1, 1, Conv, [256, 1, 1]],
43
+ [-1, 1, nn.Upsample, [None, 2, 'nearest']],
44
+ [[-1, 4], 1, Concat, [1]], # cat backbone P3
45
+ [-1, 3, C3, [256, False]], # 23 (P3/8-small)
46
+
47
+ [-1, 1, Conv, [256, 3, 2]],
48
+ [[-1, 20], 1, Concat, [1]], # cat head P4
49
+ [-1, 3, C3, [512, False]], # 26 (P4/16-medium)
50
+
51
+ [-1, 1, Conv, [512, 3, 2]],
52
+ [[-1, 16], 1, Concat, [1]], # cat head P5
53
+ [-1, 3, C3, [768, False]], # 29 (P5/32-large)
54
+
55
+ [-1, 1, Conv, [768, 3, 2]],
56
+ [[-1, 12], 1, Concat, [1]], # cat head P6
57
+ [-1, 3, C3, [1024, False]], # 32 (P6/64-xlarge)
58
+
59
+ [[23, 26, 29, 32], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5, P6)
60
+ ]
yolov5/models/hub/yolov5m6.yaml ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # YOLOv5 πŸš€ by Ultralytics, GPL-3.0 license
2
+
3
+ # Parameters
4
+ nc: 80 # number of classes
5
+ depth_multiple: 0.67 # model depth multiple
6
+ width_multiple: 0.75 # layer channel multiple
7
+ anchors:
8
+ - [19,27, 44,40, 38,94] # P3/8
9
+ - [96,68, 86,152, 180,137] # P4/16
10
+ - [140,301, 303,264, 238,542] # P5/32
11
+ - [436,615, 739,380, 925,792] # P6/64
12
+
13
+ # YOLOv5 v6.0 backbone
14
+ backbone:
15
+ # [from, number, module, args]
16
+ [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
17
+ [-1, 1, Conv, [128, 3, 2]], # 1-P2/4
18
+ [-1, 3, C3, [128]],
19
+ [-1, 1, Conv, [256, 3, 2]], # 3-P3/8
20
+ [-1, 6, C3, [256]],
21
+ [-1, 1, Conv, [512, 3, 2]], # 5-P4/16
22
+ [-1, 9, C3, [512]],
23
+ [-1, 1, Conv, [768, 3, 2]], # 7-P5/32
24
+ [-1, 3, C3, [768]],
25
+ [-1, 1, Conv, [1024, 3, 2]], # 9-P6/64
26
+ [-1, 3, C3, [1024]],
27
+ [-1, 1, SPPF, [1024, 5]], # 11
28
+ ]
29
+
30
+ # YOLOv5 v6.0 head
31
+ head:
32
+ [[-1, 1, Conv, [768, 1, 1]],
33
+ [-1, 1, nn.Upsample, [None, 2, 'nearest']],
34
+ [[-1, 8], 1, Concat, [1]], # cat backbone P5
35
+ [-1, 3, C3, [768, False]], # 15
36
+
37
+ [-1, 1, Conv, [512, 1, 1]],
38
+ [-1, 1, nn.Upsample, [None, 2, 'nearest']],
39
+ [[-1, 6], 1, Concat, [1]], # cat backbone P4
40
+ [-1, 3, C3, [512, False]], # 19
41
+
42
+ [-1, 1, Conv, [256, 1, 1]],
43
+ [-1, 1, nn.Upsample, [None, 2, 'nearest']],
44
+ [[-1, 4], 1, Concat, [1]], # cat backbone P3
45
+ [-1, 3, C3, [256, False]], # 23 (P3/8-small)
46
+
47
+ [-1, 1, Conv, [256, 3, 2]],
48
+ [[-1, 20], 1, Concat, [1]], # cat head P4
49
+ [-1, 3, C3, [512, False]], # 26 (P4/16-medium)
50
+
51
+ [-1, 1, Conv, [512, 3, 2]],
52
+ [[-1, 16], 1, Concat, [1]], # cat head P5
53
+ [-1, 3, C3, [768, False]], # 29 (P5/32-large)
54
+
55
+ [-1, 1, Conv, [768, 3, 2]],
56
+ [[-1, 12], 1, Concat, [1]], # cat head P6
57
+ [-1, 3, C3, [1024, False]], # 32 (P6/64-xlarge)
58
+
59
+ [[23, 26, 29, 32], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5, P6)
60
+ ]
yolov5/models/hub/yolov5n6.yaml ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # YOLOv5 πŸš€ by Ultralytics, GPL-3.0 license
2
+
3
+ # Parameters
4
+ nc: 80 # number of classes
5
+ depth_multiple: 0.33 # model depth multiple
6
+ width_multiple: 0.25 # layer channel multiple
7
+ anchors:
8
+ - [19,27, 44,40, 38,94] # P3/8
9
+ - [96,68, 86,152, 180,137] # P4/16
10
+ - [140,301, 303,264, 238,542] # P5/32
11
+ - [436,615, 739,380, 925,792] # P6/64
12
+
13
+ # YOLOv5 v6.0 backbone
14
+ backbone:
15
+ # [from, number, module, args]
16
+ [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
17
+ [-1, 1, Conv, [128, 3, 2]], # 1-P2/4
18
+ [-1, 3, C3, [128]],
19
+ [-1, 1, Conv, [256, 3, 2]], # 3-P3/8
20
+ [-1, 6, C3, [256]],
21
+ [-1, 1, Conv, [512, 3, 2]], # 5-P4/16
22
+ [-1, 9, C3, [512]],
23
+ [-1, 1, Conv, [768, 3, 2]], # 7-P5/32
24
+ [-1, 3, C3, [768]],
25
+ [-1, 1, Conv, [1024, 3, 2]], # 9-P6/64
26
+ [-1, 3, C3, [1024]],
27
+ [-1, 1, SPPF, [1024, 5]], # 11
28
+ ]
29
+
30
+ # YOLOv5 v6.0 head
31
+ head:
32
+ [[-1, 1, Conv, [768, 1, 1]],
33
+ [-1, 1, nn.Upsample, [None, 2, 'nearest']],
34
+ [[-1, 8], 1, Concat, [1]], # cat backbone P5
35
+ [-1, 3, C3, [768, False]], # 15
36
+
37
+ [-1, 1, Conv, [512, 1, 1]],
38
+ [-1, 1, nn.Upsample, [None, 2, 'nearest']],
39
+ [[-1, 6], 1, Concat, [1]], # cat backbone P4
40
+ [-1, 3, C3, [512, False]], # 19
41
+
42
+ [-1, 1, Conv, [256, 1, 1]],
43
+ [-1, 1, nn.Upsample, [None, 2, 'nearest']],
44
+ [[-1, 4], 1, Concat, [1]], # cat backbone P3
45
+ [-1, 3, C3, [256, False]], # 23 (P3/8-small)
46
+
47
+ [-1, 1, Conv, [256, 3, 2]],
48
+ [[-1, 20], 1, Concat, [1]], # cat head P4
49
+ [-1, 3, C3, [512, False]], # 26 (P4/16-medium)
50
+
51
+ [-1, 1, Conv, [512, 3, 2]],
52
+ [[-1, 16], 1, Concat, [1]], # cat head P5
53
+ [-1, 3, C3, [768, False]], # 29 (P5/32-large)
54
+
55
+ [-1, 1, Conv, [768, 3, 2]],
56
+ [[-1, 12], 1, Concat, [1]], # cat head P6
57
+ [-1, 3, C3, [1024, False]], # 32 (P6/64-xlarge)
58
+
59
+ [[23, 26, 29, 32], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5, P6)
60
+ ]
yolov5/models/hub/yolov5s-ghost.yaml ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # YOLOv5 πŸš€ by Ultralytics, GPL-3.0 license
2
+
3
+ # Parameters
4
+ nc: 80 # number of classes
5
+ depth_multiple: 0.33 # model depth multiple
6
+ width_multiple: 0.50 # layer channel multiple
7
+ anchors:
8
+ - [10,13, 16,30, 33,23] # P3/8
9
+ - [30,61, 62,45, 59,119] # P4/16
10
+ - [116,90, 156,198, 373,326] # P5/32
11
+
12
+ # YOLOv5 v6.0 backbone
13
+ backbone:
14
+ # [from, number, module, args]
15
+ [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
16
+ [-1, 1, GhostConv, [128, 3, 2]], # 1-P2/4
17
+ [-1, 3, C3Ghost, [128]],
18
+ [-1, 1, GhostConv, [256, 3, 2]], # 3-P3/8
19
+ [-1, 6, C3Ghost, [256]],
20
+ [-1, 1, GhostConv, [512, 3, 2]], # 5-P4/16
21
+ [-1, 9, C3Ghost, [512]],
22
+ [-1, 1, GhostConv, [1024, 3, 2]], # 7-P5/32
23
+ [-1, 3, C3Ghost, [1024]],
24
+ [-1, 1, SPPF, [1024, 5]], # 9
25
+ ]
26
+
27
+ # YOLOv5 v6.0 head
28
+ head:
29
+ [[-1, 1, GhostConv, [512, 1, 1]],
30
+ [-1, 1, nn.Upsample, [None, 2, 'nearest']],
31
+ [[-1, 6], 1, Concat, [1]], # cat backbone P4
32
+ [-1, 3, C3Ghost, [512, False]], # 13
33
+
34
+ [-1, 1, GhostConv, [256, 1, 1]],
35
+ [-1, 1, nn.Upsample, [None, 2, 'nearest']],
36
+ [[-1, 4], 1, Concat, [1]], # cat backbone P3
37
+ [-1, 3, C3Ghost, [256, False]], # 17 (P3/8-small)
38
+
39
+ [-1, 1, GhostConv, [256, 3, 2]],
40
+ [[-1, 14], 1, Concat, [1]], # cat head P4
41
+ [-1, 3, C3Ghost, [512, False]], # 20 (P4/16-medium)
42
+
43
+ [-1, 1, GhostConv, [512, 3, 2]],
44
+ [[-1, 10], 1, Concat, [1]], # cat head P5
45
+ [-1, 3, C3Ghost, [1024, False]], # 23 (P5/32-large)
46
+
47
+ [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)
48
+ ]
yolov5/models/hub/yolov5s-transformer.yaml ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # YOLOv5 πŸš€ by Ultralytics, GPL-3.0 license
2
+
3
+ # Parameters
4
+ nc: 80 # number of classes
5
+ depth_multiple: 0.33 # model depth multiple
6
+ width_multiple: 0.50 # layer channel multiple
7
+ anchors:
8
+ - [10,13, 16,30, 33,23] # P3/8
9
+ - [30,61, 62,45, 59,119] # P4/16
10
+ - [116,90, 156,198, 373,326] # P5/32
11
+
12
+ # YOLOv5 v6.0 backbone
13
+ backbone:
14
+ # [from, number, module, args]
15
+ [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
16
+ [-1, 1, Conv, [128, 3, 2]], # 1-P2/4
17
+ [-1, 3, C3, [128]],
18
+ [-1, 1, Conv, [256, 3, 2]], # 3-P3/8
19
+ [-1, 6, C3, [256]],
20
+ [-1, 1, Conv, [512, 3, 2]], # 5-P4/16
21
+ [-1, 9, C3, [512]],
22
+ [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32
23
+ [-1, 3, C3TR, [1024]], # 9 <--- C3TR() Transformer module
24
+ [-1, 1, SPPF, [1024, 5]], # 9
25
+ ]
26
+
27
+ # YOLOv5 v6.0 head
28
+ head:
29
+ [[-1, 1, Conv, [512, 1, 1]],
30
+ [-1, 1, nn.Upsample, [None, 2, 'nearest']],
31
+ [[-1, 6], 1, Concat, [1]], # cat backbone P4
32
+ [-1, 3, C3, [512, False]], # 13
33
+
34
+ [-1, 1, Conv, [256, 1, 1]],
35
+ [-1, 1, nn.Upsample, [None, 2, 'nearest']],
36
+ [[-1, 4], 1, Concat, [1]], # cat backbone P3
37
+ [-1, 3, C3, [256, False]], # 17 (P3/8-small)
38
+
39
+ [-1, 1, Conv, [256, 3, 2]],
40
+ [[-1, 14], 1, Concat, [1]], # cat head P4
41
+ [-1, 3, C3, [512, False]], # 20 (P4/16-medium)
42
+
43
+ [-1, 1, Conv, [512, 3, 2]],
44
+ [[-1, 10], 1, Concat, [1]], # cat head P5
45
+ [-1, 3, C3, [1024, False]], # 23 (P5/32-large)
46
+
47
+ [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)
48
+ ]
yolov5/models/hub/yolov5s6.yaml ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # YOLOv5 πŸš€ by Ultralytics, GPL-3.0 license
2
+
3
+ # Parameters
4
+ nc: 80 # number of classes
5
+ depth_multiple: 0.33 # model depth multiple
6
+ width_multiple: 0.50 # layer channel multiple
7
+ anchors:
8
+ - [19,27, 44,40, 38,94] # P3/8
9
+ - [96,68, 86,152, 180,137] # P4/16
10
+ - [140,301, 303,264, 238,542] # P5/32
11
+ - [436,615, 739,380, 925,792] # P6/64
12
+
13
+ # YOLOv5 v6.0 backbone
14
+ backbone:
15
+ # [from, number, module, args]
16
+ [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
17
+ [-1, 1, Conv, [128, 3, 2]], # 1-P2/4
18
+ [-1, 3, C3, [128]],
19
+ [-1, 1, Conv, [256, 3, 2]], # 3-P3/8
20
+ [-1, 6, C3, [256]],
21
+ [-1, 1, Conv, [512, 3, 2]], # 5-P4/16
22
+ [-1, 9, C3, [512]],
23
+ [-1, 1, Conv, [768, 3, 2]], # 7-P5/32
24
+ [-1, 3, C3, [768]],
25
+ [-1, 1, Conv, [1024, 3, 2]], # 9-P6/64
26
+ [-1, 3, C3, [1024]],
27
+ [-1, 1, SPPF, [1024, 5]], # 11
28
+ ]
29
+
30
+ # YOLOv5 v6.0 head
31
+ head:
32
+ [[-1, 1, Conv, [768, 1, 1]],
33
+ [-1, 1, nn.Upsample, [None, 2, 'nearest']],
34
+ [[-1, 8], 1, Concat, [1]], # cat backbone P5
35
+ [-1, 3, C3, [768, False]], # 15
36
+
37
+ [-1, 1, Conv, [512, 1, 1]],
38
+ [-1, 1, nn.Upsample, [None, 2, 'nearest']],
39
+ [[-1, 6], 1, Concat, [1]], # cat backbone P4
40
+ [-1, 3, C3, [512, False]], # 19
41
+
42
+ [-1, 1, Conv, [256, 1, 1]],
43
+ [-1, 1, nn.Upsample, [None, 2, 'nearest']],
44
+ [[-1, 4], 1, Concat, [1]], # cat backbone P3
45
+ [-1, 3, C3, [256, False]], # 23 (P3/8-small)
46
+
47
+ [-1, 1, Conv, [256, 3, 2]],
48
+ [[-1, 20], 1, Concat, [1]], # cat head P4
49
+ [-1, 3, C3, [512, False]], # 26 (P4/16-medium)
50
+
51
+ [-1, 1, Conv, [512, 3, 2]],
52
+ [[-1, 16], 1, Concat, [1]], # cat head P5
53
+ [-1, 3, C3, [768, False]], # 29 (P5/32-large)
54
+
55
+ [-1, 1, Conv, [768, 3, 2]],
56
+ [[-1, 12], 1, Concat, [1]], # cat head P6
57
+ [-1, 3, C3, [1024, False]], # 32 (P6/64-xlarge)
58
+
59
+ [[23, 26, 29, 32], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5, P6)
60
+ ]
yolov5/models/hub/yolov5x6.yaml ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # YOLOv5 πŸš€ by Ultralytics, GPL-3.0 license
2
+
3
+ # Parameters
4
+ nc: 80 # number of classes
5
+ depth_multiple: 1.33 # model depth multiple
6
+ width_multiple: 1.25 # layer channel multiple
7
+ anchors:
8
+ - [19,27, 44,40, 38,94] # P3/8
9
+ - [96,68, 86,152, 180,137] # P4/16
10
+ - [140,301, 303,264, 238,542] # P5/32
11
+ - [436,615, 739,380, 925,792] # P6/64
12
+
13
+ # YOLOv5 v6.0 backbone
14
+ backbone:
15
+ # [from, number, module, args]
16
+ [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
17
+ [-1, 1, Conv, [128, 3, 2]], # 1-P2/4
18
+ [-1, 3, C3, [128]],
19
+ [-1, 1, Conv, [256, 3, 2]], # 3-P3/8
20
+ [-1, 6, C3, [256]],
21
+ [-1, 1, Conv, [512, 3, 2]], # 5-P4/16
22
+ [-1, 9, C3, [512]],
23
+ [-1, 1, Conv, [768, 3, 2]], # 7-P5/32
24
+ [-1, 3, C3, [768]],
25
+ [-1, 1, Conv, [1024, 3, 2]], # 9-P6/64
26
+ [-1, 3, C3, [1024]],
27
+ [-1, 1, SPPF, [1024, 5]], # 11
28
+ ]
29
+
30
+ # YOLOv5 v6.0 head
31
+ head:
32
+ [[-1, 1, Conv, [768, 1, 1]],
33
+ [-1, 1, nn.Upsample, [None, 2, 'nearest']],
34
+ [[-1, 8], 1, Concat, [1]], # cat backbone P5
35
+ [-1, 3, C3, [768, False]], # 15
36
+
37
+ [-1, 1, Conv, [512, 1, 1]],
38
+ [-1, 1, nn.Upsample, [None, 2, 'nearest']],
39
+ [[-1, 6], 1, Concat, [1]], # cat backbone P4
40
+ [-1, 3, C3, [512, False]], # 19
41
+
42
+ [-1, 1, Conv, [256, 1, 1]],
43
+ [-1, 1, nn.Upsample, [None, 2, 'nearest']],
44
+ [[-1, 4], 1, Concat, [1]], # cat backbone P3
45
+ [-1, 3, C3, [256, False]], # 23 (P3/8-small)
46
+
47
+ [-1, 1, Conv, [256, 3, 2]],
48
+ [[-1, 20], 1, Concat, [1]], # cat head P4
49
+ [-1, 3, C3, [512, False]], # 26 (P4/16-medium)
50
+
51
+ [-1, 1, Conv, [512, 3, 2]],
52
+ [[-1, 16], 1, Concat, [1]], # cat head P5
53
+ [-1, 3, C3, [768, False]], # 29 (P5/32-large)
54
+
55
+ [-1, 1, Conv, [768, 3, 2]],
56
+ [[-1, 12], 1, Concat, [1]], # cat head P6
57
+ [-1, 3, C3, [1024, False]], # 32 (P6/64-xlarge)
58
+
59
+ [[23, 26, 29, 32], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5, P6)
60
+ ]
yolov5/models/tf.py ADDED
@@ -0,0 +1,464 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # YOLOv5 πŸš€ by Ultralytics, GPL-3.0 license
2
+ """
3
+ TensorFlow, Keras and TFLite versions of YOLOv5
4
+ Authored by https://github.com/zldrobit in PR https://github.com/ultralytics/yolov5/pull/1127
5
+
6
+ Usage:
7
+ $ python models/tf.py --weights yolov5s.pt
8
+
9
+ Export:
10
+ $ python path/to/export.py --weights yolov5s.pt --include saved_model pb tflite tfjs
11
+ """
12
+
13
+ import argparse
14
+ import sys
15
+ from copy import deepcopy
16
+ from pathlib import Path
17
+
18
+ FILE = Path(__file__).resolve()
19
+ ROOT = FILE.parents[1] # YOLOv5 root directory
20
+ if str(ROOT) not in sys.path:
21
+ sys.path.append(str(ROOT)) # add ROOT to PATH
22
+ # ROOT = ROOT.relative_to(Path.cwd()) # relative
23
+
24
+ import numpy as np
25
+ import tensorflow as tf
26
+ import torch
27
+ import torch.nn as nn
28
+ from tensorflow import keras
29
+
30
+ from models.common import C3, SPP, SPPF, Bottleneck, BottleneckCSP, Concat, Conv, DWConv, Focus, autopad
31
+ from models.experimental import CrossConv, MixConv2d, attempt_load
32
+ from models.yolo import Detect
33
+ from utils.activations import SiLU
34
+ from utils.general import LOGGER, make_divisible, print_args
35
+
36
+
37
+ class TFBN(keras.layers.Layer):
38
+ # TensorFlow BatchNormalization wrapper
39
+ def __init__(self, w=None):
40
+ super().__init__()
41
+ self.bn = keras.layers.BatchNormalization(
42
+ beta_initializer=keras.initializers.Constant(w.bias.numpy()),
43
+ gamma_initializer=keras.initializers.Constant(w.weight.numpy()),
44
+ moving_mean_initializer=keras.initializers.Constant(w.running_mean.numpy()),
45
+ moving_variance_initializer=keras.initializers.Constant(w.running_var.numpy()),
46
+ epsilon=w.eps)
47
+
48
+ def call(self, inputs):
49
+ return self.bn(inputs)
50
+
51
+
52
+ class TFPad(keras.layers.Layer):
53
+ def __init__(self, pad):
54
+ super().__init__()
55
+ self.pad = tf.constant([[0, 0], [pad, pad], [pad, pad], [0, 0]])
56
+
57
+ def call(self, inputs):
58
+ return tf.pad(inputs, self.pad, mode='constant', constant_values=0)
59
+
60
+
61
+ class TFConv(keras.layers.Layer):
62
+ # Standard convolution
63
+ def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True, w=None):
64
+ # ch_in, ch_out, weights, kernel, stride, padding, groups
65
+ super().__init__()
66
+ assert g == 1, "TF v2.2 Conv2D does not support 'groups' argument"
67
+ assert isinstance(k, int), "Convolution with multiple kernels are not allowed."
68
+ # TensorFlow convolution padding is inconsistent with PyTorch (e.g. k=3 s=2 'SAME' padding)
69
+ # see https://stackoverflow.com/questions/52975843/comparing-conv2d-with-padding-between-tensorflow-and-pytorch
70
+
71
+ conv = keras.layers.Conv2D(
72
+ c2, k, s, 'SAME' if s == 1 else 'VALID', use_bias=False if hasattr(w, 'bn') else True,
73
+ kernel_initializer=keras.initializers.Constant(w.conv.weight.permute(2, 3, 1, 0).numpy()),
74
+ bias_initializer='zeros' if hasattr(w, 'bn') else keras.initializers.Constant(w.conv.bias.numpy()))
75
+ self.conv = conv if s == 1 else keras.Sequential([TFPad(autopad(k, p)), conv])
76
+ self.bn = TFBN(w.bn) if hasattr(w, 'bn') else tf.identity
77
+
78
+ # YOLOv5 activations
79
+ if isinstance(w.act, nn.LeakyReLU):
80
+ self.act = (lambda x: keras.activations.relu(x, alpha=0.1)) if act else tf.identity
81
+ elif isinstance(w.act, nn.Hardswish):
82
+ self.act = (lambda x: x * tf.nn.relu6(x + 3) * 0.166666667) if act else tf.identity
83
+ elif isinstance(w.act, (nn.SiLU, SiLU)):
84
+ self.act = (lambda x: keras.activations.swish(x)) if act else tf.identity
85
+ else:
86
+ raise Exception(f'no matching TensorFlow activation found for {w.act}')
87
+
88
+ def call(self, inputs):
89
+ return self.act(self.bn(self.conv(inputs)))
90
+
91
+
92
+ class TFFocus(keras.layers.Layer):
93
+ # Focus wh information into c-space
94
+ def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True, w=None):
95
+ # ch_in, ch_out, kernel, stride, padding, groups
96
+ super().__init__()
97
+ self.conv = TFConv(c1 * 4, c2, k, s, p, g, act, w.conv)
98
+
99
+ def call(self, inputs): # x(b,w,h,c) -> y(b,w/2,h/2,4c)
100
+ # inputs = inputs / 255 # normalize 0-255 to 0-1
101
+ return self.conv(tf.concat([inputs[:, ::2, ::2, :],
102
+ inputs[:, 1::2, ::2, :],
103
+ inputs[:, ::2, 1::2, :],
104
+ inputs[:, 1::2, 1::2, :]], 3))
105
+
106
+
107
+ class TFBottleneck(keras.layers.Layer):
108
+ # Standard bottleneck
109
+ def __init__(self, c1, c2, shortcut=True, g=1, e=0.5, w=None): # ch_in, ch_out, shortcut, groups, expansion
110
+ super().__init__()
111
+ c_ = int(c2 * e) # hidden channels
112
+ self.cv1 = TFConv(c1, c_, 1, 1, w=w.cv1)
113
+ self.cv2 = TFConv(c_, c2, 3, 1, g=g, w=w.cv2)
114
+ self.add = shortcut and c1 == c2
115
+
116
+ def call(self, inputs):
117
+ return inputs + self.cv2(self.cv1(inputs)) if self.add else self.cv2(self.cv1(inputs))
118
+
119
+
120
+ class TFConv2d(keras.layers.Layer):
121
+ # Substitution for PyTorch nn.Conv2D
122
+ def __init__(self, c1, c2, k, s=1, g=1, bias=True, w=None):
123
+ super().__init__()
124
+ assert g == 1, "TF v2.2 Conv2D does not support 'groups' argument"
125
+ self.conv = keras.layers.Conv2D(
126
+ c2, k, s, 'VALID', use_bias=bias,
127
+ kernel_initializer=keras.initializers.Constant(w.weight.permute(2, 3, 1, 0).numpy()),
128
+ bias_initializer=keras.initializers.Constant(w.bias.numpy()) if bias else None, )
129
+
130
+ def call(self, inputs):
131
+ return self.conv(inputs)
132
+
133
+
134
+ class TFBottleneckCSP(keras.layers.Layer):
135
+ # CSP Bottleneck https://github.com/WongKinYiu/CrossStagePartialNetworks
136
+ def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5, w=None):
137
+ # ch_in, ch_out, number, shortcut, groups, expansion
138
+ super().__init__()
139
+ c_ = int(c2 * e) # hidden channels
140
+ self.cv1 = TFConv(c1, c_, 1, 1, w=w.cv1)
141
+ self.cv2 = TFConv2d(c1, c_, 1, 1, bias=False, w=w.cv2)
142
+ self.cv3 = TFConv2d(c_, c_, 1, 1, bias=False, w=w.cv3)
143
+ self.cv4 = TFConv(2 * c_, c2, 1, 1, w=w.cv4)
144
+ self.bn = TFBN(w.bn)
145
+ self.act = lambda x: keras.activations.relu(x, alpha=0.1)
146
+ self.m = keras.Sequential([TFBottleneck(c_, c_, shortcut, g, e=1.0, w=w.m[j]) for j in range(n)])
147
+
148
+ def call(self, inputs):
149
+ y1 = self.cv3(self.m(self.cv1(inputs)))
150
+ y2 = self.cv2(inputs)
151
+ return self.cv4(self.act(self.bn(tf.concat((y1, y2), axis=3))))
152
+
153
+
154
+ class TFC3(keras.layers.Layer):
155
+ # CSP Bottleneck with 3 convolutions
156
+ def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5, w=None):
157
+ # ch_in, ch_out, number, shortcut, groups, expansion
158
+ super().__init__()
159
+ c_ = int(c2 * e) # hidden channels
160
+ self.cv1 = TFConv(c1, c_, 1, 1, w=w.cv1)
161
+ self.cv2 = TFConv(c1, c_, 1, 1, w=w.cv2)
162
+ self.cv3 = TFConv(2 * c_, c2, 1, 1, w=w.cv3)
163
+ self.m = keras.Sequential([TFBottleneck(c_, c_, shortcut, g, e=1.0, w=w.m[j]) for j in range(n)])
164
+
165
+ def call(self, inputs):
166
+ return self.cv3(tf.concat((self.m(self.cv1(inputs)), self.cv2(inputs)), axis=3))
167
+
168
+
169
+ class TFSPP(keras.layers.Layer):
170
+ # Spatial pyramid pooling layer used in YOLOv3-SPP
171
+ def __init__(self, c1, c2, k=(5, 9, 13), w=None):
172
+ super().__init__()
173
+ c_ = c1 // 2 # hidden channels
174
+ self.cv1 = TFConv(c1, c_, 1, 1, w=w.cv1)
175
+ self.cv2 = TFConv(c_ * (len(k) + 1), c2, 1, 1, w=w.cv2)
176
+ self.m = [keras.layers.MaxPool2D(pool_size=x, strides=1, padding='SAME') for x in k]
177
+
178
+ def call(self, inputs):
179
+ x = self.cv1(inputs)
180
+ return self.cv2(tf.concat([x] + [m(x) for m in self.m], 3))
181
+
182
+
183
+ class TFSPPF(keras.layers.Layer):
184
+ # Spatial pyramid pooling-Fast layer
185
+ def __init__(self, c1, c2, k=5, w=None):
186
+ super().__init__()
187
+ c_ = c1 // 2 # hidden channels
188
+ self.cv1 = TFConv(c1, c_, 1, 1, w=w.cv1)
189
+ self.cv2 = TFConv(c_ * 4, c2, 1, 1, w=w.cv2)
190
+ self.m = keras.layers.MaxPool2D(pool_size=k, strides=1, padding='SAME')
191
+
192
+ def call(self, inputs):
193
+ x = self.cv1(inputs)
194
+ y1 = self.m(x)
195
+ y2 = self.m(y1)
196
+ return self.cv2(tf.concat([x, y1, y2, self.m(y2)], 3))
197
+
198
+
199
+ class TFDetect(keras.layers.Layer):
200
+ def __init__(self, nc=80, anchors=(), ch=(), imgsz=(640, 640), w=None): # detection layer
201
+ super().__init__()
202
+ self.stride = tf.convert_to_tensor(w.stride.numpy(), dtype=tf.float32)
203
+ self.nc = nc # number of classes
204
+ self.no = nc + 5 # number of outputs per anchor
205
+ self.nl = len(anchors) # number of detection layers
206
+ self.na = len(anchors[0]) // 2 # number of anchors
207
+ self.grid = [tf.zeros(1)] * self.nl # init grid
208
+ self.anchors = tf.convert_to_tensor(w.anchors.numpy(), dtype=tf.float32)
209
+ self.anchor_grid = tf.reshape(self.anchors * tf.reshape(self.stride, [self.nl, 1, 1]),
210
+ [self.nl, 1, -1, 1, 2])
211
+ self.m = [TFConv2d(x, self.no * self.na, 1, w=w.m[i]) for i, x in enumerate(ch)]
212
+ self.training = False # set to False after building model
213
+ self.imgsz = imgsz
214
+ for i in range(self.nl):
215
+ ny, nx = self.imgsz[0] // self.stride[i], self.imgsz[1] // self.stride[i]
216
+ self.grid[i] = self._make_grid(nx, ny)
217
+
218
+ def call(self, inputs):
219
+ z = [] # inference output
220
+ x = []
221
+ for i in range(self.nl):
222
+ x.append(self.m[i](inputs[i]))
223
+ # x(bs,20,20,255) to x(bs,3,20,20,85)
224
+ ny, nx = self.imgsz[0] // self.stride[i], self.imgsz[1] // self.stride[i]
225
+ x[i] = tf.transpose(tf.reshape(x[i], [-1, ny * nx, self.na, self.no]), [0, 2, 1, 3])
226
+
227
+ if not self.training: # inference
228
+ y = tf.sigmoid(x[i])
229
+ xy = (y[..., 0:2] * 2 - 0.5 + self.grid[i]) * self.stride[i] # xy
230
+ wh = (y[..., 2:4] * 2) ** 2 * self.anchor_grid[i]
231
+ # Normalize xywh to 0-1 to reduce calibration error
232
+ xy /= tf.constant([[self.imgsz[1], self.imgsz[0]]], dtype=tf.float32)
233
+ wh /= tf.constant([[self.imgsz[1], self.imgsz[0]]], dtype=tf.float32)
234
+ y = tf.concat([xy, wh, y[..., 4:]], -1)
235
+ z.append(tf.reshape(y, [-1, self.na * ny * nx, self.no]))
236
+
237
+ return x if self.training else (tf.concat(z, 1), x)
238
+
239
+ @staticmethod
240
+ def _make_grid(nx=20, ny=20):
241
+ # yv, xv = torch.meshgrid([torch.arange(ny), torch.arange(nx)])
242
+ # return torch.stack((xv, yv), 2).view((1, 1, ny, nx, 2)).float()
243
+ xv, yv = tf.meshgrid(tf.range(nx), tf.range(ny))
244
+ return tf.cast(tf.reshape(tf.stack([xv, yv], 2), [1, 1, ny * nx, 2]), dtype=tf.float32)
245
+
246
+
247
+ class TFUpsample(keras.layers.Layer):
248
+ def __init__(self, size, scale_factor, mode, w=None): # warning: all arguments needed including 'w'
249
+ super().__init__()
250
+ assert scale_factor == 2, "scale_factor must be 2"
251
+ self.upsample = lambda x: tf.image.resize(x, (x.shape[1] * 2, x.shape[2] * 2), method=mode)
252
+ # self.upsample = keras.layers.UpSampling2D(size=scale_factor, interpolation=mode)
253
+ # with default arguments: align_corners=False, half_pixel_centers=False
254
+ # self.upsample = lambda x: tf.raw_ops.ResizeNearestNeighbor(images=x,
255
+ # size=(x.shape[1] * 2, x.shape[2] * 2))
256
+
257
+ def call(self, inputs):
258
+ return self.upsample(inputs)
259
+
260
+
261
+ class TFConcat(keras.layers.Layer):
262
+ def __init__(self, dimension=1, w=None):
263
+ super().__init__()
264
+ assert dimension == 1, "convert only NCHW to NHWC concat"
265
+ self.d = 3
266
+
267
+ def call(self, inputs):
268
+ return tf.concat(inputs, self.d)
269
+
270
+
271
+ def parse_model(d, ch, model, imgsz): # model_dict, input_channels(3)
272
+ LOGGER.info(f"\n{'':>3}{'from':>18}{'n':>3}{'params':>10} {'module':<40}{'arguments':<30}")
273
+ anchors, nc, gd, gw = d['anchors'], d['nc'], d['depth_multiple'], d['width_multiple']
274
+ na = (len(anchors[0]) // 2) if isinstance(anchors, list) else anchors # number of anchors
275
+ no = na * (nc + 5) # number of outputs = anchors * (classes + 5)
276
+
277
+ layers, save, c2 = [], [], ch[-1] # layers, savelist, ch out
278
+ for i, (f, n, m, args) in enumerate(d['backbone'] + d['head']): # from, number, module, args
279
+ m_str = m
280
+ m = eval(m) if isinstance(m, str) else m # eval strings
281
+ for j, a in enumerate(args):
282
+ try:
283
+ args[j] = eval(a) if isinstance(a, str) else a # eval strings
284
+ except NameError:
285
+ pass
286
+
287
+ n = max(round(n * gd), 1) if n > 1 else n # depth gain
288
+ if m in [nn.Conv2d, Conv, Bottleneck, SPP, SPPF, DWConv, MixConv2d, Focus, CrossConv, BottleneckCSP, C3]:
289
+ c1, c2 = ch[f], args[0]
290
+ c2 = make_divisible(c2 * gw, 8) if c2 != no else c2
291
+
292
+ args = [c1, c2, *args[1:]]
293
+ if m in [BottleneckCSP, C3]:
294
+ args.insert(2, n)
295
+ n = 1
296
+ elif m is nn.BatchNorm2d:
297
+ args = [ch[f]]
298
+ elif m is Concat:
299
+ c2 = sum(ch[-1 if x == -1 else x + 1] for x in f)
300
+ elif m is Detect:
301
+ args.append([ch[x + 1] for x in f])
302
+ if isinstance(args[1], int): # number of anchors
303
+ args[1] = [list(range(args[1] * 2))] * len(f)
304
+ args.append(imgsz)
305
+ else:
306
+ c2 = ch[f]
307
+
308
+ tf_m = eval('TF' + m_str.replace('nn.', ''))
309
+ m_ = keras.Sequential([tf_m(*args, w=model.model[i][j]) for j in range(n)]) if n > 1 \
310
+ else tf_m(*args, w=model.model[i]) # module
311
+
312
+ torch_m_ = nn.Sequential(*(m(*args) for _ in range(n))) if n > 1 else m(*args) # module
313
+ t = str(m)[8:-2].replace('__main__.', '') # module type
314
+ np = sum(x.numel() for x in torch_m_.parameters()) # number params
315
+ m_.i, m_.f, m_.type, m_.np = i, f, t, np # attach index, 'from' index, type, number params
316
+ LOGGER.info(f'{i:>3}{str(f):>18}{str(n):>3}{np:>10} {t:<40}{str(args):<30}') # print
317
+ save.extend(x % i for x in ([f] if isinstance(f, int) else f) if x != -1) # append to savelist
318
+ layers.append(m_)
319
+ ch.append(c2)
320
+ return keras.Sequential(layers), sorted(save)
321
+
322
+
323
+ class TFModel:
324
+ def __init__(self, cfg='yolov5s.yaml', ch=3, nc=None, model=None, imgsz=(640, 640)): # model, channels, classes
325
+ super().__init__()
326
+ if isinstance(cfg, dict):
327
+ self.yaml = cfg # model dict
328
+ else: # is *.yaml
329
+ import yaml # for torch hub
330
+ self.yaml_file = Path(cfg).name
331
+ with open(cfg) as f:
332
+ self.yaml = yaml.load(f, Loader=yaml.FullLoader) # model dict
333
+
334
+ # Define model
335
+ if nc and nc != self.yaml['nc']:
336
+ LOGGER.info(f"Overriding {cfg} nc={self.yaml['nc']} with nc={nc}")
337
+ self.yaml['nc'] = nc # override yaml value
338
+ self.model, self.savelist = parse_model(deepcopy(self.yaml), ch=[ch], model=model, imgsz=imgsz)
339
+
340
+ def predict(self, inputs, tf_nms=False, agnostic_nms=False, topk_per_class=100, topk_all=100, iou_thres=0.45,
341
+ conf_thres=0.25):
342
+ y = [] # outputs
343
+ x = inputs
344
+ for i, m in enumerate(self.model.layers):
345
+ if m.f != -1: # if not from previous layer
346
+ x = y[m.f] if isinstance(m.f, int) else [x if j == -1 else y[j] for j in m.f] # from earlier layers
347
+
348
+ x = m(x) # run
349
+ y.append(x if m.i in self.savelist else None) # save output
350
+
351
+ # Add TensorFlow NMS
352
+ if tf_nms:
353
+ boxes = self._xywh2xyxy(x[0][..., :4])
354
+ probs = x[0][:, :, 4:5]
355
+ classes = x[0][:, :, 5:]
356
+ scores = probs * classes
357
+ if agnostic_nms:
358
+ nms = AgnosticNMS()((boxes, classes, scores), topk_all, iou_thres, conf_thres)
359
+ return nms, x[1]
360
+ else:
361
+ boxes = tf.expand_dims(boxes, 2)
362
+ nms = tf.image.combined_non_max_suppression(
363
+ boxes, scores, topk_per_class, topk_all, iou_thres, conf_thres, clip_boxes=False)
364
+ return nms, x[1]
365
+
366
+ return x[0] # output only first tensor [1,6300,85] = [xywh, conf, class0, class1, ...]
367
+ # x = x[0][0] # [x(1,6300,85), ...] to x(6300,85)
368
+ # xywh = x[..., :4] # x(6300,4) boxes
369
+ # conf = x[..., 4:5] # x(6300,1) confidences
370
+ # cls = tf.reshape(tf.cast(tf.argmax(x[..., 5:], axis=1), tf.float32), (-1, 1)) # x(6300,1) classes
371
+ # return tf.concat([conf, cls, xywh], 1)
372
+
373
+ @staticmethod
374
+ def _xywh2xyxy(xywh):
375
+ # Convert nx4 boxes from [x, y, w, h] to [x1, y1, x2, y2] where xy1=top-left, xy2=bottom-right
376
+ x, y, w, h = tf.split(xywh, num_or_size_splits=4, axis=-1)
377
+ return tf.concat([x - w / 2, y - h / 2, x + w / 2, y + h / 2], axis=-1)
378
+
379
+
380
+ class AgnosticNMS(keras.layers.Layer):
381
+ # TF Agnostic NMS
382
+ def call(self, input, topk_all, iou_thres, conf_thres):
383
+ # wrap map_fn to avoid TypeSpec related error https://stackoverflow.com/a/65809989/3036450
384
+ return tf.map_fn(lambda x: self._nms(x, topk_all, iou_thres, conf_thres), input,
385
+ fn_output_signature=(tf.float32, tf.float32, tf.float32, tf.int32),
386
+ name='agnostic_nms')
387
+
388
+ @staticmethod
389
+ def _nms(x, topk_all=100, iou_thres=0.45, conf_thres=0.25): # agnostic NMS
390
+ boxes, classes, scores = x
391
+ class_inds = tf.cast(tf.argmax(classes, axis=-1), tf.float32)
392
+ scores_inp = tf.reduce_max(scores, -1)
393
+ selected_inds = tf.image.non_max_suppression(
394
+ boxes, scores_inp, max_output_size=topk_all, iou_threshold=iou_thres, score_threshold=conf_thres)
395
+ selected_boxes = tf.gather(boxes, selected_inds)
396
+ padded_boxes = tf.pad(selected_boxes,
397
+ paddings=[[0, topk_all - tf.shape(selected_boxes)[0]], [0, 0]],
398
+ mode="CONSTANT", constant_values=0.0)
399
+ selected_scores = tf.gather(scores_inp, selected_inds)
400
+ padded_scores = tf.pad(selected_scores,
401
+ paddings=[[0, topk_all - tf.shape(selected_boxes)[0]]],
402
+ mode="CONSTANT", constant_values=-1.0)
403
+ selected_classes = tf.gather(class_inds, selected_inds)
404
+ padded_classes = tf.pad(selected_classes,
405
+ paddings=[[0, topk_all - tf.shape(selected_boxes)[0]]],
406
+ mode="CONSTANT", constant_values=-1.0)
407
+ valid_detections = tf.shape(selected_inds)[0]
408
+ return padded_boxes, padded_scores, padded_classes, valid_detections
409
+
410
+
411
+ def representative_dataset_gen(dataset, ncalib=100):
412
+ # Representative dataset generator for use with converter.representative_dataset, returns a generator of np arrays
413
+ for n, (path, img, im0s, vid_cap, string) in enumerate(dataset):
414
+ input = np.transpose(img, [1, 2, 0])
415
+ input = np.expand_dims(input, axis=0).astype(np.float32)
416
+ input /= 255
417
+ yield [input]
418
+ if n >= ncalib:
419
+ break
420
+
421
+
422
+ def run(weights=ROOT / 'yolov5s.pt', # weights path
423
+ imgsz=(640, 640), # inference size h,w
424
+ batch_size=1, # batch size
425
+ dynamic=False, # dynamic batch size
426
+ ):
427
+ # PyTorch model
428
+ im = torch.zeros((batch_size, 3, *imgsz)) # BCHW image
429
+ model = attempt_load(weights, map_location=torch.device('cpu'), inplace=True, fuse=False)
430
+ _ = model(im) # inference
431
+ model.info()
432
+
433
+ # TensorFlow model
434
+ im = tf.zeros((batch_size, *imgsz, 3)) # BHWC image
435
+ tf_model = TFModel(cfg=model.yaml, model=model, nc=model.nc, imgsz=imgsz)
436
+ _ = tf_model.predict(im) # inference
437
+
438
+ # Keras model
439
+ im = keras.Input(shape=(*imgsz, 3), batch_size=None if dynamic else batch_size)
440
+ keras_model = keras.Model(inputs=im, outputs=tf_model.predict(im))
441
+ keras_model.summary()
442
+
443
+ LOGGER.info('PyTorch, TensorFlow and Keras models successfully verified.\nUse export.py for TF model export.')
444
+
445
+
446
+ def parse_opt():
447
+ parser = argparse.ArgumentParser()
448
+ parser.add_argument('--weights', type=str, default=ROOT / 'yolov5s.pt', help='weights path')
449
+ parser.add_argument('--imgsz', '--img', '--img-size', nargs='+', type=int, default=[640], help='inference size h,w')
450
+ parser.add_argument('--batch-size', type=int, default=1, help='batch size')
451
+ parser.add_argument('--dynamic', action='store_true', help='dynamic batch size')
452
+ opt = parser.parse_args()
453
+ opt.imgsz *= 2 if len(opt.imgsz) == 1 else 1 # expand
454
+ print_args(FILE.stem, opt)
455
+ return opt
456
+
457
+
458
+ def main(opt):
459
+ run(**vars(opt))
460
+
461
+
462
+ if __name__ == "__main__":
463
+ opt = parse_opt()
464
+ main(opt)
yolov5/models/yolo.py ADDED
@@ -0,0 +1,329 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # YOLOv5 πŸš€ by Ultralytics, GPL-3.0 license
2
+ """
3
+ YOLO-specific modules
4
+
5
+ Usage:
6
+ $ python path/to/models/yolo.py --cfg yolov5s.yaml
7
+ """
8
+
9
+ import argparse
10
+ import sys
11
+ from copy import deepcopy
12
+ from pathlib import Path
13
+
14
+ FILE = Path(__file__).resolve()
15
+ ROOT = FILE.parents[1] # YOLOv5 root directory
16
+ if str(ROOT) not in sys.path:
17
+ sys.path.append(str(ROOT)) # add ROOT to PATH
18
+ # ROOT = ROOT.relative_to(Path.cwd()) # relative
19
+
20
+ from models.common import *
21
+ from models.experimental import *
22
+ from utils.autoanchor import check_anchor_order
23
+ from utils.general import LOGGER, check_version, check_yaml, make_divisible, print_args
24
+ from utils.plots import feature_visualization
25
+ from utils.torch_utils import fuse_conv_and_bn, initialize_weights, model_info, scale_img, select_device, time_sync
26
+
27
+ try:
28
+ import thop # for FLOPs computation
29
+ except ImportError:
30
+ thop = None
31
+
32
+
33
+ class Detect(nn.Module):
34
+ stride = None # strides computed during build
35
+ onnx_dynamic = False # ONNX export parameter
36
+
37
+ def __init__(self, nc=80, anchors=(), ch=(), inplace=True): # detection layer
38
+ super().__init__()
39
+ self.nc = nc # number of classes
40
+ self.no = nc + 5 # number of outputs per anchor
41
+ self.nl = len(anchors) # number of detection layers
42
+ self.na = len(anchors[0]) // 2 # number of anchors
43
+ self.grid = [torch.zeros(1)] * self.nl # init grid
44
+ self.anchor_grid = [torch.zeros(1)] * self.nl # init anchor grid
45
+ self.register_buffer('anchors', torch.tensor(anchors).float().view(self.nl, -1, 2)) # shape(nl,na,2)
46
+ self.m = nn.ModuleList(nn.Conv2d(x, self.no * self.na, 1) for x in ch) # output conv
47
+ self.inplace = inplace # use in-place ops (e.g. slice assignment)
48
+
49
+ def forward(self, x):
50
+ z = [] # inference output
51
+ for i in range(self.nl):
52
+ x[i] = self.m[i](x[i]) # conv
53
+ bs, _, ny, nx = x[i].shape # x(bs,255,20,20) to x(bs,3,20,20,85)
54
+ x[i] = x[i].view(bs, self.na, self.no, ny, nx).permute(0, 1, 3, 4, 2).contiguous()
55
+
56
+ if not self.training: # inference
57
+ if self.onnx_dynamic or self.grid[i].shape[2:4] != x[i].shape[2:4]:
58
+ self.grid[i], self.anchor_grid[i] = self._make_grid(nx, ny, i)
59
+
60
+ y = x[i].sigmoid()
61
+ if self.inplace:
62
+ y[..., 0:2] = (y[..., 0:2] * 2 - 0.5 + self.grid[i]) * self.stride[i] # xy
63
+ y[..., 2:4] = (y[..., 2:4] * 2) ** 2 * self.anchor_grid[i] # wh
64
+ else: # for YOLOv5 on AWS Inferentia https://github.com/ultralytics/yolov5/pull/2953
65
+ xy = (y[..., 0:2] * 2 - 0.5 + self.grid[i]) * self.stride[i] # xy
66
+ wh = (y[..., 2:4] * 2) ** 2 * self.anchor_grid[i] # wh
67
+ y = torch.cat((xy, wh, y[..., 4:]), -1)
68
+ z.append(y.view(bs, -1, self.no))
69
+
70
+ return x if self.training else (torch.cat(z, 1), x)
71
+
72
+ def _make_grid(self, nx=20, ny=20, i=0):
73
+ d = self.anchors[i].device
74
+ if check_version(torch.__version__, '1.10.0'): # torch>=1.10.0 meshgrid workaround for torch>=0.7 compatibility
75
+ yv, xv = torch.meshgrid([torch.arange(ny, device=d), torch.arange(nx, device=d)], indexing='ij')
76
+ else:
77
+ yv, xv = torch.meshgrid([torch.arange(ny, device=d), torch.arange(nx, device=d)])
78
+ grid = torch.stack((xv, yv), 2).expand((1, self.na, ny, nx, 2)).float()
79
+ anchor_grid = (self.anchors[i].clone() * self.stride[i]) \
80
+ .view((1, self.na, 1, 1, 2)).expand((1, self.na, ny, nx, 2)).float()
81
+ return grid, anchor_grid
82
+
83
+
84
+ class Model(nn.Module):
85
+ def __init__(self, cfg='yolov5s.yaml', ch=3, nc=None, anchors=None): # model, input channels, number of classes
86
+ super().__init__()
87
+ if isinstance(cfg, dict):
88
+ self.yaml = cfg # model dict
89
+ else: # is *.yaml
90
+ import yaml # for torch hub
91
+ self.yaml_file = Path(cfg).name
92
+ with open(cfg, encoding='ascii', errors='ignore') as f:
93
+ self.yaml = yaml.safe_load(f) # model dict
94
+
95
+ # Define model
96
+ ch = self.yaml['ch'] = self.yaml.get('ch', ch) # input channels
97
+ if nc and nc != self.yaml['nc']:
98
+ LOGGER.info(f"Overriding model.yaml nc={self.yaml['nc']} with nc={nc}")
99
+ self.yaml['nc'] = nc # override yaml value
100
+ if anchors:
101
+ LOGGER.info(f'Overriding model.yaml anchors with anchors={anchors}')
102
+ self.yaml['anchors'] = round(anchors) # override yaml value
103
+ self.model, self.save = parse_model(deepcopy(self.yaml), ch=[ch]) # model, savelist
104
+ self.names = [str(i) for i in range(self.yaml['nc'])] # default names
105
+ self.inplace = self.yaml.get('inplace', True)
106
+
107
+ # Build strides, anchors
108
+ m = self.model[-1] # Detect()
109
+ if isinstance(m, Detect):
110
+ s = 256 # 2x min stride
111
+ m.inplace = self.inplace
112
+ m.stride = torch.tensor([s / x.shape[-2] for x in self.forward(torch.zeros(1, ch, s, s))]) # forward
113
+ m.anchors /= m.stride.view(-1, 1, 1)
114
+ check_anchor_order(m)
115
+ self.stride = m.stride
116
+ self._initialize_biases() # only run once
117
+
118
+ # Init weights, biases
119
+ initialize_weights(self)
120
+ self.info()
121
+ LOGGER.info('')
122
+
123
+ def forward(self, x, augment=False, profile=False, visualize=False):
124
+ if augment:
125
+ return self._forward_augment(x) # augmented inference, None
126
+ return self._forward_once(x, profile, visualize) # single-scale inference, train
127
+
128
+ def _forward_augment(self, x):
129
+ img_size = x.shape[-2:] # height, width
130
+ s = [1, 0.83, 0.67] # scales
131
+ f = [None, 3, None] # flips (2-ud, 3-lr)
132
+ y = [] # outputs
133
+ for si, fi in zip(s, f):
134
+ xi = scale_img(x.flip(fi) if fi else x, si, gs=int(self.stride.max()))
135
+ yi = self._forward_once(xi)[0] # forward
136
+ # cv2.imwrite(f'img_{si}.jpg', 255 * xi[0].cpu().numpy().transpose((1, 2, 0))[:, :, ::-1]) # save
137
+ yi = self._descale_pred(yi, fi, si, img_size)
138
+ y.append(yi)
139
+ y = self._clip_augmented(y) # clip augmented tails
140
+ return torch.cat(y, 1), None # augmented inference, train
141
+
142
+ def _forward_once(self, x, profile=False, visualize=False):
143
+ y, dt = [], [] # outputs
144
+ for m in self.model:
145
+ if m.f != -1: # if not from previous layer
146
+ x = y[m.f] if isinstance(m.f, int) else [x if j == -1 else y[j] for j in m.f] # from earlier layers
147
+ if profile:
148
+ self._profile_one_layer(m, x, dt)
149
+ x = m(x) # run
150
+ y.append(x if m.i in self.save else None) # save output
151
+ if visualize:
152
+ feature_visualization(x, m.type, m.i, save_dir=visualize)
153
+ return x
154
+
155
+ def _descale_pred(self, p, flips, scale, img_size):
156
+ # de-scale predictions following augmented inference (inverse operation)
157
+ if self.inplace:
158
+ p[..., :4] /= scale # de-scale
159
+ if flips == 2:
160
+ p[..., 1] = img_size[0] - p[..., 1] # de-flip ud
161
+ elif flips == 3:
162
+ p[..., 0] = img_size[1] - p[..., 0] # de-flip lr
163
+ else:
164
+ x, y, wh = p[..., 0:1] / scale, p[..., 1:2] / scale, p[..., 2:4] / scale # de-scale
165
+ if flips == 2:
166
+ y = img_size[0] - y # de-flip ud
167
+ elif flips == 3:
168
+ x = img_size[1] - x # de-flip lr
169
+ p = torch.cat((x, y, wh, p[..., 4:]), -1)
170
+ return p
171
+
172
+ def _clip_augmented(self, y):
173
+ # Clip YOLOv5 augmented inference tails
174
+ nl = self.model[-1].nl # number of detection layers (P3-P5)
175
+ g = sum(4 ** x for x in range(nl)) # grid points
176
+ e = 1 # exclude layer count
177
+ i = (y[0].shape[1] // g) * sum(4 ** x for x in range(e)) # indices
178
+ y[0] = y[0][:, :-i] # large
179
+ i = (y[-1].shape[1] // g) * sum(4 ** (nl - 1 - x) for x in range(e)) # indices
180
+ y[-1] = y[-1][:, i:] # small
181
+ return y
182
+
183
+ def _profile_one_layer(self, m, x, dt):
184
+ c = isinstance(m, Detect) # is final layer, copy input as inplace fix
185
+ o = thop.profile(m, inputs=(x.copy() if c else x,), verbose=False)[0] / 1E9 * 2 if thop else 0 # FLOPs
186
+ t = time_sync()
187
+ for _ in range(10):
188
+ m(x.copy() if c else x)
189
+ dt.append((time_sync() - t) * 100)
190
+ if m == self.model[0]:
191
+ LOGGER.info(f"{'time (ms)':>10s} {'GFLOPs':>10s} {'params':>10s} {'module'}")
192
+ LOGGER.info(f'{dt[-1]:10.2f} {o:10.2f} {m.np:10.0f} {m.type}')
193
+ if c:
194
+ LOGGER.info(f"{sum(dt):10.2f} {'-':>10s} {'-':>10s} Total")
195
+
196
+ def _initialize_biases(self, cf=None): # initialize biases into Detect(), cf is class frequency
197
+ # https://arxiv.org/abs/1708.02002 section 3.3
198
+ # cf = torch.bincount(torch.tensor(np.concatenate(dataset.labels, 0)[:, 0]).long(), minlength=nc) + 1.
199
+ m = self.model[-1] # Detect() module
200
+ for mi, s in zip(m.m, m.stride): # from
201
+ b = mi.bias.view(m.na, -1) # conv.bias(255) to (3,85)
202
+ b.data[:, 4] += math.log(8 / (640 / s) ** 2) # obj (8 objects per 640 image)
203
+ b.data[:, 5:] += math.log(0.6 / (m.nc - 0.999999)) if cf is None else torch.log(cf / cf.sum()) # cls
204
+ mi.bias = torch.nn.Parameter(b.view(-1), requires_grad=True)
205
+
206
+ def _print_biases(self):
207
+ m = self.model[-1] # Detect() module
208
+ for mi in m.m: # from
209
+ b = mi.bias.detach().view(m.na, -1).T # conv.bias(255) to (3,85)
210
+ LOGGER.info(
211
+ ('%6g Conv2d.bias:' + '%10.3g' * 6) % (mi.weight.shape[1], *b[:5].mean(1).tolist(), b[5:].mean()))
212
+
213
+ # def _print_weights(self):
214
+ # for m in self.model.modules():
215
+ # if type(m) is Bottleneck:
216
+ # LOGGER.info('%10.3g' % (m.w.detach().sigmoid() * 2)) # shortcut weights
217
+
218
+ def fuse(self): # fuse model Conv2d() + BatchNorm2d() layers
219
+ LOGGER.info('Fusing layers... ')
220
+ for m in self.model.modules():
221
+ if isinstance(m, (Conv, DWConv)) and hasattr(m, 'bn'):
222
+ m.conv = fuse_conv_and_bn(m.conv, m.bn) # update conv
223
+ delattr(m, 'bn') # remove batchnorm
224
+ m.forward = m.forward_fuse # update forward
225
+ self.info()
226
+ return self
227
+
228
+ def info(self, verbose=False, img_size=640): # print model information
229
+ model_info(self, verbose, img_size)
230
+
231
+ def _apply(self, fn):
232
+ # Apply to(), cpu(), cuda(), half() to model tensors that are not parameters or registered buffers
233
+ self = super()._apply(fn)
234
+ m = self.model[-1] # Detect()
235
+ if isinstance(m, Detect):
236
+ m.stride = fn(m.stride)
237
+ m.grid = list(map(fn, m.grid))
238
+ if isinstance(m.anchor_grid, list):
239
+ m.anchor_grid = list(map(fn, m.anchor_grid))
240
+ return self
241
+
242
+
243
+ def parse_model(d, ch): # model_dict, input_channels(3)
244
+ LOGGER.info(f"\n{'':>3}{'from':>18}{'n':>3}{'params':>10} {'module':<40}{'arguments':<30}")
245
+ anchors, nc, gd, gw = d['anchors'], d['nc'], d['depth_multiple'], d['width_multiple']
246
+ na = (len(anchors[0]) // 2) if isinstance(anchors, list) else anchors # number of anchors
247
+ no = na * (nc + 5) # number of outputs = anchors * (classes + 5)
248
+
249
+ layers, save, c2 = [], [], ch[-1] # layers, savelist, ch out
250
+ for i, (f, n, m, args) in enumerate(d['backbone'] + d['head']): # from, number, module, args
251
+ m = eval(m) if isinstance(m, str) else m # eval strings
252
+ for j, a in enumerate(args):
253
+ try:
254
+ args[j] = eval(a) if isinstance(a, str) else a # eval strings
255
+ except NameError:
256
+ pass
257
+
258
+ n = n_ = max(round(n * gd), 1) if n > 1 else n # depth gain
259
+ if m in [Conv, GhostConv, Bottleneck, GhostBottleneck, SPP, SPPF, DWConv, MixConv2d, Focus, CrossConv,
260
+ BottleneckCSP, C3, C3TR, C3SPP, C3Ghost]:
261
+ c1, c2 = ch[f], args[0]
262
+ if c2 != no: # if not output
263
+ c2 = make_divisible(c2 * gw, 8)
264
+
265
+ args = [c1, c2, *args[1:]]
266
+ if m in [BottleneckCSP, C3, C3TR, C3Ghost]:
267
+ args.insert(2, n) # number of repeats
268
+ n = 1
269
+ elif m is nn.BatchNorm2d:
270
+ args = [ch[f]]
271
+ elif m is Concat:
272
+ c2 = sum(ch[x] for x in f)
273
+ elif m is Detect:
274
+ args.append([ch[x] for x in f])
275
+ if isinstance(args[1], int): # number of anchors
276
+ args[1] = [list(range(args[1] * 2))] * len(f)
277
+ elif m is Contract:
278
+ c2 = ch[f] * args[0] ** 2
279
+ elif m is Expand:
280
+ c2 = ch[f] // args[0] ** 2
281
+ else:
282
+ c2 = ch[f]
283
+
284
+ m_ = nn.Sequential(*(m(*args) for _ in range(n))) if n > 1 else m(*args) # module
285
+ t = str(m)[8:-2].replace('__main__.', '') # module type
286
+ np = sum(x.numel() for x in m_.parameters()) # number params
287
+ m_.i, m_.f, m_.type, m_.np = i, f, t, np # attach index, 'from' index, type, number params
288
+ LOGGER.info(f'{i:>3}{str(f):>18}{n_:>3}{np:10.0f} {t:<40}{str(args):<30}') # print
289
+ save.extend(x % i for x in ([f] if isinstance(f, int) else f) if x != -1) # append to savelist
290
+ layers.append(m_)
291
+ if i == 0:
292
+ ch = []
293
+ ch.append(c2)
294
+ return nn.Sequential(*layers), sorted(save)
295
+
296
+
297
+ if __name__ == '__main__':
298
+ parser = argparse.ArgumentParser()
299
+ parser.add_argument('--cfg', type=str, default='yolov5s.yaml', help='model.yaml')
300
+ parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu')
301
+ parser.add_argument('--profile', action='store_true', help='profile model speed')
302
+ parser.add_argument('--test', action='store_true', help='test all yolo*.yaml')
303
+ opt = parser.parse_args()
304
+ opt.cfg = check_yaml(opt.cfg) # check YAML
305
+ print_args(FILE.stem, opt)
306
+ device = select_device(opt.device)
307
+
308
+ # Create model
309
+ model = Model(opt.cfg).to(device)
310
+ model.train()
311
+
312
+ # Profile
313
+ if opt.profile:
314
+ img = torch.rand(8 if torch.cuda.is_available() else 1, 3, 640, 640).to(device)
315
+ y = model(img, profile=True)
316
+
317
+ # Test all models
318
+ if opt.test:
319
+ for cfg in Path(ROOT / 'models').rglob('yolo*.yaml'):
320
+ try:
321
+ _ = Model(cfg)
322
+ except Exception as e:
323
+ print(f'Error in {cfg}: {e}')
324
+
325
+ # Tensorboard (not working https://github.com/ultralytics/yolov5/issues/2898)
326
+ # from torch.utils.tensorboard import SummaryWriter
327
+ # tb_writer = SummaryWriter('.')
328
+ # LOGGER.info("Run 'tensorboard --logdir=models' to view tensorboard at http://localhost:6006/")
329
+ # tb_writer.add_graph(torch.jit.trace(model, img, strict=False), []) # add model graph
yolov5/models/yolov5l.yaml ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # YOLOv5 πŸš€ by Ultralytics, GPL-3.0 license
2
+
3
+ # Parameters
4
+ nc: 80 # number of classes
5
+ depth_multiple: 1.0 # model depth multiple
6
+ width_multiple: 1.0 # layer channel multiple
7
+ anchors:
8
+ - [10,13, 16,30, 33,23] # P3/8
9
+ - [30,61, 62,45, 59,119] # P4/16
10
+ - [116,90, 156,198, 373,326] # P5/32
11
+
12
+ # YOLOv5 v6.0 backbone
13
+ backbone:
14
+ # [from, number, module, args]
15
+ [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
16
+ [-1, 1, Conv, [128, 3, 2]], # 1-P2/4
17
+ [-1, 3, C3, [128]],
18
+ [-1, 1, Conv, [256, 3, 2]], # 3-P3/8
19
+ [-1, 6, C3, [256]],
20
+ [-1, 1, Conv, [512, 3, 2]], # 5-P4/16
21
+ [-1, 9, C3, [512]],
22
+ [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32
23
+ [-1, 3, C3, [1024]],
24
+ [-1, 1, SPPF, [1024, 5]], # 9
25
+ ]
26
+
27
+ # YOLOv5 v6.0 head
28
+ head:
29
+ [[-1, 1, Conv, [512, 1, 1]],
30
+ [-1, 1, nn.Upsample, [None, 2, 'nearest']],
31
+ [[-1, 6], 1, Concat, [1]], # cat backbone P4
32
+ [-1, 3, C3, [512, False]], # 13
33
+
34
+ [-1, 1, Conv, [256, 1, 1]],
35
+ [-1, 1, nn.Upsample, [None, 2, 'nearest']],
36
+ [[-1, 4], 1, Concat, [1]], # cat backbone P3
37
+ [-1, 3, C3, [256, False]], # 17 (P3/8-small)
38
+
39
+ [-1, 1, Conv, [256, 3, 2]],
40
+ [[-1, 14], 1, Concat, [1]], # cat head P4
41
+ [-1, 3, C3, [512, False]], # 20 (P4/16-medium)
42
+
43
+ [-1, 1, Conv, [512, 3, 2]],
44
+ [[-1, 10], 1, Concat, [1]], # cat head P5
45
+ [-1, 3, C3, [1024, False]], # 23 (P5/32-large)
46
+
47
+ [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)
48
+ ]
yolov5/models/yolov5m.yaml ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # YOLOv5 πŸš€ by Ultralytics, GPL-3.0 license
2
+
3
+ # Parameters
4
+ nc: 80 # number of classes
5
+ depth_multiple: 0.67 # model depth multiple
6
+ width_multiple: 0.75 # layer channel multiple
7
+ anchors:
8
+ - [10,13, 16,30, 33,23] # P3/8
9
+ - [30,61, 62,45, 59,119] # P4/16
10
+ - [116,90, 156,198, 373,326] # P5/32
11
+
12
+ # YOLOv5 v6.0 backbone
13
+ backbone:
14
+ # [from, number, module, args]
15
+ [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
16
+ [-1, 1, Conv, [128, 3, 2]], # 1-P2/4
17
+ [-1, 3, C3, [128]],
18
+ [-1, 1, Conv, [256, 3, 2]], # 3-P3/8
19
+ [-1, 6, C3, [256]],
20
+ [-1, 1, Conv, [512, 3, 2]], # 5-P4/16
21
+ [-1, 9, C3, [512]],
22
+ [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32
23
+ [-1, 3, C3, [1024]],
24
+ [-1, 1, SPPF, [1024, 5]], # 9
25
+ ]
26
+
27
+ # YOLOv5 v6.0 head
28
+ head:
29
+ [[-1, 1, Conv, [512, 1, 1]],
30
+ [-1, 1, nn.Upsample, [None, 2, 'nearest']],
31
+ [[-1, 6], 1, Concat, [1]], # cat backbone P4
32
+ [-1, 3, C3, [512, False]], # 13
33
+
34
+ [-1, 1, Conv, [256, 1, 1]],
35
+ [-1, 1, nn.Upsample, [None, 2, 'nearest']],
36
+ [[-1, 4], 1, Concat, [1]], # cat backbone P3
37
+ [-1, 3, C3, [256, False]], # 17 (P3/8-small)
38
+
39
+ [-1, 1, Conv, [256, 3, 2]],
40
+ [[-1, 14], 1, Concat, [1]], # cat head P4
41
+ [-1, 3, C3, [512, False]], # 20 (P4/16-medium)
42
+
43
+ [-1, 1, Conv, [512, 3, 2]],
44
+ [[-1, 10], 1, Concat, [1]], # cat head P5
45
+ [-1, 3, C3, [1024, False]], # 23 (P5/32-large)
46
+
47
+ [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)
48
+ ]
yolov5/models/yolov5n.yaml ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # YOLOv5 πŸš€ by Ultralytics, GPL-3.0 license
2
+
3
+ # Parameters
4
+ nc: 80 # number of classes
5
+ depth_multiple: 0.33 # model depth multiple
6
+ width_multiple: 0.25 # layer channel multiple
7
+ anchors:
8
+ - [10,13, 16,30, 33,23] # P3/8
9
+ - [30,61, 62,45, 59,119] # P4/16
10
+ - [116,90, 156,198, 373,326] # P5/32
11
+
12
+ # YOLOv5 v6.0 backbone
13
+ backbone:
14
+ # [from, number, module, args]
15
+ [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
16
+ [-1, 1, Conv, [128, 3, 2]], # 1-P2/4
17
+ [-1, 3, C3, [128]],
18
+ [-1, 1, Conv, [256, 3, 2]], # 3-P3/8
19
+ [-1, 6, C3, [256]],
20
+ [-1, 1, Conv, [512, 3, 2]], # 5-P4/16
21
+ [-1, 9, C3, [512]],
22
+ [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32
23
+ [-1, 3, C3, [1024]],
24
+ [-1, 1, SPPF, [1024, 5]], # 9
25
+ ]
26
+
27
+ # YOLOv5 v6.0 head
28
+ head:
29
+ [[-1, 1, Conv, [512, 1, 1]],
30
+ [-1, 1, nn.Upsample, [None, 2, 'nearest']],
31
+ [[-1, 6], 1, Concat, [1]], # cat backbone P4
32
+ [-1, 3, C3, [512, False]], # 13
33
+
34
+ [-1, 1, Conv, [256, 1, 1]],
35
+ [-1, 1, nn.Upsample, [None, 2, 'nearest']],
36
+ [[-1, 4], 1, Concat, [1]], # cat backbone P3
37
+ [-1, 3, C3, [256, False]], # 17 (P3/8-small)
38
+
39
+ [-1, 1, Conv, [256, 3, 2]],
40
+ [[-1, 14], 1, Concat, [1]], # cat head P4
41
+ [-1, 3, C3, [512, False]], # 20 (P4/16-medium)
42
+
43
+ [-1, 1, Conv, [512, 3, 2]],
44
+ [[-1, 10], 1, Concat, [1]], # cat head P5
45
+ [-1, 3, C3, [1024, False]], # 23 (P5/32-large)
46
+
47
+ [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)
48
+ ]
yolov5/models/yolov5s.yaml ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # YOLOv5 πŸš€ by Ultralytics, GPL-3.0 license
2
+
3
+ # Parameters
4
+ nc: 80 # number of classes
5
+ depth_multiple: 0.33 # model depth multiple
6
+ width_multiple: 0.50 # layer channel multiple
7
+ anchors:
8
+ - [10,13, 16,30, 33,23] # P3/8
9
+ - [30,61, 62,45, 59,119] # P4/16
10
+ - [116,90, 156,198, 373,326] # P5/32
11
+
12
+ # YOLOv5 v6.0 backbone
13
+ backbone:
14
+ # [from, number, module, args]
15
+ [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
16
+ [-1, 1, Conv, [128, 3, 2]], # 1-P2/4
17
+ [-1, 3, C3, [128]],
18
+ [-1, 1, Conv, [256, 3, 2]], # 3-P3/8
19
+ [-1, 6, C3, [256]],
20
+ [-1, 1, Conv, [512, 3, 2]], # 5-P4/16
21
+ [-1, 9, C3, [512]],
22
+ [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32
23
+ [-1, 3, C3, [1024]],
24
+ [-1, 1, SPPF, [1024, 5]], # 9
25
+ ]
26
+
27
+ # YOLOv5 v6.0 head
28
+ head:
29
+ [[-1, 1, Conv, [512, 1, 1]],
30
+ [-1, 1, nn.Upsample, [None, 2, 'nearest']],
31
+ [[-1, 6], 1, Concat, [1]], # cat backbone P4
32
+ [-1, 3, C3, [512, False]], # 13
33
+
34
+ [-1, 1, Conv, [256, 1, 1]],
35
+ [-1, 1, nn.Upsample, [None, 2, 'nearest']],
36
+ [[-1, 4], 1, Concat, [1]], # cat backbone P3
37
+ [-1, 3, C3, [256, False]], # 17 (P3/8-small)
38
+
39
+ [-1, 1, Conv, [256, 3, 2]],
40
+ [[-1, 14], 1, Concat, [1]], # cat head P4
41
+ [-1, 3, C3, [512, False]], # 20 (P4/16-medium)
42
+
43
+ [-1, 1, Conv, [512, 3, 2]],
44
+ [[-1, 10], 1, Concat, [1]], # cat head P5
45
+ [-1, 3, C3, [1024, False]], # 23 (P5/32-large)
46
+
47
+ [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)
48
+ ]
yolov5/models/yolov5x.yaml ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # YOLOv5 πŸš€ by Ultralytics, GPL-3.0 license
2
+
3
+ # Parameters
4
+ nc: 80 # number of classes
5
+ depth_multiple: 1.33 # model depth multiple
6
+ width_multiple: 1.25 # layer channel multiple
7
+ anchors:
8
+ - [10,13, 16,30, 33,23] # P3/8
9
+ - [30,61, 62,45, 59,119] # P4/16
10
+ - [116,90, 156,198, 373,326] # P5/32
11
+
12
+ # YOLOv5 v6.0 backbone
13
+ backbone:
14
+ # [from, number, module, args]
15
+ [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
16
+ [-1, 1, Conv, [128, 3, 2]], # 1-P2/4
17
+ [-1, 3, C3, [128]],
18
+ [-1, 1, Conv, [256, 3, 2]], # 3-P3/8
19
+ [-1, 6, C3, [256]],
20
+ [-1, 1, Conv, [512, 3, 2]], # 5-P4/16
21
+ [-1, 9, C3, [512]],
22
+ [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32
23
+ [-1, 3, C3, [1024]],
24
+ [-1, 1, SPPF, [1024, 5]], # 9
25
+ ]
26
+
27
+ # YOLOv5 v6.0 head
28
+ head:
29
+ [[-1, 1, Conv, [512, 1, 1]],
30
+ [-1, 1, nn.Upsample, [None, 2, 'nearest']],
31
+ [[-1, 6], 1, Concat, [1]], # cat backbone P4
32
+ [-1, 3, C3, [512, False]], # 13
33
+
34
+ [-1, 1, Conv, [256, 1, 1]],
35
+ [-1, 1, nn.Upsample, [None, 2, 'nearest']],
36
+ [[-1, 4], 1, Concat, [1]], # cat backbone P3
37
+ [-1, 3, C3, [256, False]], # 17 (P3/8-small)
38
+
39
+ [-1, 1, Conv, [256, 3, 2]],
40
+ [[-1, 14], 1, Concat, [1]], # cat head P4
41
+ [-1, 3, C3, [512, False]], # 20 (P4/16-medium)
42
+
43
+ [-1, 1, Conv, [512, 3, 2]],
44
+ [[-1, 10], 1, Concat, [1]], # cat head P5
45
+ [-1, 3, C3, [1024, False]], # 23 (P5/32-large)
46
+
47
+ [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)
48
+ ]
yolov5/utils/__init__.py ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # YOLOv5 πŸš€ by Ultralytics, GPL-3.0 license
2
+ """
3
+ utils/initialization
4
+ """
5
+
6
+
7
+ def notebook_init(verbose=True):
8
+ # Check system software and hardware
9
+ print('Checking setup...')
10
+
11
+ import os
12
+ import shutil
13
+
14
+ from utils.general import check_requirements, emojis, is_colab
15
+ from utils.torch_utils import select_device # imports
16
+
17
+ check_requirements(('psutil', 'IPython'))
18
+ import psutil
19
+ from IPython import display # to display images and clear console output
20
+
21
+ if is_colab():
22
+ shutil.rmtree('/content/sample_data', ignore_errors=True) # remove colab /sample_data directory
23
+
24
+ if verbose:
25
+ # System info
26
+ # gb = 1 / 1000 ** 3 # bytes to GB
27
+ gib = 1 / 1024 ** 3 # bytes to GiB
28
+ ram = psutil.virtual_memory().total
29
+ total, used, free = shutil.disk_usage("/")
30
+ display.clear_output()
31
+ s = f'({os.cpu_count()} CPUs, {ram * gib:.1f} GB RAM, {(total - free) * gib:.1f}/{total * gib:.1f} GB disk)'
32
+ else:
33
+ s = ''
34
+
35
+ select_device(newline=False)
36
+ print(emojis(f'Setup complete βœ… {s}'))
37
+ return display
yolov5/utils/__pycache__/__init__.cpython-36.pyc ADDED
Binary file (1.08 kB). View file
 
yolov5/utils/__pycache__/__init__.cpython-39.pyc ADDED
Binary file (1.06 kB). View file
 
yolov5/utils/__pycache__/activations.cpython-36.pyc ADDED
Binary file (4.56 kB). View file
 
yolov5/utils/__pycache__/activations.cpython-39.pyc ADDED
Binary file (4.58 kB). View file
 
yolov5/utils/__pycache__/augmentations.cpython-36.pyc ADDED
Binary file (9.1 kB). View file
 
yolov5/utils/__pycache__/augmentations.cpython-39.pyc ADDED
Binary file (9.12 kB). View file
 
yolov5/utils/__pycache__/autoanchor.cpython-36.pyc ADDED
Binary file (6.34 kB). View file