├── Files
├── plots.py
└── predict.py
├── LICENSE
├── README.md
├── Single_Click_YOLOv7_Instance_Segmentation_withDistance_Estimation.ipynb
├── YOLOv7_Segmentation_With_DeepSORT_Tracking.ipynb
├── classify
├── predict.py
├── train.py
└── val.py
├── data
├── coco.names
├── coco.yaml
├── hyps
│ ├── hyp.scratch-high.yaml
│ ├── hyp.scratch-low.yaml
│ └── hyp.scratch-med.yaml
└── scripts
│ ├── get_coco.sh
│ └── get_imagenet.sh
├── detect.py
├── export.py
├── figure
├── 1.png
├── 2.png
├── 3.png
├── Screenshot (350).png
├── Screenshot (351).png
├── Screenshot (352).png
└── yolov7-seg-example.png
├── hubconf.py
├── models
├── __init__.py
├── __pycache__
│ ├── __init__.cpython-310.pyc
│ ├── common.cpython-310.pyc
│ ├── experimental.cpython-310.pyc
│ └── yolo.cpython-310.pyc
├── common.py
├── experimental.py
├── hub
│ ├── yolov3-spp.yaml
│ ├── yolov3-tiny.yaml
│ └── yolov3.yaml
├── segment
│ └── yolov7-seg.yaml
├── tf.py
└── yolo.py
├── requirements.txt
├── runs
└── predict-seg
│ └── exp
│ └── Demo.mp4
├── segment
├── predict.py
├── train.py
└── val.py
├── setup.cfg
├── train.py
├── utils
├── __init__.py
├── __pycache__
│ ├── __init__.cpython-310.pyc
│ ├── augmentations.cpython-310.pyc
│ ├── autoanchor.cpython-310.pyc
│ ├── dataloaders.cpython-310.pyc
│ ├── downloads.cpython-310.pyc
│ ├── general.cpython-310.pyc
│ ├── metrics.cpython-310.pyc
│ ├── plots.cpython-310.pyc
│ └── torch_utils.cpython-310.pyc
├── activations.py
├── augmentations.py
├── autoanchor.py
├── autobatch.py
├── aws
│ ├── __init__.py
│ ├── mime.sh
│ ├── resume.py
│ └── userdata.sh
├── benchmarks.py
├── callbacks.py
├── dataloaders.py
├── docker
│ ├── Dockerfile
│ ├── Dockerfile-arm64
│ └── Dockerfile-cpu
├── downloads.py
├── flask_rest_api
│ ├── README.md
│ ├── example_request.py
│ └── restapi.py
├── general.py
├── google_app_engine
│ ├── Dockerfile
│ ├── additional_requirements.txt
│ └── app.yaml
├── loggers
│ ├── __init__.py
│ ├── clearml
│ │ ├── README.md
│ │ ├── __init__.py
│ │ ├── clearml_utils.py
│ │ └── hpo.py
│ └── wandb
│ │ ├── README.md
│ │ ├── __init__.py
│ │ ├── log_dataset.py
│ │ ├── sweep.py
│ │ ├── sweep.yaml
│ │ └── wandb_utils.py
├── loss.py
├── metrics.py
├── plots.py
├── segment
│ ├── __init__.py
│ ├── __pycache__
│ │ ├── __init__.cpython-310.pyc
│ │ ├── general.cpython-310.pyc
│ │ └── plots.cpython-310.pyc
│ ├── augmentations.py
│ ├── dataloaders.py
│ ├── general.py
│ ├── loss.py
│ ├── metrics.py
│ └── plots.py
└── torch_utils.py
└── val.py
/README.md:
--------------------------------------------------------------------------------
1 |
2 | YOLOv7 Segmentation with DeepSORT Tracking
3 |
4 |
5 | I have implemented the YOLOv7 Segmantation with DeepSORT Tracking, please support by giving a star.
6 |
7 | [`yolov7-seg.pt`](https://github.com/WongKinYiu/yolov7/releases/download/v0.1/yolov7-seg.pt)
8 |
9 | ## Steps to run Code
10 |
11 | - Clone the repository
12 | ```
13 | https://github.com/MuhammadMoinFaisal/yolov7-segmentation-with-DeepSORT-Tracking.git
14 | ```
15 | - Goto the cloned folder.
16 | ```
17 | cd yolov7-segmentation-with-DeepSORT-Tracking
18 | ```
19 | - Create a virtual envirnoment (Recommended, If you dont want to disturb python packages)
20 | ```
21 | ### For Linux Users
22 | python3 -m venv yolov7seg
23 | source yolov7seg/bin/activate
24 |
25 | ### For Window Users
26 | python3 -m venv yolov7seg
27 | cd yolov7seg
28 | cd Scripts
29 | activate
30 | cd ..
31 | cd ..
32 | ```
33 |
34 | - Downloading the DeepSORT Files From The Google Drive
35 | ```
36 | cd yolov7-segmentation-with-DeepSORT-Tracking
37 | gdown "https://drive.google.com/uc?id=1BNZ1S5yflbQpbHeRM1fNeu_2WfuP17hJ&confirm=t"
38 | unzip /content/yolov7-segmentation-with-DeepSORT-Tracking/deep_sort_pytorch.zip
39 | ```
40 |
41 | - Downloading a Sample Video from the Google Drive
42 | ```
43 | gdown "https://drive.google.com/uc?id=1o-G_Fs-XtF_Nn_fQdri6GZWYtD_3_Ckw&confirm=t"
44 | ```
45 |
46 | - Upgrade pip with mentioned command below.
47 | ```
48 | pip install --upgrade pip
49 | ```
50 | - Install requirements with mentioned command below.
51 | ```
52 | pip install -r requirements.txt
53 | ```
54 | - Download weights from [link](https://github.com/RizwanMunawar/yolov7-segmentation/releases/download/yolov7-segmentation/yolov7-seg.pt) and store in "yolov7-segmentation-with-DeepSORT-Tracking" directory.
55 |
56 | - Run the code with mentioned command below.
57 | ```
58 | #for segmentation with detection + Tracking
59 | python3 segment/predict.py --source videosfinal.mp4 --weights yolov7-seg.pt --track
60 | ```
61 |
62 | - Output file will be created in the working directory with name runs/predict-seg/exp/"original-video-name.mp4"
63 |
64 | ## Colab File Link
65 | The google colab file link is provided below, you can check the implementation in Google Colab, and its a single click implementation, you just need to select the Run Time as GPU, and click on Run All.
66 |
67 | [`Google Colab File`](https://colab.research.google.com/drive/1I6_UpDniCsOrL5fj_bTX337Jo_UWhPGQ?usp=sharing)
68 |
69 |
70 | ## DeepSORT Files
71 |
72 | The DeepSORT files are uplaoded in the Google Drive Link Below.
73 | [`DeepSORT Files`](https://drive.google.com/drive/folders/1YjbfZL0n6mQH-hvD_DpoxBLVj9prJMpG)
74 |
75 | ### RESULTS
76 |
77 | #### Vehicles Semantic Segmentation
78 | 
79 |
80 | #### Vehicles Sematic Segmentation
81 |
82 | 
83 |
84 | #### Vehicles Semantic Segmentation
85 |
86 | 
87 |
88 | ## References
89 | - https://github.com/WongKinYiu/yolov7.git
90 |
--------------------------------------------------------------------------------
/classify/predict.py:
--------------------------------------------------------------------------------
1 | # YOLOv5 🚀 by Ultralytics, GPL-3.0 license
2 | """
3 | Run YOLOv5 classification inference on images, videos, directories, globs, YouTube, webcam, streams, etc.
4 |
5 | Usage - sources:
6 | $ python classify/predict.py --weights yolov5s-cls.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 classify/predict.py --weights yolov5s-cls.pt # PyTorch
16 | yolov5s-cls.torchscript # TorchScript
17 | yolov5s-cls.onnx # ONNX Runtime or OpenCV DNN with --dnn
18 | yolov5s-cls.xml # OpenVINO
19 | yolov5s-cls.engine # TensorRT
20 | yolov5s-cls.mlmodel # CoreML (macOS-only)
21 | yolov5s-cls_saved_model # TensorFlow SavedModel
22 | yolov5s-cls.pb # TensorFlow GraphDef
23 | yolov5s-cls.tflite # TensorFlow Lite
24 | yolov5s-cls_edgetpu.tflite # TensorFlow Edge TPU
25 | """
26 |
27 | import argparse
28 | import os
29 | import platform
30 | import sys
31 | from pathlib import Path
32 |
33 | import torch
34 | import torch.backends.cudnn as cudnn
35 | import torch.nn.functional as F
36 |
37 | FILE = Path(__file__).resolve()
38 | ROOT = FILE.parents[1] # YOLOv5 root directory
39 | if str(ROOT) not in sys.path:
40 | sys.path.append(str(ROOT)) # add ROOT to PATH
41 | ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative
42 |
43 | from models.common import DetectMultiBackend
44 | from utils.augmentations import classify_transforms
45 | from utils.dataloaders import IMG_FORMATS, VID_FORMATS, LoadImages, LoadStreams
46 | from utils.general import (LOGGER, Profile, check_file, check_img_size, check_imshow, check_requirements, colorstr, cv2,
47 | increment_path, print_args, strip_optimizer)
48 | from utils.plots import Annotator
49 | from utils.torch_utils import select_device, smart_inference_mode
50 |
51 |
52 | @smart_inference_mode()
53 | def run(
54 | weights=ROOT / 'yolov5s-cls.pt', # model.pt path(s)
55 | source=ROOT / 'data/images', # file/dir/URL/glob, 0 for webcam
56 | data=ROOT / 'data/coco128.yaml', # dataset.yaml path
57 | imgsz=(224, 224), # inference size (height, width)
58 | device='', # cuda device, i.e. 0 or 0,1,2,3 or cpu
59 | view_img=False, # show results
60 | save_txt=False, # save results to *.txt
61 | nosave=False, # do not save images/videos
62 | augment=False, # augmented inference
63 | visualize=False, # visualize features
64 | update=False, # update all models
65 | project=ROOT / 'runs/predict-cls', # save results to project/name
66 | name='exp', # save results to project/name
67 | exist_ok=False, # existing project/name ok, do not increment
68 | half=False, # use FP16 half-precision inference
69 | dnn=False, # use OpenCV DNN for ONNX inference
70 | ):
71 | source = str(source)
72 | save_img = not nosave and not source.endswith('.txt') # save inference images
73 | is_file = Path(source).suffix[1:] in (IMG_FORMATS + VID_FORMATS)
74 | is_url = source.lower().startswith(('rtsp://', 'rtmp://', 'http://', 'https://'))
75 | webcam = source.isnumeric() or source.endswith('.txt') or (is_url and not is_file)
76 | if is_url and is_file:
77 | source = check_file(source) # download
78 |
79 | # Directories
80 | save_dir = increment_path(Path(project) / name, exist_ok=exist_ok) # increment run
81 | (save_dir / 'labels' if save_txt else save_dir).mkdir(parents=True, exist_ok=True) # make dir
82 |
83 | # Load model
84 | device = select_device(device)
85 | model = DetectMultiBackend(weights, device=device, dnn=dnn, data=data, fp16=half)
86 | stride, names, pt = model.stride, model.names, model.pt
87 | imgsz = check_img_size(imgsz, s=stride) # check image size
88 |
89 | # Dataloader
90 | if webcam:
91 | view_img = check_imshow()
92 | cudnn.benchmark = True # set True to speed up constant image size inference
93 | dataset = LoadStreams(source, img_size=imgsz, transforms=classify_transforms(imgsz[0]))
94 | bs = len(dataset) # batch_size
95 | else:
96 | dataset = LoadImages(source, img_size=imgsz, transforms=classify_transforms(imgsz[0]))
97 | bs = 1 # batch_size
98 | vid_path, vid_writer = [None] * bs, [None] * bs
99 |
100 | # Run inference
101 | model.warmup(imgsz=(1 if pt else bs, 3, *imgsz)) # warmup
102 | seen, windows, dt = 0, [], (Profile(), Profile(), Profile())
103 | for path, im, im0s, vid_cap, s in dataset:
104 | with dt[0]:
105 | im = torch.Tensor(im).to(device)
106 | im = im.half() if model.fp16 else im.float() # uint8 to fp16/32
107 | if len(im.shape) == 3:
108 | im = im[None] # expand for batch dim
109 |
110 | # Inference
111 | with dt[1]:
112 | results = model(im)
113 |
114 | # Post-process
115 | with dt[2]:
116 | pred = F.softmax(results, dim=1) # probabilities
117 |
118 | # Process predictions
119 | for i, prob in enumerate(pred): # per image
120 | seen += 1
121 | if webcam: # batch_size >= 1
122 | p, im0 = path[i], im0s[i].copy()
123 | s += f'{i}: '
124 | else:
125 | p, im0 = path, im0s.copy()
126 |
127 | p = Path(p) # to Path
128 | save_path = str(save_dir / p.name) # im.jpg
129 | s += '%gx%g ' % im.shape[2:] # print string
130 | annotator = Annotator(im0, example=str(names), pil=True)
131 |
132 | # Print results
133 | top5i = prob.argsort(0, descending=True)[:5].tolist() # top 5 indices
134 | s += f"{', '.join(f'{names[j]} {prob[j]:.2f}' for j in top5i)}, "
135 |
136 | # Write results
137 | if save_img or view_img: # Add bbox to image
138 | text = '\n'.join(f'{prob[j]:.2f} {names[j]}' for j in top5i)
139 | annotator.text((32, 32), text, txt_color=(255, 255, 255))
140 |
141 | # Stream results
142 | im0 = annotator.result()
143 | if view_img:
144 | if platform.system() == 'Linux' and p not in windows:
145 | windows.append(p)
146 | cv2.namedWindow(str(p), cv2.WINDOW_NORMAL | cv2.WINDOW_KEEPRATIO) # allow window resize (Linux)
147 | cv2.resizeWindow(str(p), im0.shape[1], im0.shape[0])
148 | cv2.imshow(str(p), im0)
149 | cv2.waitKey(1) # 1 millisecond
150 |
151 | # Save results (image with detections)
152 | if save_img:
153 | if dataset.mode == 'image':
154 | cv2.imwrite(save_path, im0)
155 | else: # 'video' or 'stream'
156 | if vid_path[i] != save_path: # new video
157 | vid_path[i] = save_path
158 | if isinstance(vid_writer[i], cv2.VideoWriter):
159 | vid_writer[i].release() # release previous video writer
160 | if vid_cap: # video
161 | fps = vid_cap.get(cv2.CAP_PROP_FPS)
162 | w = int(vid_cap.get(cv2.CAP_PROP_FRAME_WIDTH))
163 | h = int(vid_cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
164 | else: # stream
165 | fps, w, h = 30, im0.shape[1], im0.shape[0]
166 | save_path = str(Path(save_path).with_suffix('.mp4')) # force *.mp4 suffix on results videos
167 | vid_writer[i] = cv2.VideoWriter(save_path, cv2.VideoWriter_fourcc(*'mp4v'), fps, (w, h))
168 | vid_writer[i].write(im0)
169 |
170 | # Print time (inference-only)
171 | LOGGER.info(f"{s}{dt[1].dt * 1E3:.1f}ms")
172 |
173 | # Print results
174 | t = tuple(x.t / seen * 1E3 for x in dt) # speeds per image
175 | LOGGER.info(f'Speed: %.1fms pre-process, %.1fms inference, %.1fms NMS per image at shape {(1, 3, *imgsz)}' % t)
176 | if save_txt or save_img:
177 | s = f"\n{len(list(save_dir.glob('labels/*.txt')))} labels saved to {save_dir / 'labels'}" if save_txt else ''
178 | LOGGER.info(f"Results saved to {colorstr('bold', save_dir)}{s}")
179 | if update:
180 | strip_optimizer(weights[0]) # update model (to fix SourceChangeWarning)
181 |
182 |
183 | def parse_opt():
184 | parser = argparse.ArgumentParser()
185 | parser.add_argument('--weights', nargs='+', type=str, default=ROOT / 'yolov5s-cls.pt', help='model path(s)')
186 | parser.add_argument('--source', type=str, default=ROOT / 'data/images', help='file/dir/URL/glob, 0 for webcam')
187 | parser.add_argument('--data', type=str, default=ROOT / 'data/coco128.yaml', help='(optional) dataset.yaml path')
188 | parser.add_argument('--imgsz', '--img', '--img-size', nargs='+', type=int, default=[224], help='inference size h,w')
189 | parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu')
190 | parser.add_argument('--view-img', action='store_true', help='show results')
191 | parser.add_argument('--save-txt', action='store_true', help='save results to *.txt')
192 | parser.add_argument('--nosave', action='store_true', help='do not save images/videos')
193 | parser.add_argument('--augment', action='store_true', help='augmented inference')
194 | parser.add_argument('--visualize', action='store_true', help='visualize features')
195 | parser.add_argument('--update', action='store_true', help='update all models')
196 | parser.add_argument('--project', default=ROOT / 'runs/predict-cls', help='save results to project/name')
197 | parser.add_argument('--name', default='exp', help='save results to project/name')
198 | parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment')
199 | parser.add_argument('--half', action='store_true', help='use FP16 half-precision inference')
200 | parser.add_argument('--dnn', action='store_true', help='use OpenCV DNN for ONNX inference')
201 | opt = parser.parse_args()
202 | opt.imgsz *= 2 if len(opt.imgsz) == 1 else 1 # expand
203 | print_args(vars(opt))
204 | return opt
205 |
206 |
207 | def main(opt):
208 | check_requirements(exclude=('tensorboard', 'thop'))
209 | run(**vars(opt))
210 |
211 |
212 | if __name__ == "__main__":
213 | opt = parse_opt()
214 | main(opt)
215 |
--------------------------------------------------------------------------------
/classify/val.py:
--------------------------------------------------------------------------------
1 | # YOLOv5 🚀 by Ultralytics, GPL-3.0 license
2 | """
3 | Validate a trained YOLOv5 classification model on a classification dataset
4 |
5 | Usage:
6 | $ bash data/scripts/get_imagenet.sh --val # download ImageNet val split (6.3G, 50000 images)
7 | $ python classify/val.py --weights yolov5m-cls.pt --data ../datasets/imagenet --img 224 # validate ImageNet
8 |
9 | Usage - formats:
10 | $ python classify/val.py --weights yolov5s-cls.pt # PyTorch
11 | yolov5s-cls.torchscript # TorchScript
12 | yolov5s-cls.onnx # ONNX Runtime or OpenCV DNN with --dnn
13 | yolov5s-cls.xml # OpenVINO
14 | yolov5s-cls.engine # TensorRT
15 | yolov5s-cls.mlmodel # CoreML (macOS-only)
16 | yolov5s-cls_saved_model # TensorFlow SavedModel
17 | yolov5s-cls.pb # TensorFlow GraphDef
18 | yolov5s-cls.tflite # TensorFlow Lite
19 | yolov5s-cls_edgetpu.tflite # TensorFlow Edge TPU
20 | """
21 |
22 | import argparse
23 | import os
24 | import sys
25 | from pathlib import Path
26 |
27 | import torch
28 | from tqdm import tqdm
29 |
30 | FILE = Path(__file__).resolve()
31 | ROOT = FILE.parents[1] # YOLOv5 root directory
32 | if str(ROOT) not in sys.path:
33 | sys.path.append(str(ROOT)) # add ROOT to PATH
34 | ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative
35 |
36 | from models.common import DetectMultiBackend
37 | from utils.dataloaders import create_classification_dataloader
38 | from utils.general import LOGGER, Profile, check_img_size, check_requirements, colorstr, increment_path, print_args
39 | from utils.torch_utils import select_device, smart_inference_mode
40 |
41 |
42 | @smart_inference_mode()
43 | def run(
44 | data=ROOT / '../datasets/mnist', # dataset dir
45 | weights=ROOT / 'yolov5s-cls.pt', # model.pt path(s)
46 | batch_size=128, # batch size
47 | imgsz=224, # inference size (pixels)
48 | device='', # cuda device, i.e. 0 or 0,1,2,3 or cpu
49 | workers=8, # max dataloader workers (per RANK in DDP mode)
50 | verbose=False, # verbose output
51 | project=ROOT / 'runs/val-cls', # save to project/name
52 | name='exp', # save to project/name
53 | exist_ok=False, # existing project/name ok, do not increment
54 | half=False, # use FP16 half-precision inference
55 | dnn=False, # use OpenCV DNN for ONNX inference
56 | model=None,
57 | dataloader=None,
58 | criterion=None,
59 | pbar=None,
60 | ):
61 | # Initialize/load model and set device
62 | training = model is not None
63 | if training: # called by train.py
64 | device, pt, jit, engine = next(model.parameters()).device, True, False, False # get model device, PyTorch model
65 | half &= device.type != 'cpu' # half precision only supported on CUDA
66 | model.half() if half else model.float()
67 | else: # called directly
68 | device = select_device(device, batch_size=batch_size)
69 |
70 | # Directories
71 | save_dir = increment_path(Path(project) / name, exist_ok=exist_ok) # increment run
72 | save_dir.mkdir(parents=True, exist_ok=True) # make dir
73 |
74 | # Load model
75 | model = DetectMultiBackend(weights, device=device, dnn=dnn, fp16=half)
76 | stride, pt, jit, engine = model.stride, model.pt, model.jit, model.engine
77 | imgsz = check_img_size(imgsz, s=stride) # check image size
78 | half = model.fp16 # FP16 supported on limited backends with CUDA
79 | if engine:
80 | batch_size = model.batch_size
81 | else:
82 | device = model.device
83 | if not (pt or jit):
84 | batch_size = 1 # export.py models default to batch-size 1
85 | LOGGER.info(f'Forcing --batch-size 1 square inference (1,3,{imgsz},{imgsz}) for non-PyTorch models')
86 |
87 | # Dataloader
88 | data = Path(data)
89 | test_dir = data / 'test' if (data / 'test').exists() else data / 'val' # data/test or data/val
90 | dataloader = create_classification_dataloader(path=test_dir,
91 | imgsz=imgsz,
92 | batch_size=batch_size,
93 | augment=False,
94 | rank=-1,
95 | workers=workers)
96 |
97 | model.eval()
98 | pred, targets, loss, dt = [], [], 0, (Profile(), Profile(), Profile())
99 | n = len(dataloader) # number of batches
100 | action = 'validating' if dataloader.dataset.root.stem == 'val' else 'testing'
101 | desc = f"{pbar.desc[:-36]}{action:>36}" if pbar else f"{action}"
102 | bar = tqdm(dataloader, desc, n, not training, bar_format='{l_bar}{bar:10}{r_bar}{bar:-10b}', position=0)
103 | with torch.cuda.amp.autocast(enabled=device.type != 'cpu'):
104 | for images, labels in bar:
105 | with dt[0]:
106 | images, labels = images.to(device, non_blocking=True), labels.to(device)
107 |
108 | with dt[1]:
109 | y = model(images)
110 |
111 | with dt[2]:
112 | pred.append(y.argsort(1, descending=True)[:, :5])
113 | targets.append(labels)
114 | if criterion:
115 | loss += criterion(y, labels)
116 |
117 | loss /= n
118 | pred, targets = torch.cat(pred), torch.cat(targets)
119 | correct = (targets[:, None] == pred).float()
120 | acc = torch.stack((correct[:, 0], correct.max(1).values), dim=1) # (top1, top5) accuracy
121 | top1, top5 = acc.mean(0).tolist()
122 |
123 | if pbar:
124 | pbar.desc = f"{pbar.desc[:-36]}{loss:>12.3g}{top1:>12.3g}{top5:>12.3g}"
125 | if verbose: # all classes
126 | LOGGER.info(f"{'Class':>24}{'Images':>12}{'top1_acc':>12}{'top5_acc':>12}")
127 | LOGGER.info(f"{'all':>24}{targets.shape[0]:>12}{top1:>12.3g}{top5:>12.3g}")
128 | for i, c in model.names.items():
129 | aci = acc[targets == i]
130 | top1i, top5i = aci.mean(0).tolist()
131 | LOGGER.info(f"{c:>24}{aci.shape[0]:>12}{top1i:>12.3g}{top5i:>12.3g}")
132 |
133 | # Print results
134 | t = tuple(x.t / len(dataloader.dataset.samples) * 1E3 for x in dt) # speeds per image
135 | shape = (1, 3, imgsz, imgsz)
136 | LOGGER.info(f'Speed: %.1fms pre-process, %.1fms inference, %.1fms post-process per image at shape {shape}' % t)
137 | LOGGER.info(f"Results saved to {colorstr('bold', save_dir)}")
138 |
139 | return top1, top5, loss
140 |
141 |
142 | def parse_opt():
143 | parser = argparse.ArgumentParser()
144 | parser.add_argument('--data', type=str, default=ROOT / '../datasets/mnist', help='dataset path')
145 | parser.add_argument('--weights', nargs='+', type=str, default=ROOT / 'yolov5s-cls.pt', help='model.pt path(s)')
146 | parser.add_argument('--batch-size', type=int, default=128, help='batch size')
147 | parser.add_argument('--imgsz', '--img', '--img-size', type=int, default=224, help='inference size (pixels)')
148 | parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu')
149 | parser.add_argument('--workers', type=int, default=8, help='max dataloader workers (per RANK in DDP mode)')
150 | parser.add_argument('--verbose', nargs='?', const=True, default=True, help='verbose output')
151 | parser.add_argument('--project', default=ROOT / 'runs/val-cls', help='save to project/name')
152 | parser.add_argument('--name', default='exp', help='save to project/name')
153 | parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment')
154 | parser.add_argument('--half', action='store_true', help='use FP16 half-precision inference')
155 | parser.add_argument('--dnn', action='store_true', help='use OpenCV DNN for ONNX inference')
156 | opt = parser.parse_args()
157 | print_args(vars(opt))
158 | return opt
159 |
160 |
161 | def main(opt):
162 | check_requirements(exclude=('tensorboard', 'thop'))
163 | run(**vars(opt))
164 |
165 |
166 | if __name__ == "__main__":
167 | opt = parse_opt()
168 | main(opt)
169 |
--------------------------------------------------------------------------------
/data/coco.names:
--------------------------------------------------------------------------------
1 | person
2 | bicycle
3 | car
4 | motorcycle
5 | airplane
6 | bus
7 | train
8 | truck
9 | boat
10 | traffic light
11 | fire hydrant
12 | stop sign
13 | parking meter
14 | bench
15 | bird
16 | cat
17 | dog
18 | horse
19 | sheep
20 | cow
21 | elephant
22 | bear
23 | zebra
24 | giraffe
25 | backpack
26 | umbrella
27 | handbag
28 | tie
29 | suitcase
30 | frisbee
31 | skis
32 | snowboard
33 | sports ball
34 | kite
35 | baseball bat
36 | baseball glove
37 | skateboard
38 | surfboard
39 | tennis racket
40 | bottle
41 | wine glass
42 | cup
43 | fork
44 | knife
45 | spoon
46 | bowl
47 | banana
48 | apple
49 | sandwich
50 | orange
51 | broccoli
52 | carrot
53 | hot dog
54 | pizza
55 | donut
56 | cake
57 | chair
58 | couch
59 | potted plant
60 | bed
61 | dining table
62 | toilet
63 | tv
64 | laptop
65 | mouse
66 | remote
67 | keyboard
68 | cell phone
69 | microwave
70 | oven
71 | toaster
72 | sink
73 | refrigerator
74 | book
75 | clock
76 | vase
77 | scissors
78 | teddy bear
79 | hair drier
80 | toothbrush
81 |
--------------------------------------------------------------------------------
/data/coco.yaml:
--------------------------------------------------------------------------------
1 | # YOLOv5 🚀 by Ultralytics, GPL-3.0 license
2 | # COCO 2017 dataset http://cocodataset.org by Microsoft
3 | # Example usage: python train.py --data coco.yaml
4 | # parent
5 | # ├── yolov5
6 | # └── datasets
7 | # └── coco ← downloads here (20.1 GB)
8 |
9 |
10 | # Train/val/test sets as 1) dir: path/to/imgs, 2) file: path/to/imgs.txt, or 3) list: [path/to/imgs1, path/to/imgs2, ..]
11 | path: ../datasets/coco # dataset root dir
12 | train: train2017.txt # train images (relative to 'path') 118287 images
13 | val: val2017.txt # val images (relative to 'path') 5000 images
14 | test: test-dev2017.txt # 20288 of 40670 images, submit to https://competitions.codalab.org/competitions/20794
15 |
16 | # Classes
17 | names:
18 | 0: person
19 | 1: bicycle
20 | 2: car
21 | 3: motorcycle
22 | 4: airplane
23 | 5: bus
24 | 6: train
25 | 7: truck
26 | 8: boat
27 | 9: traffic light
28 | 10: fire hydrant
29 | 11: stop sign
30 | 12: parking meter
31 | 13: bench
32 | 14: bird
33 | 15: cat
34 | 16: dog
35 | 17: horse
36 | 18: sheep
37 | 19: cow
38 | 20: elephant
39 | 21: bear
40 | 22: zebra
41 | 23: giraffe
42 | 24: backpack
43 | 25: umbrella
44 | 26: handbag
45 | 27: tie
46 | 28: suitcase
47 | 29: frisbee
48 | 30: skis
49 | 31: snowboard
50 | 32: sports ball
51 | 33: kite
52 | 34: baseball bat
53 | 35: baseball glove
54 | 36: skateboard
55 | 37: surfboard
56 | 38: tennis racket
57 | 39: bottle
58 | 40: wine glass
59 | 41: cup
60 | 42: fork
61 | 43: knife
62 | 44: spoon
63 | 45: bowl
64 | 46: banana
65 | 47: apple
66 | 48: sandwich
67 | 49: orange
68 | 50: broccoli
69 | 51: carrot
70 | 52: hot dog
71 | 53: pizza
72 | 54: donut
73 | 55: cake
74 | 56: chair
75 | 57: couch
76 | 58: potted plant
77 | 59: bed
78 | 60: dining table
79 | 61: toilet
80 | 62: tv
81 | 63: laptop
82 | 64: mouse
83 | 65: remote
84 | 66: keyboard
85 | 67: cell phone
86 | 68: microwave
87 | 69: oven
88 | 70: toaster
89 | 71: sink
90 | 72: refrigerator
91 | 73: book
92 | 74: clock
93 | 75: vase
94 | 76: scissors
95 | 77: teddy bear
96 | 78: hair drier
97 | 79: toothbrush
98 |
99 |
100 | # Download script/URL (optional)
101 | download: |
102 | from utils.general import download, Path
103 |
104 |
105 | # Download labels
106 | segments = False # segment or box labels
107 | dir = Path(yaml['path']) # dataset root dir
108 | url = 'https://github.com/ultralytics/yolov5/releases/download/v1.0/'
109 | urls = [url + ('coco2017labels-segments.zip' if segments else 'coco2017labels.zip')] # labels
110 | download(urls, dir=dir.parent)
111 |
112 | # Download data
113 | urls = ['http://images.cocodataset.org/zips/train2017.zip', # 19G, 118k images
114 | 'http://images.cocodataset.org/zips/val2017.zip', # 1G, 5k images
115 | 'http://images.cocodataset.org/zips/test2017.zip'] # 7G, 41k images (optional)
116 | download(urls, dir=dir / 'images', threads=3)
117 |
--------------------------------------------------------------------------------
/data/hyps/hyp.scratch-high.yaml:
--------------------------------------------------------------------------------
1 | # YOLOv5 🚀 by Ultralytics, GPL-3.0 license
2 | # Hyperparameters for high-augmentation COCO training from scratch
3 | # python train.py --batch 32 --cfg yolov5m6.yaml --weights '' --data coco.yaml --img 1280 --epochs 300
4 | # See tutorials for hyperparameter evolution https://github.com/ultralytics/yolov5#tutorials
5 |
6 | lr0: 0.01 # initial learning rate (SGD=1E-2, Adam=1E-3)
7 | lrf: 0.1 # final OneCycleLR learning rate (lr0 * lrf)
8 | momentum: 0.937 # SGD momentum/Adam beta1
9 | weight_decay: 0.0005 # optimizer weight decay 5e-4
10 | warmup_epochs: 3.0 # warmup epochs (fractions ok)
11 | warmup_momentum: 0.8 # warmup initial momentum
12 | warmup_bias_lr: 0.1 # warmup initial bias lr
13 | box: 0.05 # box loss gain
14 | cls: 0.3 # cls loss gain
15 | cls_pw: 1.0 # cls BCELoss positive_weight
16 | obj: 0.7 # obj loss gain (scale with pixels)
17 | obj_pw: 1.0 # obj BCELoss positive_weight
18 | iou_t: 0.20 # IoU training threshold
19 | anchor_t: 4.0 # anchor-multiple threshold
20 | # anchors: 3 # anchors per output layer (0 to ignore)
21 | fl_gamma: 0.0 # focal loss gamma (efficientDet default gamma=1.5)
22 | hsv_h: 0.015 # image HSV-Hue augmentation (fraction)
23 | hsv_s: 0.7 # image HSV-Saturation augmentation (fraction)
24 | hsv_v: 0.4 # image HSV-Value augmentation (fraction)
25 | degrees: 0.0 # image rotation (+/- deg)
26 | translate: 0.1 # image translation (+/- fraction)
27 | scale: 0.9 # image scale (+/- gain)
28 | shear: 0.0 # image shear (+/- deg)
29 | perspective: 0.0 # image perspective (+/- fraction), range 0-0.001
30 | flipud: 0.0 # image flip up-down (probability)
31 | fliplr: 0.5 # image flip left-right (probability)
32 | mosaic: 1.0 # image mosaic (probability)
33 | mixup: 0.1 # image mixup (probability)
34 | copy_paste: 0.1 # segment copy-paste (probability)
35 |
--------------------------------------------------------------------------------
/data/hyps/hyp.scratch-low.yaml:
--------------------------------------------------------------------------------
1 | # YOLOv5 🚀 by Ultralytics, GPL-3.0 license
2 | # Hyperparameters for low-augmentation COCO training from scratch
3 | # python train.py --batch 64 --cfg yolov5n6.yaml --weights '' --data coco.yaml --img 640 --epochs 300 --linear
4 | # See tutorials for hyperparameter evolution https://github.com/ultralytics/yolov5#tutorials
5 |
6 | lr0: 0.01 # initial learning rate (SGD=1E-2, Adam=1E-3)
7 | lrf: 0.01 # final OneCycleLR learning rate (lr0 * lrf)
8 | momentum: 0.937 # SGD momentum/Adam beta1
9 | weight_decay: 0.0005 # optimizer weight decay 5e-4
10 | warmup_epochs: 3.0 # warmup epochs (fractions ok)
11 | warmup_momentum: 0.8 # warmup initial momentum
12 | warmup_bias_lr: 0.1 # warmup initial bias lr
13 | box: 0.05 # box loss gain
14 | cls: 0.5 # cls loss gain
15 | cls_pw: 1.0 # cls BCELoss positive_weight
16 | obj: 1.0 # obj loss gain (scale with pixels)
17 | obj_pw: 1.0 # obj BCELoss positive_weight
18 | iou_t: 0.20 # IoU training threshold
19 | anchor_t: 4.0 # anchor-multiple threshold
20 | # anchors: 3 # anchors per output layer (0 to ignore)
21 | fl_gamma: 0.0 # focal loss gamma (efficientDet default gamma=1.5)
22 | hsv_h: 0.015 # image HSV-Hue augmentation (fraction)
23 | hsv_s: 0.7 # image HSV-Saturation augmentation (fraction)
24 | hsv_v: 0.4 # image HSV-Value augmentation (fraction)
25 | degrees: 0.0 # image rotation (+/- deg)
26 | translate: 0.1 # image translation (+/- fraction)
27 | scale: 0.5 # image scale (+/- gain)
28 | shear: 0.0 # image shear (+/- deg)
29 | perspective: 0.0 # image perspective (+/- fraction), range 0-0.001
30 | flipud: 0.0 # image flip up-down (probability)
31 | fliplr: 0.5 # image flip left-right (probability)
32 | mosaic: 1.0 # image mosaic (probability)
33 | mixup: 0.0 # image mixup (probability)
34 | copy_paste: 0.0 # segment copy-paste (probability)
35 |
--------------------------------------------------------------------------------
/data/hyps/hyp.scratch-med.yaml:
--------------------------------------------------------------------------------
1 | # YOLOv5 🚀 by Ultralytics, GPL-3.0 license
2 | # Hyperparameters for medium-augmentation COCO training from scratch
3 | # python train.py --batch 32 --cfg yolov5m6.yaml --weights '' --data coco.yaml --img 1280 --epochs 300
4 | # See tutorials for hyperparameter evolution https://github.com/ultralytics/yolov5#tutorials
5 |
6 | lr0: 0.01 # initial learning rate (SGD=1E-2, Adam=1E-3)
7 | lrf: 0.1 # final OneCycleLR learning rate (lr0 * lrf)
8 | momentum: 0.937 # SGD momentum/Adam beta1
9 | weight_decay: 0.0005 # optimizer weight decay 5e-4
10 | warmup_epochs: 3.0 # warmup epochs (fractions ok)
11 | warmup_momentum: 0.8 # warmup initial momentum
12 | warmup_bias_lr: 0.1 # warmup initial bias lr
13 | box: 0.05 # box loss gain
14 | cls: 0.3 # cls loss gain
15 | cls_pw: 1.0 # cls BCELoss positive_weight
16 | obj: 0.7 # obj loss gain (scale with pixels)
17 | obj_pw: 1.0 # obj BCELoss positive_weight
18 | iou_t: 0.20 # IoU training threshold
19 | anchor_t: 4.0 # anchor-multiple threshold
20 | # anchors: 3 # anchors per output layer (0 to ignore)
21 | fl_gamma: 0.0 # focal loss gamma (efficientDet default gamma=1.5)
22 | hsv_h: 0.015 # image HSV-Hue augmentation (fraction)
23 | hsv_s: 0.7 # image HSV-Saturation augmentation (fraction)
24 | hsv_v: 0.4 # image HSV-Value augmentation (fraction)
25 | degrees: 0.0 # image rotation (+/- deg)
26 | translate: 0.1 # image translation (+/- fraction)
27 | scale: 0.9 # image scale (+/- gain)
28 | shear: 0.0 # image shear (+/- deg)
29 | perspective: 0.0 # image perspective (+/- fraction), range 0-0.001
30 | flipud: 0.0 # image flip up-down (probability)
31 | fliplr: 0.5 # image flip left-right (probability)
32 | mosaic: 1.0 # image mosaic (probability)
33 | mixup: 0.1 # image mixup (probability)
34 | copy_paste: 0.0 # segment copy-paste (probability)
35 |
--------------------------------------------------------------------------------
/data/scripts/get_coco.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # YOLOv5 🚀 by Ultralytics, GPL-3.0 license
3 | # Download COCO 2017 dataset http://cocodataset.org
4 | # Example usage: bash data/scripts/get_coco.sh
5 | # parent
6 | # ├── yolov5
7 | # └── datasets
8 | # └── coco ← downloads here
9 |
10 | # Arguments (optional) Usage: bash data/scripts/get_coco.sh --train --val --test --segments
11 | if [ "$#" -gt 0 ]; then
12 | for opt in "$@"; do
13 | case "${opt}" in
14 | --train) train=true ;;
15 | --val) val=true ;;
16 | --test) test=true ;;
17 | --segments) segments=true ;;
18 | esac
19 | done
20 | else
21 | train=true
22 | val=true
23 | test=false
24 | segments=false
25 | fi
26 |
27 | # Download/unzip labels
28 | d='../datasets' # unzip directory
29 | url=https://github.com/ultralytics/yolov5/releases/download/v1.0/
30 | if [ "$segments" == "true" ]; then
31 | f='coco2017labels-segments.zip' # 168 MB
32 | else
33 | f='coco2017labels.zip' # 168 MB
34 | fi
35 | echo 'Downloading' $url$f ' ...'
36 | curl -L $url$f -o $f -# && unzip -q $f -d $d && rm $f &
37 |
38 | # Download/unzip images
39 | d='../datasets/coco/images' # unzip directory
40 | url=http://images.cocodataset.org/zips/
41 | if [ "$train" == "true" ]; then
42 | f='train2017.zip' # 19G, 118k images
43 | echo 'Downloading' $url$f '...'
44 | curl -L $url$f -o $f -# && unzip -q $f -d $d && rm $f &
45 | fi
46 | if [ "$val" == "true" ]; then
47 | f='val2017.zip' # 1G, 5k images
48 | echo 'Downloading' $url$f '...'
49 | curl -L $url$f -o $f -# && unzip -q $f -d $d && rm $f &
50 | fi
51 | if [ "$test" == "true" ]; then
52 | f='test2017.zip' # 7G, 41k images (optional)
53 | echo 'Downloading' $url$f '...'
54 | curl -L $url$f -o $f -# && unzip -q $f -d $d && rm $f &
55 | fi
56 | wait # finish background tasks
57 |
--------------------------------------------------------------------------------
/data/scripts/get_imagenet.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # YOLOv5 🚀 by Ultralytics, GPL-3.0 license
3 | # Download ILSVRC2012 ImageNet dataset https://image-net.org
4 | # Example usage: bash data/scripts/get_imagenet.sh
5 | # parent
6 | # ├── yolov5
7 | # └── datasets
8 | # └── imagenet ← downloads here
9 |
10 | # Arguments (optional) Usage: bash data/scripts/get_imagenet.sh --train --val
11 | if [ "$#" -gt 0 ]; then
12 | for opt in "$@"; do
13 | case "${opt}" in
14 | --train) train=true ;;
15 | --val) val=true ;;
16 | esac
17 | done
18 | else
19 | train=true
20 | val=true
21 | fi
22 |
23 | # Make dir
24 | d='../datasets/imagenet' # unzip directory
25 | mkdir -p $d && cd $d
26 |
27 | # Download/unzip train
28 | if [ "$train" == "true" ]; then
29 | wget https://image-net.org/data/ILSVRC/2012/ILSVRC2012_img_train.tar # download 138G, 1281167 images
30 | mkdir train && mv ILSVRC2012_img_train.tar train/ && cd train
31 | tar -xf ILSVRC2012_img_train.tar && rm -f ILSVRC2012_img_train.tar
32 | find . -name "*.tar" | while read NAME; do
33 | mkdir -p "${NAME%.tar}"
34 | tar -xf "${NAME}" -C "${NAME%.tar}"
35 | rm -f "${NAME}"
36 | done
37 | cd ..
38 | fi
39 |
40 | # Download/unzip val
41 | if [ "$val" == "true" ]; then
42 | wget https://image-net.org/data/ILSVRC/2012/ILSVRC2012_img_val.tar # download 6.3G, 50000 images
43 | mkdir val && mv ILSVRC2012_img_val.tar val/ && cd val && tar -xf ILSVRC2012_img_val.tar
44 | wget -qO- https://raw.githubusercontent.com/soumith/imagenetloader.torch/master/valprep.sh | bash # move into subdirs
45 | fi
46 |
47 | # Delete corrupted image (optional: PNG under JPEG name that may cause dataloaders to fail)
48 | # rm train/n04266014/n04266014_10835.JPEG
49 |
50 | # TFRecords (optional)
51 | # wget https://raw.githubusercontent.com/tensorflow/models/master/research/slim/datasets/imagenet_lsvrc_2015_synsets.txt
52 |
--------------------------------------------------------------------------------
/detect.py:
--------------------------------------------------------------------------------
1 | # YOLOv5 🚀 by Ultralytics, GPL-3.0 license
2 | """
3 | Run YOLOv5 detection inference on images, videos, directories, globs, YouTube, webcam, streams, etc.
4 |
5 | Usage - sources:
6 | $ python 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 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 platform
30 | import sys
31 | from pathlib import Path
32 |
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.dataloaders import IMG_FORMATS, VID_FORMATS, LoadImages, LoadStreams
44 | from utils.general import (LOGGER, Profile, check_file, check_img_size, check_imshow, check_requirements, colorstr, cv2,
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, smart_inference_mode
48 |
49 |
50 | @smart_inference_mode()
51 | def run(
52 | 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, fp16=half)
94 | stride, names, pt = model.stride, model.names, model.pt
95 | imgsz = check_img_size(imgsz, s=stride) # check image size
96 |
97 | # Dataloader
98 | if webcam:
99 | view_img = check_imshow()
100 | cudnn.benchmark = True # set True to speed up constant image size inference
101 | dataset = LoadStreams(source, img_size=imgsz, stride=stride, auto=pt)
102 | bs = len(dataset) # batch_size
103 | else:
104 | dataset = LoadImages(source, img_size=imgsz, stride=stride, auto=pt)
105 | bs = 1 # batch_size
106 | vid_path, vid_writer = [None] * bs, [None] * bs
107 |
108 | # Run inference
109 | model.warmup(imgsz=(1 if pt else bs, 3, *imgsz)) # warmup
110 | seen, windows, dt = 0, [], (Profile(), Profile(), Profile())
111 | for path, im, im0s, vid_cap, s in dataset:
112 | with dt[0]:
113 | im = torch.from_numpy(im).to(device)
114 | im = im.half() if model.fp16 else im.float() # uint8 to fp16/32
115 | im /= 255 # 0 - 255 to 0.0 - 1.0
116 | if len(im.shape) == 3:
117 | im = im[None] # expand for batch dim
118 |
119 | # Inference
120 | with dt[1]:
121 | visualize = increment_path(save_dir / Path(path).stem, mkdir=True) if visualize else False
122 | pred = model(im, augment=augment, visualize=visualize)
123 |
124 | # NMS
125 | with dt[2]:
126 | pred = non_max_suppression(pred, conf_thres, iou_thres, classes, agnostic_nms, max_det=max_det)
127 |
128 | # Second-stage classifier (optional)
129 | # pred = utils.general.apply_classifier(pred, classifier_model, im, im0s)
130 |
131 | # Process predictions
132 | for i, det in enumerate(pred): # per image
133 | seen += 1
134 | if webcam: # batch_size >= 1
135 | p, im0, frame = path[i], im0s[i].copy(), dataset.count
136 | s += f'{i}: '
137 | else:
138 | p, im0, frame = path, im0s.copy(), getattr(dataset, 'frame', 0)
139 |
140 | p = Path(p) # to Path
141 | save_path = str(save_dir / p.name) # im.jpg
142 | txt_path = str(save_dir / 'labels' / p.stem) + ('' if dataset.mode == 'image' else f'_{frame}') # im.txt
143 | s += '%gx%g ' % im.shape[2:] # print string
144 | gn = torch.tensor(im0.shape)[[1, 0, 1, 0]] # normalization gain whwh
145 | imc = im0.copy() if save_crop else im0 # for save_crop
146 | annotator = Annotator(im0, line_width=line_thickness, example=str(names))
147 | if len(det):
148 | # Rescale boxes from img_size to im0 size
149 | det[:, :4] = scale_coords(im.shape[2:], det[:, :4], im0.shape).round()
150 |
151 | # Print results
152 | for c in det[:, 5].unique():
153 | n = (det[:, 5] == c).sum() # detections per class
154 | s += f"{n} {names[int(c)]}{'s' * (n > 1)}, " # add to string
155 |
156 | # Write results
157 | for *xyxy, conf, cls in reversed(det):
158 | if save_txt: # Write to file
159 | xywh = (xyxy2xywh(torch.tensor(xyxy).view(1, 4)) / gn).view(-1).tolist() # normalized xywh
160 | line = (cls, *xywh, conf) if save_conf else (cls, *xywh) # label format
161 | with open(f'{txt_path}.txt', 'a') as f:
162 | f.write(('%g ' * len(line)).rstrip() % line + '\n')
163 |
164 | if save_img or save_crop or view_img: # Add bbox to image
165 | c = int(cls) # integer class
166 | label = None if hide_labels else (names[c] if hide_conf else f'{names[c]} {conf:.2f}')
167 | annotator.box_label(xyxy, label, color=colors(c, True))
168 | if save_crop:
169 | save_one_box(xyxy, imc, file=save_dir / 'crops' / names[c] / f'{p.stem}.jpg', BGR=True)
170 |
171 | # Stream results
172 | im0 = annotator.result()
173 | if view_img:
174 | if platform.system() == 'Linux' and p not in windows:
175 | windows.append(p)
176 | cv2.namedWindow(str(p), cv2.WINDOW_NORMAL | cv2.WINDOW_KEEPRATIO) # allow window resize (Linux)
177 | cv2.resizeWindow(str(p), im0.shape[1], im0.shape[0])
178 | cv2.imshow(str(p), im0)
179 | cv2.waitKey(1) # 1 millisecond
180 |
181 | # Save results (image with detections)
182 | if save_img:
183 | if dataset.mode == 'image':
184 | cv2.imwrite(save_path, im0)
185 | else: # 'video' or 'stream'
186 | if vid_path[i] != save_path: # new video
187 | vid_path[i] = save_path
188 | if isinstance(vid_writer[i], cv2.VideoWriter):
189 | vid_writer[i].release() # release previous video writer
190 | if vid_cap: # video
191 | fps = vid_cap.get(cv2.CAP_PROP_FPS)
192 | w = int(vid_cap.get(cv2.CAP_PROP_FRAME_WIDTH))
193 | h = int(vid_cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
194 | else: # stream
195 | fps, w, h = 30, im0.shape[1], im0.shape[0]
196 | save_path = str(Path(save_path).with_suffix('.mp4')) # force *.mp4 suffix on results videos
197 | vid_writer[i] = cv2.VideoWriter(save_path, cv2.VideoWriter_fourcc(*'mp4v'), fps, (w, h))
198 | vid_writer[i].write(im0)
199 |
200 | # Print time (inference-only)
201 | LOGGER.info(f"{s}{'' if len(det) else '(no detections), '}{dt[1].dt * 1E3:.1f}ms")
202 |
203 | # Print results
204 | t = tuple(x.t / seen * 1E3 for x in dt) # speeds per image
205 | LOGGER.info(f'Speed: %.1fms pre-process, %.1fms inference, %.1fms NMS per image at shape {(1, 3, *imgsz)}' % t)
206 | if save_txt or save_img:
207 | s = f"\n{len(list(save_dir.glob('labels/*.txt')))} labels saved to {save_dir / 'labels'}" if save_txt else ''
208 | LOGGER.info(f"Results saved to {colorstr('bold', save_dir)}{s}")
209 | if update:
210 | strip_optimizer(weights[0]) # update model (to fix SourceChangeWarning)
211 |
212 |
213 | def parse_opt():
214 | parser = argparse.ArgumentParser()
215 | parser.add_argument('--weights', nargs='+', type=str, default=ROOT / 'yolov5s.pt', help='model path(s)')
216 | parser.add_argument('--source', type=str, default=ROOT / 'data/images', help='file/dir/URL/glob, 0 for webcam')
217 | parser.add_argument('--data', type=str, default=ROOT / 'data/coco128.yaml', help='(optional) dataset.yaml path')
218 | parser.add_argument('--imgsz', '--img', '--img-size', nargs='+', type=int, default=[640], help='inference size h,w')
219 | parser.add_argument('--conf-thres', type=float, default=0.25, help='confidence threshold')
220 | parser.add_argument('--iou-thres', type=float, default=0.45, help='NMS IoU threshold')
221 | parser.add_argument('--max-det', type=int, default=1000, help='maximum detections per image')
222 | parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu')
223 | parser.add_argument('--view-img', action='store_true', help='show results')
224 | parser.add_argument('--save-txt', action='store_true', help='save results to *.txt')
225 | parser.add_argument('--save-conf', action='store_true', help='save confidences in --save-txt labels')
226 | parser.add_argument('--save-crop', action='store_true', help='save cropped prediction boxes')
227 | parser.add_argument('--nosave', action='store_true', help='do not save images/videos')
228 | parser.add_argument('--classes', nargs='+', type=int, help='filter by class: --classes 0, or --classes 0 2 3')
229 | parser.add_argument('--agnostic-nms', action='store_true', help='class-agnostic NMS')
230 | parser.add_argument('--augment', action='store_true', help='augmented inference')
231 | parser.add_argument('--visualize', action='store_true', help='visualize features')
232 | parser.add_argument('--update', action='store_true', help='update all models')
233 | parser.add_argument('--project', default=ROOT / 'runs/detect', help='save results to project/name')
234 | parser.add_argument('--name', default='exp', help='save results to project/name')
235 | parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment')
236 | parser.add_argument('--line-thickness', default=3, type=int, help='bounding box thickness (pixels)')
237 | parser.add_argument('--hide-labels', default=False, action='store_true', help='hide labels')
238 | parser.add_argument('--hide-conf', default=False, action='store_true', help='hide confidences')
239 | parser.add_argument('--half', action='store_true', help='use FP16 half-precision inference')
240 | parser.add_argument('--dnn', action='store_true', help='use OpenCV DNN for ONNX inference')
241 | opt = parser.parse_args()
242 | opt.imgsz *= 2 if len(opt.imgsz) == 1 else 1 # expand
243 | print_args(vars(opt))
244 | return opt
245 |
246 |
247 | def main(opt):
248 | check_requirements(exclude=('tensorboard', 'thop'))
249 | run(**vars(opt))
250 |
251 |
252 | if __name__ == "__main__":
253 | opt = parse_opt()
254 | main(opt)
255 |
--------------------------------------------------------------------------------
/figure/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MuhammadMoinFaisal/yolov7-segmentation-with-DeepSORT-Tracking/989fb3a9655ec5e263da760edc3c033045329fa3/figure/1.png
--------------------------------------------------------------------------------
/figure/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MuhammadMoinFaisal/yolov7-segmentation-with-DeepSORT-Tracking/989fb3a9655ec5e263da760edc3c033045329fa3/figure/2.png
--------------------------------------------------------------------------------
/figure/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MuhammadMoinFaisal/yolov7-segmentation-with-DeepSORT-Tracking/989fb3a9655ec5e263da760edc3c033045329fa3/figure/3.png
--------------------------------------------------------------------------------
/figure/Screenshot (350).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MuhammadMoinFaisal/yolov7-segmentation-with-DeepSORT-Tracking/989fb3a9655ec5e263da760edc3c033045329fa3/figure/Screenshot (350).png
--------------------------------------------------------------------------------
/figure/Screenshot (351).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MuhammadMoinFaisal/yolov7-segmentation-with-DeepSORT-Tracking/989fb3a9655ec5e263da760edc3c033045329fa3/figure/Screenshot (351).png
--------------------------------------------------------------------------------
/figure/Screenshot (352).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MuhammadMoinFaisal/yolov7-segmentation-with-DeepSORT-Tracking/989fb3a9655ec5e263da760edc3c033045329fa3/figure/Screenshot (352).png
--------------------------------------------------------------------------------
/figure/yolov7-seg-example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MuhammadMoinFaisal/yolov7-segmentation-with-DeepSORT-Tracking/989fb3a9655ec5e263da760edc3c033045329fa3/figure/yolov7-seg-example.png
--------------------------------------------------------------------------------
/hubconf.py:
--------------------------------------------------------------------------------
1 | # YOLOv5 🚀 by Ultralytics, GPL-3.0 license
2 | """
3 | PyTorch Hub models https://pytorch.org/hub/ultralytics_yolov5
4 |
5 | Usage:
6 | import torch
7 | model = torch.hub.load('ultralytics/yolov5', 'yolov5s')
8 | model = torch.hub.load('ultralytics/yolov5:master', 'custom', 'path/to/yolov5s.onnx') # custom model from branch
9 | """
10 |
11 | import torch
12 |
13 |
14 | def _create(name, pretrained=True, channels=3, classes=80, autoshape=True, verbose=True, device=None):
15 | """Creates or loads a YOLOv5 model
16 |
17 | Arguments:
18 | name (str): model name 'yolov5s' or path 'path/to/best.pt'
19 | pretrained (bool): load pretrained weights into the model
20 | channels (int): number of input channels
21 | classes (int): number of model classes
22 | autoshape (bool): apply YOLOv5 .autoshape() wrapper to model
23 | verbose (bool): print all information to screen
24 | device (str, torch.device, None): device to use for model parameters
25 |
26 | Returns:
27 | YOLOv5 model
28 | """
29 | from pathlib import Path
30 |
31 | from models.common import AutoShape, DetectMultiBackend
32 | from models.experimental import attempt_load
33 | from models.yolo import ClassificationModel, DetectionModel
34 | from utils.downloads import attempt_download
35 | from utils.general import LOGGER, check_requirements, intersect_dicts, logging
36 | from utils.torch_utils import select_device
37 |
38 | if not verbose:
39 | LOGGER.setLevel(logging.WARNING)
40 | check_requirements(exclude=('tensorboard', 'thop', 'opencv-python'))
41 | name = Path(name)
42 | path = name.with_suffix('.pt') if name.suffix == '' and not name.is_dir() else name # checkpoint path
43 | try:
44 | device = select_device(device)
45 | if pretrained and channels == 3 and classes == 80:
46 | try:
47 | model = DetectMultiBackend(path, device=device, fuse=autoshape) # detection model
48 | if autoshape:
49 | if model.pt and isinstance(model.model, ClassificationModel):
50 | LOGGER.warning('WARNING: YOLOv5 v6.2 ClassificationModel is not yet AutoShape compatible. '
51 | 'You must pass torch tensors in BCHW to this model, i.e. shape(1,3,224,224).')
52 | else:
53 | model = AutoShape(model) # for file/URI/PIL/cv2/np inputs and NMS
54 | except Exception:
55 | model = attempt_load(path, device=device, fuse=False) # arbitrary model
56 | else:
57 | cfg = list((Path(__file__).parent / 'models').rglob(f'{path.stem}.yaml'))[0] # model.yaml path
58 | model = DetectionModel(cfg, channels, classes) # create model
59 | if pretrained:
60 | ckpt = torch.load(attempt_download(path), map_location=device) # load
61 | csd = ckpt['model'].float().state_dict() # checkpoint state_dict as FP32
62 | csd = intersect_dicts(csd, model.state_dict(), exclude=['anchors']) # intersect
63 | model.load_state_dict(csd, strict=False) # load
64 | if len(ckpt['model'].names) == classes:
65 | model.names = ckpt['model'].names # set class names attribute
66 | if not verbose:
67 | LOGGER.setLevel(logging.INFO) # reset to default
68 | return model.to(device)
69 |
70 | except Exception as e:
71 | help_url = 'https://github.com/ultralytics/yolov5/issues/36'
72 | s = f'{e}. Cache may be out of date, try `force_reload=True` or see {help_url} for help.'
73 | raise Exception(s) from e
74 |
75 |
76 | def custom(path='path/to/model.pt', autoshape=True, _verbose=True, device=None):
77 | # YOLOv5 custom or local model
78 | return _create(path, autoshape=autoshape, verbose=_verbose, device=device)
79 |
80 |
81 | def yolov5n(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None):
82 | # YOLOv5-nano model https://github.com/ultralytics/yolov5
83 | return _create('yolov5n', pretrained, channels, classes, autoshape, _verbose, device)
84 |
85 |
86 | def yolov5s(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None):
87 | # YOLOv5-small model https://github.com/ultralytics/yolov5
88 | return _create('yolov5s', pretrained, channels, classes, autoshape, _verbose, device)
89 |
90 |
91 | def yolov5m(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None):
92 | # YOLOv5-medium model https://github.com/ultralytics/yolov5
93 | return _create('yolov5m', pretrained, channels, classes, autoshape, _verbose, device)
94 |
95 |
96 | def yolov5l(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None):
97 | # YOLOv5-large model https://github.com/ultralytics/yolov5
98 | return _create('yolov5l', pretrained, channels, classes, autoshape, _verbose, device)
99 |
100 |
101 | def yolov5x(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None):
102 | # YOLOv5-xlarge model https://github.com/ultralytics/yolov5
103 | return _create('yolov5x', pretrained, channels, classes, autoshape, _verbose, device)
104 |
105 |
106 | def yolov5n6(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None):
107 | # YOLOv5-nano-P6 model https://github.com/ultralytics/yolov5
108 | return _create('yolov5n6', pretrained, channels, classes, autoshape, _verbose, device)
109 |
110 |
111 | def yolov5s6(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None):
112 | # YOLOv5-small-P6 model https://github.com/ultralytics/yolov5
113 | return _create('yolov5s6', pretrained, channels, classes, autoshape, _verbose, device)
114 |
115 |
116 | def yolov5m6(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None):
117 | # YOLOv5-medium-P6 model https://github.com/ultralytics/yolov5
118 | return _create('yolov5m6', pretrained, channels, classes, autoshape, _verbose, device)
119 |
120 |
121 | def yolov5l6(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None):
122 | # YOLOv5-large-P6 model https://github.com/ultralytics/yolov5
123 | return _create('yolov5l6', pretrained, channels, classes, autoshape, _verbose, device)
124 |
125 |
126 | def yolov5x6(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None):
127 | # YOLOv5-xlarge-P6 model https://github.com/ultralytics/yolov5
128 | return _create('yolov5x6', pretrained, channels, classes, autoshape, _verbose, device)
129 |
130 |
131 | if __name__ == '__main__':
132 | import argparse
133 | from pathlib import Path
134 |
135 | import numpy as np
136 | from PIL import Image
137 |
138 | from utils.general import cv2, print_args
139 |
140 | # Argparser
141 | parser = argparse.ArgumentParser()
142 | parser.add_argument('--model', type=str, default='yolov5s', help='model name')
143 | opt = parser.parse_args()
144 | print_args(vars(opt))
145 |
146 | # Model
147 | model = _create(name=opt.model, pretrained=True, channels=3, classes=80, autoshape=True, verbose=True)
148 | # model = custom(path='path/to/model.pt') # custom
149 |
150 | # Images
151 | imgs = [
152 | 'data/images/zidane.jpg', # filename
153 | Path('data/images/zidane.jpg'), # Path
154 | 'https://ultralytics.com/images/zidane.jpg', # URI
155 | cv2.imread('data/images/bus.jpg')[:, :, ::-1], # OpenCV
156 | Image.open('data/images/bus.jpg'), # PIL
157 | np.zeros((320, 640, 3))] # numpy
158 |
159 | # Inference
160 | results = model(imgs, size=320) # batched inference
161 |
162 | # Results
163 | results.print()
164 | results.save()
165 |
--------------------------------------------------------------------------------
/models/__init__.py:
--------------------------------------------------------------------------------
1 | # init
--------------------------------------------------------------------------------
/models/__pycache__/__init__.cpython-310.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MuhammadMoinFaisal/yolov7-segmentation-with-DeepSORT-Tracking/989fb3a9655ec5e263da760edc3c033045329fa3/models/__pycache__/__init__.cpython-310.pyc
--------------------------------------------------------------------------------
/models/__pycache__/common.cpython-310.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MuhammadMoinFaisal/yolov7-segmentation-with-DeepSORT-Tracking/989fb3a9655ec5e263da760edc3c033045329fa3/models/__pycache__/common.cpython-310.pyc
--------------------------------------------------------------------------------
/models/__pycache__/experimental.cpython-310.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MuhammadMoinFaisal/yolov7-segmentation-with-DeepSORT-Tracking/989fb3a9655ec5e263da760edc3c033045329fa3/models/__pycache__/experimental.cpython-310.pyc
--------------------------------------------------------------------------------
/models/__pycache__/yolo.cpython-310.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MuhammadMoinFaisal/yolov7-segmentation-with-DeepSORT-Tracking/989fb3a9655ec5e263da760edc3c033045329fa3/models/__pycache__/yolo.cpython-310.pyc
--------------------------------------------------------------------------------
/models/experimental.py:
--------------------------------------------------------------------------------
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 utils.downloads import attempt_download
12 |
13 |
14 | class Sum(nn.Module):
15 | # Weighted sum of 2 or more layers https://arxiv.org/abs/1911.09070
16 | def __init__(self, n, weight=False): # n: number of inputs
17 | super().__init__()
18 | self.weight = weight # apply weights boolean
19 | self.iter = range(n - 1) # iter object
20 | if weight:
21 | self.w = nn.Parameter(-torch.arange(1.0, n) / 2, requires_grad=True) # layer weights
22 |
23 | def forward(self, x):
24 | y = x[0] # no weight
25 | if self.weight:
26 | w = torch.sigmoid(self.w) * 2
27 | for i in self.iter:
28 | y = y + x[i + 1] * w[i]
29 | else:
30 | for i in self.iter:
31 | y = y + x[i + 1]
32 | return y
33 |
34 |
35 | class MixConv2d(nn.Module):
36 | # Mixed Depth-wise Conv https://arxiv.org/abs/1907.09595
37 | def __init__(self, c1, c2, k=(1, 3), s=1, equal_ch=True): # ch_in, ch_out, kernel, stride, ch_strategy
38 | super().__init__()
39 | n = len(k) # number of convolutions
40 | if equal_ch: # equal c_ per group
41 | i = torch.linspace(0, n - 1E-6, c2).floor() # c2 indices
42 | c_ = [(i == g).sum() for g in range(n)] # intermediate channels
43 | else: # equal weight.numel() per group
44 | b = [c2] + [0] * n
45 | a = np.eye(n + 1, n, k=-1)
46 | a -= np.roll(a, 1, axis=1)
47 | a *= np.array(k) ** 2
48 | a[0] = 1
49 | c_ = np.linalg.lstsq(a, b, rcond=None)[0].round() # solve for equal weight indices, ax = b
50 |
51 | self.m = nn.ModuleList([
52 | nn.Conv2d(c1, int(c_), k, s, k // 2, groups=math.gcd(c1, int(c_)), bias=False) for k, c_ in zip(k, c_)])
53 | self.bn = nn.BatchNorm2d(c2)
54 | self.act = nn.SiLU()
55 |
56 | def forward(self, x):
57 | return self.act(self.bn(torch.cat([m(x) for m in self.m], 1)))
58 |
59 |
60 | class Ensemble(nn.ModuleList):
61 | # Ensemble of models
62 | def __init__(self):
63 | super().__init__()
64 |
65 | def forward(self, x, augment=False, profile=False, visualize=False):
66 | y = [module(x, augment, profile, visualize)[0] for module in self]
67 | # y = torch.stack(y).max(0)[0] # max ensemble
68 | # y = torch.stack(y).mean(0) # mean ensemble
69 | y = torch.cat(y, 1) # nms ensemble
70 | return y, None # inference, train output
71 |
72 |
73 | def attempt_load(weights, device=None, inplace=True, fuse=True):
74 | # Loads an ensemble of models weights=[a,b,c] or a single model weights=[a] or weights=a
75 | from models.yolo import Detect, Model
76 |
77 | model = Ensemble()
78 | for w in weights if isinstance(weights, list) else [weights]:
79 | ckpt = torch.load(attempt_download(w), map_location='cpu') # load
80 | ckpt = (ckpt.get('ema') or ckpt['model']).to(device).float() # FP32 model
81 |
82 | # Model compatibility updates
83 | if not hasattr(ckpt, 'stride'):
84 | ckpt.stride = torch.tensor([32.])
85 | if hasattr(ckpt, 'names') and isinstance(ckpt.names, (list, tuple)):
86 | ckpt.names = dict(enumerate(ckpt.names)) # convert to dict
87 |
88 | model.append(ckpt.fuse().eval() if fuse and hasattr(ckpt, 'fuse') else ckpt.eval()) # model in eval mode
89 |
90 | # Module compatibility updates
91 | for m in model.modules():
92 | t = type(m)
93 | if t in (nn.Hardswish, nn.LeakyReLU, nn.ReLU, nn.ReLU6, nn.SiLU, Detect, Model):
94 | m.inplace = inplace # torch 1.7.0 compatibility
95 | if t is Detect and not isinstance(m.anchor_grid, list):
96 | delattr(m, 'anchor_grid')
97 | setattr(m, 'anchor_grid', [torch.zeros(1)] * m.nl)
98 | elif t is nn.Upsample and not hasattr(m, 'recompute_scale_factor'):
99 | m.recompute_scale_factor = None # torch 1.11.0 compatibility
100 |
101 | # Return model
102 | if len(model) == 1:
103 | return model[-1]
104 |
105 | # Return detection ensemble
106 | print(f'Ensemble created with {weights}\n')
107 | for k in 'names', 'nc', 'yaml':
108 | setattr(model, k, getattr(model[0], k))
109 | model.stride = model[torch.argmax(torch.tensor([m.stride.max() for m in model])).int()].stride # max stride
110 | assert all(model[0].nc == m.nc for m in model), f'Models have different class counts: {[m.nc for m in model]}'
111 | return model
112 |
--------------------------------------------------------------------------------
/models/hub/yolov3-spp.yaml:
--------------------------------------------------------------------------------
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 | ]
52 |
--------------------------------------------------------------------------------
/models/hub/yolov3-tiny.yaml:
--------------------------------------------------------------------------------
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 | ]
42 |
--------------------------------------------------------------------------------
/models/hub/yolov3.yaml:
--------------------------------------------------------------------------------
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 | ]
52 |
--------------------------------------------------------------------------------
/models/segment/yolov7-seg.yaml:
--------------------------------------------------------------------------------
1 | # YOLOv7
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 | - [12,16, 19,36, 40,28] # P3/8
9 | - [36,75, 76,55, 72,146] # P4/16
10 | - [142,110, 192,243, 459,401] # P5/32
11 |
12 | # YOLOv7 backbone
13 | backbone:
14 | # [from, number, module, args]
15 | [[-1, 1, Conv, [32, 3, 1]], # 0
16 |
17 | [-1, 1, Conv, [64, 3, 2]], # 1-P1/2
18 | [-1, 1, Conv, [64, 3, 1]],
19 |
20 | [-1, 1, Conv, [128, 3, 2]], # 3-P2/4
21 | [-1, 1, Conv, [64, 1, 1]],
22 | [-2, 1, Conv, [64, 1, 1]],
23 | [-1, 1, Conv, [64, 3, 1]],
24 | [-1, 1, Conv, [64, 3, 1]],
25 | [-1, 1, Conv, [64, 3, 1]],
26 | [-1, 1, Conv, [64, 3, 1]],
27 | [[-1, -3, -5, -6], 1, Concat, [1]],
28 | [-1, 1, Conv, [256, 1, 1]], # 11
29 |
30 | [-1, 1, MP, []],
31 | [-1, 1, Conv, [128, 1, 1]],
32 | [-3, 1, Conv, [128, 1, 1]],
33 | [-1, 1, Conv, [128, 3, 2]],
34 | [[-1, -3], 1, Concat, [1]], # 16-P3/8
35 | [-1, 1, Conv, [128, 1, 1]],
36 | [-2, 1, Conv, [128, 1, 1]],
37 | [-1, 1, Conv, [128, 3, 1]],
38 | [-1, 1, Conv, [128, 3, 1]],
39 | [-1, 1, Conv, [128, 3, 1]],
40 | [-1, 1, Conv, [128, 3, 1]],
41 | [[-1, -3, -5, -6], 1, Concat, [1]],
42 | [-1, 1, Conv, [512, 1, 1]], # 24
43 |
44 | [-1, 1, MP, []],
45 | [-1, 1, Conv, [256, 1, 1]],
46 | [-3, 1, Conv, [256, 1, 1]],
47 | [-1, 1, Conv, [256, 3, 2]],
48 | [[-1, -3], 1, Concat, [1]], # 29-P4/16
49 | [-1, 1, Conv, [256, 1, 1]],
50 | [-2, 1, Conv, [256, 1, 1]],
51 | [-1, 1, Conv, [256, 3, 1]],
52 | [-1, 1, Conv, [256, 3, 1]],
53 | [-1, 1, Conv, [256, 3, 1]],
54 | [-1, 1, Conv, [256, 3, 1]],
55 | [[-1, -3, -5, -6], 1, Concat, [1]],
56 | [-1, 1, Conv, [1024, 1, 1]], # 37
57 |
58 | [-1, 1, MP, []],
59 | [-1, 1, Conv, [512, 1, 1]],
60 | [-3, 1, Conv, [512, 1, 1]],
61 | [-1, 1, Conv, [512, 3, 2]],
62 | [[-1, -3], 1, Concat, [1]], # 42-P5/32
63 | [-1, 1, Conv, [256, 1, 1]],
64 | [-2, 1, Conv, [256, 1, 1]],
65 | [-1, 1, Conv, [256, 3, 1]],
66 | [-1, 1, Conv, [256, 3, 1]],
67 | [-1, 1, Conv, [256, 3, 1]],
68 | [-1, 1, Conv, [256, 3, 1]],
69 | [[-1, -3, -5, -6], 1, Concat, [1]],
70 | [-1, 1, Conv, [1024, 1, 1]], # 50
71 | ]
72 |
73 | # yolov7 head
74 | head:
75 | [[-1, 1, SPPCSPC, [512]], # 51
76 |
77 | [-1, 1, Conv, [256, 1, 1]],
78 | [-1, 1, nn.Upsample, [None, 2, 'nearest']],
79 | [37, 1, Conv, [256, 1, 1]], # route backbone P4
80 | [[-1, -2], 1, Concat, [1]],
81 |
82 | [-1, 1, Conv, [256, 1, 1]],
83 | [-2, 1, Conv, [256, 1, 1]],
84 | [-1, 1, Conv, [128, 3, 1]],
85 | [-1, 1, Conv, [128, 3, 1]],
86 | [-1, 1, Conv, [128, 3, 1]],
87 | [-1, 1, Conv, [128, 3, 1]],
88 | [[-1, -2, -3, -4, -5, -6], 1, Concat, [1]],
89 | [-1, 1, Conv, [256, 1, 1]], # 63
90 |
91 | [-1, 1, Conv, [128, 1, 1]],
92 | [-1, 1, nn.Upsample, [None, 2, 'nearest']],
93 | [24, 1, Conv, [128, 1, 1]], # route backbone P3
94 | [[-1, -2], 1, Concat, [1]],
95 |
96 | [-1, 1, Conv, [128, 1, 1]],
97 | [-2, 1, Conv, [128, 1, 1]],
98 | [-1, 1, Conv, [64, 3, 1]],
99 | [-1, 1, Conv, [64, 3, 1]],
100 | [-1, 1, Conv, [64, 3, 1]],
101 | [-1, 1, Conv, [64, 3, 1]],
102 | [[-1, -2, -3, -4, -5, -6], 1, Concat, [1]],
103 | [-1, 1, Conv, [128, 1, 1]], # 75
104 |
105 | [-1, 1, MP, []],
106 | [-1, 1, Conv, [128, 1, 1]],
107 | [-3, 1, Conv, [128, 1, 1]],
108 | [-1, 1, Conv, [128, 3, 2]],
109 | [[-1, -3, 63], 1, Concat, [1]],
110 |
111 | [-1, 1, Conv, [256, 1, 1]],
112 | [-2, 1, Conv, [256, 1, 1]],
113 | [-1, 1, Conv, [128, 3, 1]],
114 | [-1, 1, Conv, [128, 3, 1]],
115 | [-1, 1, Conv, [128, 3, 1]],
116 | [-1, 1, Conv, [128, 3, 1]],
117 | [[-1, -2, -3, -4, -5, -6], 1, Concat, [1]],
118 | [-1, 1, Conv, [256, 1, 1]], # 88
119 |
120 | [-1, 1, MP, []],
121 | [-1, 1, Conv, [256, 1, 1]],
122 | [-3, 1, Conv, [256, 1, 1]],
123 | [-1, 1, Conv, [256, 3, 2]],
124 | [[-1, -3, 51], 1, Concat, [1]],
125 |
126 | [-1, 1, Conv, [512, 1, 1]],
127 | [-2, 1, Conv, [512, 1, 1]],
128 | [-1, 1, Conv, [256, 3, 1]],
129 | [-1, 1, Conv, [256, 3, 1]],
130 | [-1, 1, Conv, [256, 3, 1]],
131 | [-1, 1, Conv, [256, 3, 1]],
132 | [[-1, -2, -3, -4, -5, -6], 1, Concat, [1]],
133 | [-1, 1, Conv, [512, 1, 1]], # 101
134 |
135 | [75, 1, Conv, [256, 3, 1]],
136 | [88, 1, Conv, [512, 3, 1]],
137 | [101, 1, Conv, [1024, 3, 1]],
138 |
139 | [[102, 103, 104], 1, ISegment, [nc, anchors, 32, 256]], # Detect(P3, P4, P5)
140 | ]
141 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | # YOLOv5 requirements
2 | # Usage: pip install -r requirements.txt
3 |
4 | # Base ----------------------------------------
5 | matplotlib>=3.2.2
6 | numpy>=1.18.5
7 | opencv-python>=4.1.1
8 | Pillow>=7.1.2
9 | PyYAML>=5.3.1
10 | requests>=2.23.0
11 | scipy>=1.4.1
12 | torch>=1.7.0
13 | torchvision>=0.8.1
14 | tqdm>=4.64.0
15 | protobuf<=3.20.1 # https://github.com/ultralytics/yolov5/issues/8012
16 |
17 | # Logging -------------------------------------
18 | tensorboard>=2.4.1
19 | # wandb
20 | # clearml
21 |
22 | # Plotting ------------------------------------
23 | pandas>=1.1.4
24 | seaborn>=0.11.0
25 |
26 | # Export --------------------------------------
27 | # coremltools>=5.2 # CoreML export
28 | # onnx>=1.9.0 # ONNX export
29 | # onnx-simplifier>=0.4.1 # ONNX simplifier
30 | # nvidia-pyindex # TensorRT export
31 | # nvidia-tensorrt # TensorRT export
32 | # scikit-learn==0.19.2 # CoreML quantization
33 | # tensorflow>=2.4.1 # TFLite export (or tensorflow-cpu, tensorflow-aarch64)
34 | # tensorflowjs>=3.9.0 # TF.js export
35 | # openvino-dev # OpenVINO export
36 |
37 | # Extras --------------------------------------
38 | ipython # interactive notebook
39 | psutil # system utilization
40 | thop>=0.1.1 # FLOPs computation
41 | # albumentations>=1.0.3
42 | # pycocotools>=2.0 # COCO mAP
43 | # roboflow
44 |
--------------------------------------------------------------------------------
/runs/predict-seg/exp/Demo.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MuhammadMoinFaisal/yolov7-segmentation-with-DeepSORT-Tracking/989fb3a9655ec5e263da760edc3c033045329fa3/runs/predict-seg/exp/Demo.mp4
--------------------------------------------------------------------------------
/setup.cfg:
--------------------------------------------------------------------------------
1 | # Project-wide configuration file, can be used for package metadata and other toll configurations
2 | # Example usage: global configuration for PEP8 (via flake8) setting or default pytest arguments
3 | # Local usage: pip install pre-commit, pre-commit run --all-files
4 |
5 | [metadata]
6 | license_file = LICENSE
7 | description_file = README.md
8 |
9 |
10 | [tool:pytest]
11 | norecursedirs =
12 | .git
13 | dist
14 | build
15 | addopts =
16 | --doctest-modules
17 | --durations=25
18 | --color=yes
19 |
20 |
21 | [flake8]
22 | max-line-length = 120
23 | exclude = .tox,*.egg,build,temp
24 | select = E,W,F
25 | doctests = True
26 | verbose = 2
27 | # https://pep8.readthedocs.io/en/latest/intro.html#error-codes
28 | format = pylint
29 | # see: https://www.flake8rules.com/
30 | ignore =
31 | E731 # Do not assign a lambda expression, use a def
32 | F405 # name may be undefined, or defined from star imports: module
33 | E402 # module level import not at top of file
34 | F401 # module imported but unused
35 | W504 # line break after binary operator
36 | E127 # continuation line over-indented for visual indent
37 | W504 # line break after binary operator
38 | E231 # missing whitespace after ‘,’, ‘;’, or ‘:’
39 | E501 # line too long
40 | F403 # ‘from module import *’ used; unable to detect undefined names
41 |
42 |
43 | [isort]
44 | # https://pycqa.github.io/isort/docs/configuration/options.html
45 | line_length = 120
46 | # see: https://pycqa.github.io/isort/docs/configuration/multi_line_output_modes.html
47 | multi_line_output = 0
48 |
49 |
50 | [yapf]
51 | based_on_style = pep8
52 | spaces_before_comment = 2
53 | COLUMN_LIMIT = 120
54 | COALESCE_BRACKETS = True
55 | SPACES_AROUND_POWER_OPERATOR = True
56 | SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET = False
57 | SPLIT_BEFORE_CLOSING_BRACKET = False
58 | SPLIT_BEFORE_FIRST_ARGUMENT = False
59 | # EACH_DICT_ENTRY_ON_SEPARATE_LINE = False
60 |
--------------------------------------------------------------------------------
/utils/__init__.py:
--------------------------------------------------------------------------------
1 | # YOLOv5 🚀 by Ultralytics, GPL-3.0 license
2 | """
3 | utils/initialization
4 | """
5 |
6 | import contextlib
7 | import threading
8 |
9 |
10 | class TryExcept(contextlib.ContextDecorator):
11 | # YOLOv5 TryExcept class. Usage: @TryExcept() decorator or 'with TryExcept():' context manager
12 | def __init__(self, msg='default message here'):
13 | self.msg = msg
14 |
15 | def __enter__(self):
16 | pass
17 |
18 | def __exit__(self, exc_type, value, traceback):
19 | if value:
20 | print(f'{self.msg}: {value}')
21 | return True
22 |
23 |
24 | def threaded(func):
25 | # Multi-threads a target function and returns thread. Usage: @threaded decorator
26 | def wrapper(*args, **kwargs):
27 | thread = threading.Thread(target=func, args=args, kwargs=kwargs, daemon=True)
28 | thread.start()
29 | return thread
30 |
31 | return wrapper
32 |
33 |
34 | def notebook_init(verbose=True):
35 | # Check system software and hardware
36 | print('Checking setup...')
37 |
38 | import os
39 | import shutil
40 |
41 | from utils.general import check_requirements, emojis, is_colab
42 | from utils.torch_utils import select_device # imports
43 |
44 | check_requirements(('psutil', 'IPython'))
45 | import psutil
46 | from IPython import display # to display images and clear console output
47 |
48 | if is_colab():
49 | shutil.rmtree('/content/sample_data', ignore_errors=True) # remove colab /sample_data directory
50 |
51 | # System info
52 | if verbose:
53 | gb = 1 << 30 # bytes to GiB (1024 ** 3)
54 | ram = psutil.virtual_memory().total
55 | total, used, free = shutil.disk_usage("/")
56 | display.clear_output()
57 | s = f'({os.cpu_count()} CPUs, {ram / gb:.1f} GB RAM, {(total - free) / gb:.1f}/{total / gb:.1f} GB disk)'
58 | else:
59 | s = ''
60 |
61 | select_device(newline=False)
62 | print(emojis(f'Setup complete ✅ {s}'))
63 | return display
64 |
--------------------------------------------------------------------------------
/utils/__pycache__/__init__.cpython-310.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MuhammadMoinFaisal/yolov7-segmentation-with-DeepSORT-Tracking/989fb3a9655ec5e263da760edc3c033045329fa3/utils/__pycache__/__init__.cpython-310.pyc
--------------------------------------------------------------------------------
/utils/__pycache__/augmentations.cpython-310.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MuhammadMoinFaisal/yolov7-segmentation-with-DeepSORT-Tracking/989fb3a9655ec5e263da760edc3c033045329fa3/utils/__pycache__/augmentations.cpython-310.pyc
--------------------------------------------------------------------------------
/utils/__pycache__/autoanchor.cpython-310.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MuhammadMoinFaisal/yolov7-segmentation-with-DeepSORT-Tracking/989fb3a9655ec5e263da760edc3c033045329fa3/utils/__pycache__/autoanchor.cpython-310.pyc
--------------------------------------------------------------------------------
/utils/__pycache__/dataloaders.cpython-310.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MuhammadMoinFaisal/yolov7-segmentation-with-DeepSORT-Tracking/989fb3a9655ec5e263da760edc3c033045329fa3/utils/__pycache__/dataloaders.cpython-310.pyc
--------------------------------------------------------------------------------
/utils/__pycache__/downloads.cpython-310.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MuhammadMoinFaisal/yolov7-segmentation-with-DeepSORT-Tracking/989fb3a9655ec5e263da760edc3c033045329fa3/utils/__pycache__/downloads.cpython-310.pyc
--------------------------------------------------------------------------------
/utils/__pycache__/general.cpython-310.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MuhammadMoinFaisal/yolov7-segmentation-with-DeepSORT-Tracking/989fb3a9655ec5e263da760edc3c033045329fa3/utils/__pycache__/general.cpython-310.pyc
--------------------------------------------------------------------------------
/utils/__pycache__/metrics.cpython-310.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MuhammadMoinFaisal/yolov7-segmentation-with-DeepSORT-Tracking/989fb3a9655ec5e263da760edc3c033045329fa3/utils/__pycache__/metrics.cpython-310.pyc
--------------------------------------------------------------------------------
/utils/__pycache__/plots.cpython-310.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MuhammadMoinFaisal/yolov7-segmentation-with-DeepSORT-Tracking/989fb3a9655ec5e263da760edc3c033045329fa3/utils/__pycache__/plots.cpython-310.pyc
--------------------------------------------------------------------------------
/utils/__pycache__/torch_utils.cpython-310.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MuhammadMoinFaisal/yolov7-segmentation-with-DeepSORT-Tracking/989fb3a9655ec5e263da760edc3c033045329fa3/utils/__pycache__/torch_utils.cpython-310.pyc
--------------------------------------------------------------------------------
/utils/activations.py:
--------------------------------------------------------------------------------
1 | # YOLOv5 🚀 by Ultralytics, GPL-3.0 license
2 | """
3 | Activation functions
4 | """
5 |
6 | import torch
7 | import torch.nn as nn
8 | import torch.nn.functional as F
9 |
10 |
11 | class SiLU(nn.Module):
12 | # SiLU activation https://arxiv.org/pdf/1606.08415.pdf
13 | @staticmethod
14 | def forward(x):
15 | return x * torch.sigmoid(x)
16 |
17 |
18 | class Hardswish(nn.Module):
19 | # Hard-SiLU activation
20 | @staticmethod
21 | def forward(x):
22 | # return x * F.hardsigmoid(x) # for TorchScript and CoreML
23 | return x * F.hardtanh(x + 3, 0.0, 6.0) / 6.0 # for TorchScript, CoreML and ONNX
24 |
25 |
26 | class Mish(nn.Module):
27 | # Mish activation https://github.com/digantamisra98/Mish
28 | @staticmethod
29 | def forward(x):
30 | return x * F.softplus(x).tanh()
31 |
32 |
33 | class MemoryEfficientMish(nn.Module):
34 | # Mish activation memory-efficient
35 | class F(torch.autograd.Function):
36 |
37 | @staticmethod
38 | def forward(ctx, x):
39 | ctx.save_for_backward(x)
40 | return x.mul(torch.tanh(F.softplus(x))) # x * tanh(ln(1 + exp(x)))
41 |
42 | @staticmethod
43 | def backward(ctx, grad_output):
44 | x = ctx.saved_tensors[0]
45 | sx = torch.sigmoid(x)
46 | fx = F.softplus(x).tanh()
47 | return grad_output * (fx + x * sx * (1 - fx * fx))
48 |
49 | def forward(self, x):
50 | return self.F.apply(x)
51 |
52 |
53 | class FReLU(nn.Module):
54 | # FReLU activation https://arxiv.org/abs/2007.11824
55 | def __init__(self, c1, k=3): # ch_in, kernel
56 | super().__init__()
57 | self.conv = nn.Conv2d(c1, c1, k, 1, 1, groups=c1, bias=False)
58 | self.bn = nn.BatchNorm2d(c1)
59 |
60 | def forward(self, x):
61 | return torch.max(x, self.bn(self.conv(x)))
62 |
63 |
64 | class AconC(nn.Module):
65 | r""" ACON activation (activate or not)
66 | AconC: (p1*x-p2*x) * sigmoid(beta*(p1*x-p2*x)) + p2*x, beta is a learnable parameter
67 | according to "Activate or Not: Learning Customized Activation" .
68 | """
69 |
70 | def __init__(self, c1):
71 | super().__init__()
72 | self.p1 = nn.Parameter(torch.randn(1, c1, 1, 1))
73 | self.p2 = nn.Parameter(torch.randn(1, c1, 1, 1))
74 | self.beta = nn.Parameter(torch.ones(1, c1, 1, 1))
75 |
76 | def forward(self, x):
77 | dpx = (self.p1 - self.p2) * x
78 | return dpx * torch.sigmoid(self.beta * dpx) + self.p2 * x
79 |
80 |
81 | class MetaAconC(nn.Module):
82 | r""" ACON activation (activate or not)
83 | MetaAconC: (p1*x-p2*x) * sigmoid(beta*(p1*x-p2*x)) + p2*x, beta is generated by a small network
84 | according to "Activate or Not: Learning Customized Activation" .
85 | """
86 |
87 | def __init__(self, c1, k=1, s=1, r=16): # ch_in, kernel, stride, r
88 | super().__init__()
89 | c2 = max(r, c1 // r)
90 | self.p1 = nn.Parameter(torch.randn(1, c1, 1, 1))
91 | self.p2 = nn.Parameter(torch.randn(1, c1, 1, 1))
92 | self.fc1 = nn.Conv2d(c1, c2, k, s, bias=True)
93 | self.fc2 = nn.Conv2d(c2, c1, k, s, bias=True)
94 | # self.bn1 = nn.BatchNorm2d(c2)
95 | # self.bn2 = nn.BatchNorm2d(c1)
96 |
97 | def forward(self, x):
98 | y = x.mean(dim=2, keepdims=True).mean(dim=3, keepdims=True)
99 | # batch-size 1 bug/instabilities https://github.com/ultralytics/yolov5/issues/2891
100 | # beta = torch.sigmoid(self.bn2(self.fc2(self.bn1(self.fc1(y))))) # bug/unstable
101 | beta = torch.sigmoid(self.fc2(self.fc1(y))) # bug patch BN layers removed
102 | dpx = (self.p1 - self.p2) * x
103 | return dpx * torch.sigmoid(beta * dpx) + self.p2 * x
104 |
--------------------------------------------------------------------------------
/utils/autoanchor.py:
--------------------------------------------------------------------------------
1 | # YOLOv5 🚀 by Ultralytics, GPL-3.0 license
2 | """
3 | AutoAnchor utils
4 | """
5 |
6 | import random
7 |
8 | import numpy as np
9 | import torch
10 | import yaml
11 | from tqdm import tqdm
12 |
13 | from utils.general import LOGGER, colorstr
14 |
15 | PREFIX = colorstr('AutoAnchor: ')
16 |
17 |
18 | def check_anchor_order(m):
19 | # Check anchor order against stride order for YOLOv5 Detect() module m, and correct if necessary
20 | a = m.anchors.prod(-1).mean(-1).view(-1) # mean anchor area per output layer
21 | da = a[-1] - a[0] # delta a
22 | ds = m.stride[-1] - m.stride[0] # delta s
23 | if da and (da.sign() != ds.sign()): # same order
24 | LOGGER.info(f'{PREFIX}Reversing anchor order')
25 | m.anchors[:] = m.anchors.flip(0)
26 |
27 |
28 | def check_anchors(dataset, model, thr=4.0, imgsz=640):
29 | # Check anchor fit to data, recompute if necessary
30 | m = model.module.model[-1] if hasattr(model, 'module') else model.model[-1] # Detect()
31 | shapes = imgsz * dataset.shapes / dataset.shapes.max(1, keepdims=True)
32 | scale = np.random.uniform(0.9, 1.1, size=(shapes.shape[0], 1)) # augment scale
33 | wh = torch.tensor(np.concatenate([l[:, 3:5] * s for s, l in zip(shapes * scale, dataset.labels)])).float() # wh
34 |
35 | def metric(k): # compute metric
36 | r = wh[:, None] / k[None]
37 | x = torch.min(r, 1 / r).min(2)[0] # ratio metric
38 | best = x.max(1)[0] # best_x
39 | aat = (x > 1 / thr).float().sum(1).mean() # anchors above threshold
40 | bpr = (best > 1 / thr).float().mean() # best possible recall
41 | return bpr, aat
42 |
43 | stride = m.stride.to(m.anchors.device).view(-1, 1, 1) # model strides
44 | anchors = m.anchors.clone() * stride # current anchors
45 | bpr, aat = metric(anchors.cpu().view(-1, 2))
46 | s = f'\n{PREFIX}{aat:.2f} anchors/target, {bpr:.3f} Best Possible Recall (BPR). '
47 | if bpr > 0.98: # threshold to recompute
48 | LOGGER.info(f'{s}Current anchors are a good fit to dataset ✅')
49 | else:
50 | LOGGER.info(f'{s}Anchors are a poor fit to dataset ⚠️, attempting to improve...')
51 | na = m.anchors.numel() // 2 # number of anchors
52 | try:
53 | anchors = kmean_anchors(dataset, n=na, img_size=imgsz, thr=thr, gen=1000, verbose=False)
54 | except Exception as e:
55 | LOGGER.info(f'{PREFIX}ERROR: {e}')
56 | new_bpr = metric(anchors)[0]
57 | if new_bpr > bpr: # replace anchors
58 | anchors = torch.tensor(anchors, device=m.anchors.device).type_as(m.anchors)
59 | m.anchors[:] = anchors.clone().view_as(m.anchors)
60 | check_anchor_order(m) # must be in pixel-space (not grid-space)
61 | m.anchors /= stride
62 | s = f'{PREFIX}Done ✅ (optional: update model *.yaml to use these anchors in the future)'
63 | else:
64 | s = f'{PREFIX}Done ⚠️ (original anchors better than new anchors, proceeding with original anchors)'
65 | LOGGER.info(s)
66 |
67 |
68 | def kmean_anchors(dataset='./data/coco128.yaml', n=9, img_size=640, thr=4.0, gen=1000, verbose=True):
69 | """ Creates kmeans-evolved anchors from training dataset
70 |
71 | Arguments:
72 | dataset: path to data.yaml, or a loaded dataset
73 | n: number of anchors
74 | img_size: image size used for training
75 | thr: anchor-label wh ratio threshold hyperparameter hyp['anchor_t'] used for training, default=4.0
76 | gen: generations to evolve anchors using genetic algorithm
77 | verbose: print all results
78 |
79 | Return:
80 | k: kmeans evolved anchors
81 |
82 | Usage:
83 | from utils.autoanchor import *; _ = kmean_anchors()
84 | """
85 | from scipy.cluster.vq import kmeans
86 |
87 | npr = np.random
88 | thr = 1 / thr
89 |
90 | def metric(k, wh): # compute metrics
91 | r = wh[:, None] / k[None]
92 | x = torch.min(r, 1 / r).min(2)[0] # ratio metric
93 | # x = wh_iou(wh, torch.tensor(k)) # iou metric
94 | return x, x.max(1)[0] # x, best_x
95 |
96 | def anchor_fitness(k): # mutation fitness
97 | _, best = metric(torch.tensor(k, dtype=torch.float32), wh)
98 | return (best * (best > thr).float()).mean() # fitness
99 |
100 | def print_results(k, verbose=True):
101 | k = k[np.argsort(k.prod(1))] # sort small to large
102 | x, best = metric(k, wh0)
103 | bpr, aat = (best > thr).float().mean(), (x > thr).float().mean() * n # best possible recall, anch > thr
104 | s = f'{PREFIX}thr={thr:.2f}: {bpr:.4f} best possible recall, {aat:.2f} anchors past thr\n' \
105 | f'{PREFIX}n={n}, img_size={img_size}, metric_all={x.mean():.3f}/{best.mean():.3f}-mean/best, ' \
106 | f'past_thr={x[x > thr].mean():.3f}-mean: '
107 | for x in k:
108 | s += '%i,%i, ' % (round(x[0]), round(x[1]))
109 | if verbose:
110 | LOGGER.info(s[:-2])
111 | return k
112 |
113 | if isinstance(dataset, str): # *.yaml file
114 | with open(dataset, errors='ignore') as f:
115 | data_dict = yaml.safe_load(f) # model dict
116 | from utils.dataloaders import LoadImagesAndLabels
117 | dataset = LoadImagesAndLabels(data_dict['train'], augment=True, rect=True)
118 |
119 | # Get label wh
120 | shapes = img_size * dataset.shapes / dataset.shapes.max(1, keepdims=True)
121 | wh0 = np.concatenate([l[:, 3:5] * s for s, l in zip(shapes, dataset.labels)]) # wh
122 |
123 | # Filter
124 | i = (wh0 < 3.0).any(1).sum()
125 | if i:
126 | LOGGER.info(f'{PREFIX}WARNING: Extremely small objects found: {i} of {len(wh0)} labels are < 3 pixels in size')
127 | wh = wh0[(wh0 >= 2.0).any(1)] # filter > 2 pixels
128 | # wh = wh * (npr.rand(wh.shape[0], 1) * 0.9 + 0.1) # multiply by random scale 0-1
129 |
130 | # Kmeans init
131 | try:
132 | LOGGER.info(f'{PREFIX}Running kmeans for {n} anchors on {len(wh)} points...')
133 | assert n <= len(wh) # apply overdetermined constraint
134 | s = wh.std(0) # sigmas for whitening
135 | k = kmeans(wh / s, n, iter=30)[0] * s # points
136 | assert n == len(k) # kmeans may return fewer points than requested if wh is insufficient or too similar
137 | except Exception:
138 | LOGGER.warning(f'{PREFIX}WARNING: switching strategies from kmeans to random init')
139 | k = np.sort(npr.rand(n * 2)).reshape(n, 2) * img_size # random init
140 | wh, wh0 = (torch.tensor(x, dtype=torch.float32) for x in (wh, wh0))
141 | k = print_results(k, verbose=False)
142 |
143 | # Plot
144 | # k, d = [None] * 20, [None] * 20
145 | # for i in tqdm(range(1, 21)):
146 | # k[i-1], d[i-1] = kmeans(wh / s, i) # points, mean distance
147 | # fig, ax = plt.subplots(1, 2, figsize=(14, 7), tight_layout=True)
148 | # ax = ax.ravel()
149 | # ax[0].plot(np.arange(1, 21), np.array(d) ** 2, marker='.')
150 | # fig, ax = plt.subplots(1, 2, figsize=(14, 7)) # plot wh
151 | # ax[0].hist(wh[wh[:, 0]<100, 0],400)
152 | # ax[1].hist(wh[wh[:, 1]<100, 1],400)
153 | # fig.savefig('wh.png', dpi=200)
154 |
155 | # Evolve
156 | f, sh, mp, s = anchor_fitness(k), k.shape, 0.9, 0.1 # fitness, generations, mutation prob, sigma
157 | pbar = tqdm(range(gen), bar_format='{l_bar}{bar:10}{r_bar}{bar:-10b}') # progress bar
158 | for _ in pbar:
159 | v = np.ones(sh)
160 | while (v == 1).all(): # mutate until a change occurs (prevent duplicates)
161 | v = ((npr.random(sh) < mp) * random.random() * npr.randn(*sh) * s + 1).clip(0.3, 3.0)
162 | kg = (k.copy() * v).clip(min=2.0)
163 | fg = anchor_fitness(kg)
164 | if fg > f:
165 | f, k = fg, kg.copy()
166 | pbar.desc = f'{PREFIX}Evolving anchors with Genetic Algorithm: fitness = {f:.4f}'
167 | if verbose:
168 | print_results(k, verbose)
169 |
170 | return print_results(k)
171 |
--------------------------------------------------------------------------------
/utils/autobatch.py:
--------------------------------------------------------------------------------
1 | # YOLOv5 🚀 by Ultralytics, GPL-3.0 license
2 | """
3 | Auto-batch utils
4 | """
5 |
6 | from copy import deepcopy
7 |
8 | import numpy as np
9 | import torch
10 |
11 | from utils.general import LOGGER, colorstr
12 | from utils.torch_utils import profile
13 |
14 |
15 | def check_train_batch_size(model, imgsz=640, amp=True):
16 | # Check YOLOv5 training batch size
17 | with torch.cuda.amp.autocast(amp):
18 | return autobatch(deepcopy(model).train(), imgsz) # compute optimal batch size
19 |
20 |
21 | def autobatch(model, imgsz=640, fraction=0.9, batch_size=16):
22 | # Automatically estimate best batch size to use `fraction` of available CUDA memory
23 | # Usage:
24 | # import torch
25 | # from utils.autobatch import autobatch
26 | # model = torch.hub.load('ultralytics/yolov5', 'yolov5s', autoshape=False)
27 | # print(autobatch(model))
28 |
29 | # Check device
30 | prefix = colorstr('AutoBatch: ')
31 | LOGGER.info(f'{prefix}Computing optimal batch size for --imgsz {imgsz}')
32 | device = next(model.parameters()).device # get model device
33 | if device.type == 'cpu':
34 | LOGGER.info(f'{prefix}CUDA not detected, using default CPU batch-size {batch_size}')
35 | return batch_size
36 |
37 | # Inspect CUDA memory
38 | gb = 1 << 30 # bytes to GiB (1024 ** 3)
39 | d = str(device).upper() # 'CUDA:0'
40 | properties = torch.cuda.get_device_properties(device) # device properties
41 | t = properties.total_memory / gb # GiB total
42 | r = torch.cuda.memory_reserved(device) / gb # GiB reserved
43 | a = torch.cuda.memory_allocated(device) / gb # GiB allocated
44 | f = t - (r + a) # GiB free
45 | LOGGER.info(f'{prefix}{d} ({properties.name}) {t:.2f}G total, {r:.2f}G reserved, {a:.2f}G allocated, {f:.2f}G free')
46 |
47 | # Profile batch sizes
48 | batch_sizes = [1, 2, 4, 8, 16]
49 | try:
50 | img = [torch.empty(b, 3, imgsz, imgsz) for b in batch_sizes]
51 | results = profile(img, model, n=3, device=device)
52 | except Exception as e:
53 | LOGGER.warning(f'{prefix}{e}')
54 |
55 | # Fit a solution
56 | y = [x[2] for x in results if x] # memory [2]
57 | p = np.polyfit(batch_sizes[:len(y)], y, deg=1) # first degree polynomial fit
58 | b = int((f * fraction - p[1]) / p[0]) # y intercept (optimal batch size)
59 | if None in results: # some sizes failed
60 | i = results.index(None) # first fail index
61 | if b >= batch_sizes[i]: # y intercept above failure point
62 | b = batch_sizes[max(i - 1, 0)] # select prior safe point
63 | if b < 1: # zero or negative batch size
64 | b = 16
65 | LOGGER.warning(f'{prefix}WARNING: ⚠️ CUDA anomaly detected, recommend restart environment and retry command.')
66 |
67 | fraction = np.polyval(p, b) / t # actual fraction predicted
68 | LOGGER.info(f'{prefix}Using batch-size {b} for {d} {t * fraction:.2f}G/{t:.2f}G ({fraction * 100:.0f}%) ✅')
69 | return b
70 |
--------------------------------------------------------------------------------
/utils/aws/__init__.py:
--------------------------------------------------------------------------------
1 | # init
--------------------------------------------------------------------------------
/utils/aws/mime.sh:
--------------------------------------------------------------------------------
1 | # AWS EC2 instance startup 'MIME' script https://aws.amazon.com/premiumsupport/knowledge-center/execute-user-data-ec2/
2 | # This script will run on every instance restart, not only on first start
3 | # --- DO NOT COPY ABOVE COMMENTS WHEN PASTING INTO USERDATA ---
4 |
5 | Content-Type: multipart/mixed; boundary="//"
6 | MIME-Version: 1.0
7 |
8 | --//
9 | Content-Type: text/cloud-config; charset="us-ascii"
10 | MIME-Version: 1.0
11 | Content-Transfer-Encoding: 7bit
12 | Content-Disposition: attachment; filename="cloud-config.txt"
13 |
14 | #cloud-config
15 | cloud_final_modules:
16 | - [scripts-user, always]
17 |
18 | --//
19 | Content-Type: text/x-shellscript; charset="us-ascii"
20 | MIME-Version: 1.0
21 | Content-Transfer-Encoding: 7bit
22 | Content-Disposition: attachment; filename="userdata.txt"
23 |
24 | #!/bin/bash
25 | # --- paste contents of userdata.sh here ---
26 | --//
27 |
--------------------------------------------------------------------------------
/utils/aws/resume.py:
--------------------------------------------------------------------------------
1 | # Resume all interrupted trainings in yolov5/ dir including DDP trainings
2 | # Usage: $ python utils/aws/resume.py
3 |
4 | import os
5 | import sys
6 | from pathlib import Path
7 |
8 | import torch
9 | import yaml
10 |
11 | FILE = Path(__file__).resolve()
12 | ROOT = FILE.parents[2] # YOLOv5 root directory
13 | if str(ROOT) not in sys.path:
14 | sys.path.append(str(ROOT)) # add ROOT to PATH
15 |
16 | port = 0 # --master_port
17 | path = Path('').resolve()
18 | for last in path.rglob('*/**/last.pt'):
19 | ckpt = torch.load(last)
20 | if ckpt['optimizer'] is None:
21 | continue
22 |
23 | # Load opt.yaml
24 | with open(last.parent.parent / 'opt.yaml', errors='ignore') as f:
25 | opt = yaml.safe_load(f)
26 |
27 | # Get device count
28 | d = opt['device'].split(',') # devices
29 | nd = len(d) # number of devices
30 | ddp = nd > 1 or (nd == 0 and torch.cuda.device_count() > 1) # distributed data parallel
31 |
32 | if ddp: # multi-GPU
33 | port += 1
34 | cmd = f'python -m torch.distributed.run --nproc_per_node {nd} --master_port {port} train.py --resume {last}'
35 | else: # single-GPU
36 | cmd = f'python train.py --resume {last}'
37 |
38 | cmd += ' > /dev/null 2>&1 &' # redirect output to dev/null and run in daemon thread
39 | print(cmd)
40 | os.system(cmd)
41 |
--------------------------------------------------------------------------------
/utils/aws/userdata.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # AWS EC2 instance startup script https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/user-data.html
3 | # This script will run only once on first instance start (for a re-start script see mime.sh)
4 | # /home/ubuntu (ubuntu) or /home/ec2-user (amazon-linux) is working dir
5 | # Use >300 GB SSD
6 |
7 | cd home/ubuntu
8 | if [ ! -d yolov5 ]; then
9 | echo "Running first-time script." # install dependencies, download COCO, pull Docker
10 | git clone https://github.com/ultralytics/yolov5 -b master && sudo chmod -R 777 yolov5
11 | cd yolov5
12 | bash data/scripts/get_coco.sh && echo "COCO done." &
13 | sudo docker pull ultralytics/yolov5:latest && echo "Docker done." &
14 | python -m pip install --upgrade pip && pip install -r requirements.txt && python detect.py && echo "Requirements done." &
15 | wait && echo "All tasks done." # finish background tasks
16 | else
17 | echo "Running re-start script." # resume interrupted runs
18 | i=0
19 | list=$(sudo docker ps -qa) # container list i.e. $'one\ntwo\nthree\nfour'
20 | while IFS= read -r id; do
21 | ((i++))
22 | echo "restarting container $i: $id"
23 | sudo docker start $id
24 | # sudo docker exec -it $id python train.py --resume # single-GPU
25 | sudo docker exec -d $id python utils/aws/resume.py # multi-scenario
26 | done <<<"$list"
27 | fi
28 |
--------------------------------------------------------------------------------
/utils/benchmarks.py:
--------------------------------------------------------------------------------
1 | # YOLOv5 🚀 by Ultralytics, GPL-3.0 license
2 | """
3 | Run YOLOv5 benchmarks on all supported export formats
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 | $ pip install -U nvidia-tensorrt --index-url https://pypi.ngc.nvidia.com # TensorRT
23 |
24 | Usage:
25 | $ python utils/benchmarks.py --weights yolov5s.pt --img 640
26 | """
27 |
28 | import argparse
29 | import platform
30 | import sys
31 | import time
32 | from pathlib import Path
33 |
34 | import pandas as pd
35 |
36 | FILE = Path(__file__).resolve()
37 | ROOT = FILE.parents[1] # YOLOv5 root directory
38 | if str(ROOT) not in sys.path:
39 | sys.path.append(str(ROOT)) # add ROOT to PATH
40 | # ROOT = ROOT.relative_to(Path.cwd()) # relative
41 |
42 | import export
43 | import val
44 | from utils import notebook_init
45 | from utils.general import LOGGER, check_yaml, file_size, print_args
46 | from utils.torch_utils import select_device
47 |
48 |
49 | def run(
50 | weights=ROOT / 'yolov5s.pt', # weights path
51 | imgsz=640, # inference size (pixels)
52 | batch_size=1, # batch size
53 | data=ROOT / 'data/coco128.yaml', # dataset.yaml path
54 | device='', # cuda device, i.e. 0 or 0,1,2,3 or cpu
55 | half=False, # use FP16 half-precision inference
56 | test=False, # test exports only
57 | pt_only=False, # test PyTorch only
58 | hard_fail=False, # throw error on benchmark failure
59 | ):
60 | y, t = [], time.time()
61 | device = select_device(device)
62 | for i, (name, f, suffix, cpu, gpu) in export.export_formats().iterrows(): # index, (name, file, suffix, CPU, GPU)
63 | try:
64 | assert i not in (9, 10), 'inference not supported' # Edge TPU and TF.js are unsupported
65 | assert i != 5 or platform.system() == 'Darwin', 'inference only supported on macOS>=10.13' # CoreML
66 | if 'cpu' in device.type:
67 | assert cpu, 'inference not supported on CPU'
68 | if 'cuda' in device.type:
69 | assert gpu, 'inference not supported on GPU'
70 |
71 | # Export
72 | if f == '-':
73 | w = weights # PyTorch format
74 | else:
75 | w = export.run(weights=weights, imgsz=[imgsz], include=[f], device=device, half=half)[-1] # all others
76 | assert suffix in str(w), 'export failed'
77 |
78 | # Validate
79 | result = val.run(data, w, batch_size, imgsz, plots=False, device=device, task='benchmark', half=half)
80 | metrics = result[0] # metrics (mp, mr, map50, map, *losses(box, obj, cls))
81 | speeds = result[2] # times (preprocess, inference, postprocess)
82 | y.append([name, round(file_size(w), 1), round(metrics[3], 4), round(speeds[1], 2)]) # MB, mAP, t_inference
83 | except Exception as e:
84 | if hard_fail:
85 | assert type(e) is AssertionError, f'Benchmark --hard-fail for {name}: {e}'
86 | LOGGER.warning(f'WARNING: Benchmark failure for {name}: {e}')
87 | y.append([name, None, None, None]) # mAP, t_inference
88 | if pt_only and i == 0:
89 | break # break after PyTorch
90 |
91 | # Print results
92 | LOGGER.info('\n')
93 | parse_opt()
94 | notebook_init() # print system info
95 | c = ['Format', 'Size (MB)', 'mAP@0.5:0.95', 'Inference time (ms)'] if map else ['Format', 'Export', '', '']
96 | py = pd.DataFrame(y, columns=c)
97 | LOGGER.info(f'\nBenchmarks complete ({time.time() - t:.2f}s)')
98 | LOGGER.info(str(py if map else py.iloc[:, :2]))
99 | return py
100 |
101 |
102 | def test(
103 | weights=ROOT / 'yolov5s.pt', # weights path
104 | imgsz=640, # inference size (pixels)
105 | batch_size=1, # batch size
106 | data=ROOT / 'data/coco128.yaml', # dataset.yaml path
107 | device='', # cuda device, i.e. 0 or 0,1,2,3 or cpu
108 | half=False, # use FP16 half-precision inference
109 | test=False, # test exports only
110 | pt_only=False, # test PyTorch only
111 | hard_fail=False, # throw error on benchmark failure
112 | ):
113 | y, t = [], time.time()
114 | device = select_device(device)
115 | for i, (name, f, suffix, gpu) in export.export_formats().iterrows(): # index, (name, file, suffix, gpu-capable)
116 | try:
117 | w = weights if f == '-' else \
118 | export.run(weights=weights, imgsz=[imgsz], include=[f], device=device, half=half)[-1] # weights
119 | assert suffix in str(w), 'export failed'
120 | y.append([name, True])
121 | except Exception:
122 | y.append([name, False]) # mAP, t_inference
123 |
124 | # Print results
125 | LOGGER.info('\n')
126 | parse_opt()
127 | notebook_init() # print system info
128 | py = pd.DataFrame(y, columns=['Format', 'Export'])
129 | LOGGER.info(f'\nExports complete ({time.time() - t:.2f}s)')
130 | LOGGER.info(str(py))
131 | return py
132 |
133 |
134 | def parse_opt():
135 | parser = argparse.ArgumentParser()
136 | parser.add_argument('--weights', type=str, default=ROOT / 'yolov5s.pt', help='weights path')
137 | parser.add_argument('--imgsz', '--img', '--img-size', type=int, default=640, help='inference size (pixels)')
138 | parser.add_argument('--batch-size', type=int, default=1, help='batch size')
139 | parser.add_argument('--data', type=str, default=ROOT / 'data/coco128.yaml', help='dataset.yaml path')
140 | parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu')
141 | parser.add_argument('--half', action='store_true', help='use FP16 half-precision inference')
142 | parser.add_argument('--test', action='store_true', help='test exports only')
143 | parser.add_argument('--pt-only', action='store_true', help='test PyTorch only')
144 | parser.add_argument('--hard-fail', action='store_true', help='throw error on benchmark failure')
145 | opt = parser.parse_args()
146 | opt.data = check_yaml(opt.data) # check YAML
147 | print_args(vars(opt))
148 | return opt
149 |
150 |
151 | def main(opt):
152 | test(**vars(opt)) if opt.test else run(**vars(opt))
153 |
154 |
155 | if __name__ == "__main__":
156 | opt = parse_opt()
157 | main(opt)
158 |
--------------------------------------------------------------------------------
/utils/callbacks.py:
--------------------------------------------------------------------------------
1 | # YOLOv5 🚀 by Ultralytics, GPL-3.0 license
2 | """
3 | Callback utils
4 | """
5 |
6 | import threading
7 |
8 |
9 | class Callbacks:
10 | """"
11 | Handles all registered callbacks for YOLOv5 Hooks
12 | """
13 |
14 | def __init__(self):
15 | # Define the available callbacks
16 | self._callbacks = {
17 | 'on_pretrain_routine_start': [],
18 | 'on_pretrain_routine_end': [],
19 | 'on_train_start': [],
20 | 'on_train_epoch_start': [],
21 | 'on_train_batch_start': [],
22 | 'optimizer_step': [],
23 | 'on_before_zero_grad': [],
24 | 'on_train_batch_end': [],
25 | 'on_train_epoch_end': [],
26 | 'on_val_start': [],
27 | 'on_val_batch_start': [],
28 | 'on_val_image_end': [],
29 | 'on_val_batch_end': [],
30 | 'on_val_end': [],
31 | 'on_fit_epoch_end': [], # fit = train + val
32 | 'on_model_save': [],
33 | 'on_train_end': [],
34 | 'on_params_update': [],
35 | 'teardown': [],}
36 | self.stop_training = False # set True to interrupt training
37 |
38 | def register_action(self, hook, name='', callback=None):
39 | """
40 | Register a new action to a callback hook
41 |
42 | Args:
43 | hook: The callback hook name to register the action to
44 | name: The name of the action for later reference
45 | callback: The callback to fire
46 | """
47 | assert hook in self._callbacks, f"hook '{hook}' not found in callbacks {self._callbacks}"
48 | assert callable(callback), f"callback '{callback}' is not callable"
49 | self._callbacks[hook].append({'name': name, 'callback': callback})
50 |
51 | def get_registered_actions(self, hook=None):
52 | """"
53 | Returns all the registered actions by callback hook
54 |
55 | Args:
56 | hook: The name of the hook to check, defaults to all
57 | """
58 | return self._callbacks[hook] if hook else self._callbacks
59 |
60 | def run(self, hook, *args, thread=False, **kwargs):
61 | """
62 | Loop through the registered actions and fire all callbacks on main thread
63 |
64 | Args:
65 | hook: The name of the hook to check, defaults to all
66 | args: Arguments to receive from YOLOv5
67 | thread: (boolean) Run callbacks in daemon thread
68 | kwargs: Keyword Arguments to receive from YOLOv5
69 | """
70 |
71 | assert hook in self._callbacks, f"hook '{hook}' not found in callbacks {self._callbacks}"
72 | for logger in self._callbacks[hook]:
73 | if thread:
74 | threading.Thread(target=logger['callback'], args=args, kwargs=kwargs, daemon=True).start()
75 | else:
76 | logger['callback'](*args, **kwargs)
77 |
--------------------------------------------------------------------------------
/utils/docker/Dockerfile:
--------------------------------------------------------------------------------
1 | # YOLOv5 🚀 by Ultralytics, GPL-3.0 license
2 | # Builds ultralytics/yolov5:latest image on DockerHub https://hub.docker.com/r/ultralytics/yolov5
3 | # Image is CUDA-optimized for YOLOv5 single/multi-GPU training and inference
4 |
5 | # Start FROM NVIDIA PyTorch image https://ngc.nvidia.com/catalog/containers/nvidia:pytorch
6 | FROM nvcr.io/nvidia/pytorch:22.07-py3
7 | RUN rm -rf /opt/pytorch # remove 1.2GB dir
8 |
9 | # Downloads to user config dir
10 | ADD https://ultralytics.com/assets/Arial.ttf https://ultralytics.com/assets/Arial.Unicode.ttf /root/.config/Ultralytics/
11 |
12 | # Install linux packages
13 | RUN apt update && apt install --no-install-recommends -y zip htop screen libgl1-mesa-glx
14 |
15 | # Install pip packages
16 | COPY requirements.txt .
17 | RUN python -m pip install --upgrade pip wheel
18 | RUN pip uninstall -y Pillow torchtext torch torchvision
19 | RUN pip install --no-cache -r requirements.txt albumentations wandb gsutil notebook Pillow>=9.1.0 \
20 | 'opencv-python<4.6.0.66' \
21 | --extra-index-url https://download.pytorch.org/whl/cu113
22 |
23 | # Create working directory
24 | RUN mkdir -p /usr/src/app
25 | WORKDIR /usr/src/app
26 |
27 | # Copy contents
28 | # COPY . /usr/src/app (issues as not a .git directory)
29 | RUN git clone https://github.com/ultralytics/yolov5 /usr/src/app
30 |
31 | # Set environment variables
32 | ENV OMP_NUM_THREADS=8
33 |
34 |
35 | # Usage Examples -------------------------------------------------------------------------------------------------------
36 |
37 | # Build and Push
38 | # t=ultralytics/yolov5:latest && sudo docker build -f utils/docker/Dockerfile -t $t . && sudo docker push $t
39 |
40 | # Pull and Run
41 | # t=ultralytics/yolov5:latest && sudo docker pull $t && sudo docker run -it --ipc=host --gpus all $t
42 |
43 | # Pull and Run with local directory access
44 | # t=ultralytics/yolov5:latest && sudo docker pull $t && sudo docker run -it --ipc=host --gpus all -v "$(pwd)"/datasets:/usr/src/datasets $t
45 |
46 | # Kill all
47 | # sudo docker kill $(sudo docker ps -q)
48 |
49 | # Kill all image-based
50 | # sudo docker kill $(sudo docker ps -qa --filter ancestor=ultralytics/yolov5:latest)
51 |
52 | # DockerHub tag update
53 | # t=ultralytics/yolov5:latest tnew=ultralytics/yolov5:v6.2 && sudo docker pull $t && sudo docker tag $t $tnew && sudo docker push $tnew
54 |
55 | # Clean up
56 | # docker system prune -a --volumes
57 |
58 | # Update Ubuntu drivers
59 | # https://www.maketecheasier.com/install-nvidia-drivers-ubuntu/
60 |
61 | # DDP test
62 | # python -m torch.distributed.run --nproc_per_node 2 --master_port 1 train.py --epochs 3
63 |
64 | # GCP VM from Image
65 | # docker.io/ultralytics/yolov5:latest
66 |
--------------------------------------------------------------------------------
/utils/docker/Dockerfile-arm64:
--------------------------------------------------------------------------------
1 | # YOLOv5 🚀 by Ultralytics, GPL-3.0 license
2 | # Builds ultralytics/yolov5:latest-arm64 image on DockerHub https://hub.docker.com/r/ultralytics/yolov5
3 | # Image is aarch64-compatible for Apple M1 and other ARM architectures i.e. Jetson Nano and Raspberry Pi
4 |
5 | # Start FROM Ubuntu image https://hub.docker.com/_/ubuntu
6 | FROM arm64v8/ubuntu:20.04
7 |
8 | # Downloads to user config dir
9 | ADD https://ultralytics.com/assets/Arial.ttf https://ultralytics.com/assets/Arial.Unicode.ttf /root/.config/Ultralytics/
10 |
11 | # Install linux packages
12 | RUN apt update
13 | RUN DEBIAN_FRONTEND=noninteractive TZ=Etc/UTC apt install -y tzdata
14 | RUN apt install --no-install-recommends -y python3-pip git zip curl htop gcc \
15 | libgl1-mesa-glx libglib2.0-0 libpython3.8-dev
16 | # RUN alias python=python3
17 |
18 | # Install pip packages
19 | COPY requirements.txt .
20 | RUN python3 -m pip install --upgrade pip wheel
21 | RUN pip install --no-cache -r requirements.txt gsutil notebook \
22 | tensorflow-aarch64
23 | # tensorflowjs \
24 | # onnx onnx-simplifier onnxruntime \
25 | # coremltools openvino-dev \
26 |
27 | # Create working directory
28 | RUN mkdir -p /usr/src/app
29 | WORKDIR /usr/src/app
30 |
31 | # Copy contents
32 | # COPY . /usr/src/app (issues as not a .git directory)
33 | RUN git clone https://github.com/ultralytics/yolov5 /usr/src/app
34 |
35 |
36 | # Usage Examples -------------------------------------------------------------------------------------------------------
37 |
38 | # Build and Push
39 | # t=ultralytics/yolov5:latest-M1 && sudo docker build --platform linux/arm64 -f utils/docker/Dockerfile-arm64 -t $t . && sudo docker push $t
40 |
41 | # Pull and Run
42 | # t=ultralytics/yolov5:latest-M1 && sudo docker pull $t && sudo docker run -it --ipc=host -v "$(pwd)"/datasets:/usr/src/datasets $t
43 |
--------------------------------------------------------------------------------
/utils/docker/Dockerfile-cpu:
--------------------------------------------------------------------------------
1 | # YOLOv5 🚀 by Ultralytics, GPL-3.0 license
2 | # Builds ultralytics/yolov5:latest-cpu image on DockerHub https://hub.docker.com/r/ultralytics/yolov5
3 | # Image is CPU-optimized for ONNX, OpenVINO and PyTorch YOLOv5 deployments
4 |
5 | # Start FROM Ubuntu image https://hub.docker.com/_/ubuntu
6 | FROM ubuntu:20.04
7 |
8 | # Downloads to user config dir
9 | ADD https://ultralytics.com/assets/Arial.ttf https://ultralytics.com/assets/Arial.Unicode.ttf /root/.config/Ultralytics/
10 |
11 | # Install linux packages
12 | RUN apt update
13 | RUN DEBIAN_FRONTEND=noninteractive TZ=Etc/UTC apt install -y tzdata
14 | RUN apt install --no-install-recommends -y python3-pip git zip curl htop libgl1-mesa-glx libglib2.0-0 libpython3-dev
15 | # RUN alias python=python3
16 |
17 | # Install pip packages
18 | COPY requirements.txt .
19 | RUN python3 -m pip install --upgrade pip wheel
20 | RUN pip install --no-cache -r requirements.txt albumentations gsutil notebook \
21 | coremltools onnx onnx-simplifier onnxruntime tensorflow-cpu tensorflowjs \
22 | # openvino-dev \
23 | --extra-index-url https://download.pytorch.org/whl/cpu
24 |
25 | # Create working directory
26 | RUN mkdir -p /usr/src/app
27 | WORKDIR /usr/src/app
28 |
29 | # Copy contents
30 | # COPY . /usr/src/app (issues as not a .git directory)
31 | RUN git clone https://github.com/ultralytics/yolov5 /usr/src/app
32 |
33 |
34 | # Usage Examples -------------------------------------------------------------------------------------------------------
35 |
36 | # Build and Push
37 | # t=ultralytics/yolov5:latest-cpu && sudo docker build -f utils/docker/Dockerfile-cpu -t $t . && sudo docker push $t
38 |
39 | # Pull and Run
40 | # t=ultralytics/yolov5:latest-cpu && sudo docker pull $t && sudo docker run -it --ipc=host -v "$(pwd)"/datasets:/usr/src/datasets $t
41 |
--------------------------------------------------------------------------------
/utils/downloads.py:
--------------------------------------------------------------------------------
1 | # YOLOv5 🚀 by Ultralytics, GPL-3.0 license
2 | """
3 | Download utils
4 | """
5 |
6 | import logging
7 | import os
8 | import platform
9 | import subprocess
10 | import time
11 | import urllib
12 | from pathlib import Path
13 | from zipfile import ZipFile
14 |
15 | import requests
16 | import torch
17 |
18 |
19 | def is_url(url, check_online=True):
20 | # Check if online file exists
21 | try:
22 | url = str(url)
23 | result = urllib.parse.urlparse(url)
24 | assert all([result.scheme, result.netloc, result.path]) # check if is url
25 | return (urllib.request.urlopen(url).getcode() == 200) if check_online else True # check if exists online
26 | except (AssertionError, urllib.request.HTTPError):
27 | return False
28 |
29 |
30 | def gsutil_getsize(url=''):
31 | # gs://bucket/file size https://cloud.google.com/storage/docs/gsutil/commands/du
32 | s = subprocess.check_output(f'gsutil du {url}', shell=True).decode('utf-8')
33 | return eval(s.split(' ')[0]) if len(s) else 0 # bytes
34 |
35 |
36 | def safe_download(file, url, url2=None, min_bytes=1E0, error_msg=''):
37 | # Attempts to download file from url or url2, checks and removes incomplete downloads < min_bytes
38 | from utils.general import LOGGER
39 |
40 | file = Path(file)
41 | assert_msg = f"Downloaded file '{file}' does not exist or size is < min_bytes={min_bytes}"
42 | try: # url1
43 | LOGGER.info(f'Downloading {url} to {file}...')
44 | torch.hub.download_url_to_file(url, str(file), progress=LOGGER.level <= logging.INFO)
45 | assert file.exists() and file.stat().st_size > min_bytes, assert_msg # check
46 | except Exception as e: # url2
47 | file.unlink(missing_ok=True) # remove partial downloads
48 | LOGGER.info(f'ERROR: {e}\nRe-attempting {url2 or url} to {file}...')
49 | os.system(f"curl -# -L '{url2 or url}' -o '{file}' --retry 3 -C -") # curl download, retry and resume on fail
50 | finally:
51 | if not file.exists() or file.stat().st_size < min_bytes: # check
52 | file.unlink(missing_ok=True) # remove partial downloads
53 | LOGGER.info(f"ERROR: {assert_msg}\n{error_msg}")
54 | LOGGER.info('')
55 |
56 |
57 | def attempt_download(file, repo='ultralytics/yolov5', release='v6.2'):
58 | # Attempt file download from GitHub release assets if not found locally. release = 'latest', 'v6.2', etc.
59 | from utils.general import LOGGER
60 |
61 | def github_assets(repository, version='latest'):
62 | # Return GitHub repo tag (i.e. 'v6.2') and assets (i.e. ['yolov5s.pt', 'yolov5m.pt', ...])
63 | if version != 'latest':
64 | version = f'tags/{version}' # i.e. tags/v6.2
65 | response = requests.get(f'https://api.github.com/repos/{repository}/releases/{version}').json() # github api
66 | return response['tag_name'], [x['name'] for x in response['assets']] # tag, assets
67 |
68 | file = Path(str(file).strip().replace("'", ''))
69 | if not file.exists():
70 | # URL specified
71 | name = Path(urllib.parse.unquote(str(file))).name # decode '%2F' to '/' etc.
72 | if str(file).startswith(('http:/', 'https:/')): # download
73 | url = str(file).replace(':/', '://') # Pathlib turns :// -> :/
74 | file = name.split('?')[0] # parse authentication https://url.com/file.txt?auth...
75 | if Path(file).is_file():
76 | LOGGER.info(f'Found {url} locally at {file}') # file already exists
77 | else:
78 | safe_download(file=file, url=url, min_bytes=1E5)
79 | return file
80 |
81 | # GitHub assets
82 | assets = [
83 | 'yolov5n.pt', 'yolov5s.pt', 'yolov5m.pt', 'yolov5l.pt', 'yolov5x.pt', 'yolov5n6.pt', 'yolov5s6.pt',
84 | 'yolov5m6.pt', 'yolov5l6.pt', 'yolov5x6.pt']
85 | try:
86 | tag, assets = github_assets(repo, release)
87 | except Exception:
88 | try:
89 | tag, assets = github_assets(repo) # latest release
90 | except Exception:
91 | try:
92 | tag = subprocess.check_output('git tag', shell=True, stderr=subprocess.STDOUT).decode().split()[-1]
93 | except Exception:
94 | tag = release
95 |
96 | file.parent.mkdir(parents=True, exist_ok=True) # make parent dir (if required)
97 | if name in assets:
98 | url3 = 'https://drive.google.com/drive/folders/1EFQTEUeXWSFww0luse2jB9M1QNZQGwNl' # backup gdrive mirror
99 | safe_download(
100 | file,
101 | url=f'https://github.com/{repo}/releases/download/{tag}/{name}',
102 | url2=f'https://storage.googleapis.com/{repo}/{tag}/{name}', # backup url (optional)
103 | min_bytes=1E5,
104 | error_msg=f'{file} missing, try downloading from https://github.com/{repo}/releases/{tag} or {url3}')
105 |
106 | return str(file)
107 |
108 |
109 | def gdrive_download(id='16TiPfZj7htmTyhntwcZyEEAejOUxuT6m', file='tmp.zip'):
110 | # Downloads a file from Google Drive. from yolov5.utils.downloads import *; gdrive_download()
111 | t = time.time()
112 | file = Path(file)
113 | cookie = Path('cookie') # gdrive cookie
114 | print(f'Downloading https://drive.google.com/uc?export=download&id={id} as {file}... ', end='')
115 | file.unlink(missing_ok=True) # remove existing file
116 | cookie.unlink(missing_ok=True) # remove existing cookie
117 |
118 | # Attempt file download
119 | out = "NUL" if platform.system() == "Windows" else "/dev/null"
120 | os.system(f'curl -c ./cookie -s -L "drive.google.com/uc?export=download&id={id}" > {out}')
121 | if os.path.exists('cookie'): # large file
122 | s = f'curl -Lb ./cookie "drive.google.com/uc?export=download&confirm={get_token()}&id={id}" -o {file}'
123 | else: # small file
124 | s = f'curl -s -L -o {file} "drive.google.com/uc?export=download&id={id}"'
125 | r = os.system(s) # execute, capture return
126 | cookie.unlink(missing_ok=True) # remove existing cookie
127 |
128 | # Error check
129 | if r != 0:
130 | file.unlink(missing_ok=True) # remove partial
131 | print('Download error ') # raise Exception('Download error')
132 | return r
133 |
134 | # Unzip if archive
135 | if file.suffix == '.zip':
136 | print('unzipping... ', end='')
137 | ZipFile(file).extractall(path=file.parent) # unzip
138 | file.unlink() # remove zip
139 |
140 | print(f'Done ({time.time() - t:.1f}s)')
141 | return r
142 |
143 |
144 | def get_token(cookie="./cookie"):
145 | with open(cookie) as f:
146 | for line in f:
147 | if "download" in line:
148 | return line.split()[-1]
149 | return ""
150 |
151 |
152 | # Google utils: https://cloud.google.com/storage/docs/reference/libraries ----------------------------------------------
153 | #
154 | #
155 | # def upload_blob(bucket_name, source_file_name, destination_blob_name):
156 | # # Uploads a file to a bucket
157 | # # https://cloud.google.com/storage/docs/uploading-objects#storage-upload-object-python
158 | #
159 | # storage_client = storage.Client()
160 | # bucket = storage_client.get_bucket(bucket_name)
161 | # blob = bucket.blob(destination_blob_name)
162 | #
163 | # blob.upload_from_filename(source_file_name)
164 | #
165 | # print('File {} uploaded to {}.'.format(
166 | # source_file_name,
167 | # destination_blob_name))
168 | #
169 | #
170 | # def download_blob(bucket_name, source_blob_name, destination_file_name):
171 | # # Uploads a blob from a bucket
172 | # storage_client = storage.Client()
173 | # bucket = storage_client.get_bucket(bucket_name)
174 | # blob = bucket.blob(source_blob_name)
175 | #
176 | # blob.download_to_filename(destination_file_name)
177 | #
178 | # print('Blob {} downloaded to {}.'.format(
179 | # source_blob_name,
180 | # destination_file_name))
181 |
--------------------------------------------------------------------------------
/utils/flask_rest_api/README.md:
--------------------------------------------------------------------------------
1 | # Flask REST API
2 |
3 | [REST](https://en.wikipedia.org/wiki/Representational_state_transfer) [API](https://en.wikipedia.org/wiki/API)s are
4 | commonly used to expose Machine Learning (ML) models to other services. This folder contains an example REST API
5 | created using Flask to expose the YOLOv5s model from [PyTorch Hub](https://pytorch.org/hub/ultralytics_yolov5/).
6 |
7 | ## Requirements
8 |
9 | [Flask](https://palletsprojects.com/p/flask/) is required. Install with:
10 |
11 | ```shell
12 | $ pip install Flask
13 | ```
14 |
15 | ## Run
16 |
17 | After Flask installation run:
18 |
19 | ```shell
20 | $ python3 restapi.py --port 5000
21 | ```
22 |
23 | Then use [curl](https://curl.se/) to perform a request:
24 |
25 | ```shell
26 | $ curl -X POST -F image=@zidane.jpg 'http://localhost:5000/v1/object-detection/yolov5s'
27 | ```
28 |
29 | The model inference results are returned as a JSON response:
30 |
31 | ```json
32 | [
33 | {
34 | "class": 0,
35 | "confidence": 0.8900438547,
36 | "height": 0.9318675399,
37 | "name": "person",
38 | "width": 0.3264600933,
39 | "xcenter": 0.7438579798,
40 | "ycenter": 0.5207948685
41 | },
42 | {
43 | "class": 0,
44 | "confidence": 0.8440024257,
45 | "height": 0.7155083418,
46 | "name": "person",
47 | "width": 0.6546785235,
48 | "xcenter": 0.427829951,
49 | "ycenter": 0.6334488392
50 | },
51 | {
52 | "class": 27,
53 | "confidence": 0.3771208823,
54 | "height": 0.3902671337,
55 | "name": "tie",
56 | "width": 0.0696444362,
57 | "xcenter": 0.3675483763,
58 | "ycenter": 0.7991207838
59 | },
60 | {
61 | "class": 27,
62 | "confidence": 0.3527112305,
63 | "height": 0.1540903747,
64 | "name": "tie",
65 | "width": 0.0336618312,
66 | "xcenter": 0.7814827561,
67 | "ycenter": 0.5065554976
68 | }
69 | ]
70 | ```
71 |
72 | An example python script to perform inference using [requests](https://docs.python-requests.org/en/master/) is given
73 | in `example_request.py`
74 |
--------------------------------------------------------------------------------
/utils/flask_rest_api/example_request.py:
--------------------------------------------------------------------------------
1 | # YOLOv5 🚀 by Ultralytics, GPL-3.0 license
2 | """
3 | Perform test request
4 | """
5 |
6 | import pprint
7 |
8 | import requests
9 |
10 | DETECTION_URL = "http://localhost:5000/v1/object-detection/yolov5s"
11 | IMAGE = "zidane.jpg"
12 |
13 | # Read image
14 | with open(IMAGE, "rb") as f:
15 | image_data = f.read()
16 |
17 | response = requests.post(DETECTION_URL, files={"image": image_data}).json()
18 |
19 | pprint.pprint(response)
20 |
--------------------------------------------------------------------------------
/utils/flask_rest_api/restapi.py:
--------------------------------------------------------------------------------
1 | # YOLOv5 🚀 by Ultralytics, GPL-3.0 license
2 | """
3 | Run a Flask REST API exposing one or more YOLOv5s models
4 | """
5 |
6 | import argparse
7 | import io
8 |
9 | import torch
10 | from flask import Flask, request
11 | from PIL import Image
12 |
13 | app = Flask(__name__)
14 | models = {}
15 |
16 | DETECTION_URL = "/v1/object-detection/"
17 |
18 |
19 | @app.route(DETECTION_URL, methods=["POST"])
20 | def predict(model):
21 | if request.method != "POST":
22 | return
23 |
24 | if request.files.get("image"):
25 | # Method 1
26 | # with request.files["image"] as f:
27 | # im = Image.open(io.BytesIO(f.read()))
28 |
29 | # Method 2
30 | im_file = request.files["image"]
31 | im_bytes = im_file.read()
32 | im = Image.open(io.BytesIO(im_bytes))
33 |
34 | if model in models:
35 | results = models[model](im, size=640) # reduce size=320 for faster inference
36 | return results.pandas().xyxy[0].to_json(orient="records")
37 |
38 |
39 | if __name__ == "__main__":
40 | parser = argparse.ArgumentParser(description="Flask API exposing YOLOv5 model")
41 | parser.add_argument("--port", default=5000, type=int, help="port number")
42 | parser.add_argument('--model', nargs='+', default=['yolov5s'], help='model(s) to run, i.e. --model yolov5n yolov5s')
43 | opt = parser.parse_args()
44 |
45 | for m in opt.model:
46 | models[m] = torch.hub.load("ultralytics/yolov5", m, force_reload=True, skip_validation=True)
47 |
48 | app.run(host="0.0.0.0", port=opt.port) # debug=True causes Restarting with stat
49 |
--------------------------------------------------------------------------------
/utils/google_app_engine/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM gcr.io/google-appengine/python
2 |
3 | # Create a virtualenv for dependencies. This isolates these packages from
4 | # system-level packages.
5 | # Use -p python3 or -p python3.7 to select python version. Default is version 2.
6 | RUN virtualenv /env -p python3
7 |
8 | # Setting these environment variables are the same as running
9 | # source /env/bin/activate.
10 | ENV VIRTUAL_ENV /env
11 | ENV PATH /env/bin:$PATH
12 |
13 | RUN apt-get update && apt-get install -y python-opencv
14 |
15 | # Copy the application's requirements.txt and run pip to install all
16 | # dependencies into the virtualenv.
17 | ADD requirements.txt /app/requirements.txt
18 | RUN pip install -r /app/requirements.txt
19 |
20 | # Add the application source code.
21 | ADD . /app
22 |
23 | # Run a WSGI server to serve the application. gunicorn must be declared as
24 | # a dependency in requirements.txt.
25 | CMD gunicorn -b :$PORT main:app
26 |
--------------------------------------------------------------------------------
/utils/google_app_engine/additional_requirements.txt:
--------------------------------------------------------------------------------
1 | # add these requirements in your app on top of the existing ones
2 | pip==21.1
3 | Flask==1.0.2
4 | gunicorn==19.9.0
5 |
--------------------------------------------------------------------------------
/utils/google_app_engine/app.yaml:
--------------------------------------------------------------------------------
1 | runtime: custom
2 | env: flex
3 |
4 | service: yolov5app
5 |
6 | liveness_check:
7 | initial_delay_sec: 600
8 |
9 | manual_scaling:
10 | instances: 1
11 | resources:
12 | cpu: 1
13 | memory_gb: 4
14 | disk_size_gb: 20
15 |
--------------------------------------------------------------------------------
/utils/loggers/clearml/README.md:
--------------------------------------------------------------------------------
1 | # ClearML Integration
2 |
3 | 
4 |
5 | ## About ClearML
6 |
7 | [ClearML](https://cutt.ly/yolov5-tutorial-clearml) is an [open-source](https://github.com/allegroai/clearml) toolbox designed to save you time ⏱️.
8 |
9 | 🔨 Track every YOLOv5 training run in the experiment manager
10 |
11 | 🔧 Version and easily access your custom training data with the integrated ClearML Data Versioning Tool
12 |
13 | 🔦 Remotely train and monitor your YOLOv5 training runs using ClearML Agent
14 |
15 | 🔬 Get the very best mAP using ClearML Hyperparameter Optimization
16 |
17 | 🔭 Turn your newly trained YOLOv5 model into an API with just a few commands using ClearML Serving
18 |
19 |
20 | And so much more. It's up to you how many of these tools you want to use, you can stick to the experiment manager, or chain them all together into an impressive pipeline!
21 |
22 |
23 |
24 | 
25 |
26 |
27 |
28 |
29 |
30 | ## 🦾 Setting Things Up
31 |
32 | To keep track of your experiments and/or data, ClearML needs to communicate to a server. You have 2 options to get one:
33 |
34 | Either sign up for free to the [ClearML Hosted Service](https://cutt.ly/yolov5-tutorial-clearml) or you can set up your own server, see [here](https://clear.ml/docs/latest/docs/deploying_clearml/clearml_server). Even the server is open-source, so even if you're dealing with sensitive data, you should be good to go!
35 |
36 | 1. Install the `clearml` python package:
37 |
38 | ```bash
39 | pip install clearml
40 | ```
41 |
42 | 1. Connect the ClearML SDK to the server by [creating credentials](https://app.clear.ml/settings/workspace-configuration) (go right top to Settings -> Workspace -> Create new credentials), then execute the command below and follow the instructions:
43 |
44 | ```bash
45 | clearml-init
46 | ```
47 |
48 | That's it! You're done 😎
49 |
50 |
51 |
52 | ## 🚀 Training YOLOv5 With ClearML
53 |
54 | To enable ClearML experiment tracking, simply install the ClearML pip package.
55 |
56 | ```bash
57 | pip install clearml
58 | ```
59 |
60 | This will enable integration with the YOLOv5 training script. Every training run from now on, will be captured and stored by the ClearML experiment manager. If you want to change the `project_name` or `task_name`, head over to our custom logger, where you can change it: `utils/loggers/clearml/clearml_utils.py`
61 |
62 | ```bash
63 | python train.py --img 640 --batch 16 --epochs 3 --data coco128.yaml --weights yolov5s.pt --cache
64 | ```
65 |
66 | This will capture:
67 | - Source code + uncommitted changes
68 | - Installed packages
69 | - (Hyper)parameters
70 | - Model files (use `--save-period n` to save a checkpoint every n epochs)
71 | - Console output
72 | - Scalars (mAP_0.5, mAP_0.5:0.95, precision, recall, losses, learning rates, ...)
73 | - General info such as machine details, runtime, creation date etc.
74 | - All produced plots such as label correlogram and confusion matrix
75 | - Images with bounding boxes per epoch
76 | - Mosaic per epoch
77 | - Validation images per epoch
78 | - ...
79 |
80 | That's a lot right? 🤯
81 | Now, we can visualize all of this information in the ClearML UI to get an overview of our training progress. Add custom columns to the table view (such as e.g. mAP_0.5) so you can easily sort on the best performing model. Or select multiple experiments and directly compare them!
82 |
83 | There even more we can do with all of this information, like hyperparameter optimization and remote execution, so keep reading if you want to see how that works!
84 |
85 |
86 |
87 | ## 🔗 Dataset Version Management
88 |
89 | Versioning your data separately from your code is generally a good idea and makes it easy to aqcuire the latest version too. This repository supports supplying a dataset version ID and it will make sure to get the data if it's not there yet. Next to that, this workflow also saves the used dataset ID as part of the task parameters, so you will always know for sure which data was used in which experiment!
90 |
91 | 
92 |
93 | ### Prepare Your Dataset
94 |
95 | The YOLOv5 repository supports a number of different datasets by using yaml files containing their information. By default datasets are downloaded to the `../datasets` folder in relation to the repository root folder. So if you downloaded the `coco128` dataset using the link in the yaml or with the scripts provided by yolov5, you get this folder structure:
96 |
97 | ```
98 | ..
99 | |_ yolov5
100 | |_ datasets
101 | |_ coco128
102 | |_ images
103 | |_ labels
104 | |_ LICENSE
105 | |_ README.txt
106 | ```
107 | But this can be any dataset you wish. Feel free to use your own, as long as you keep to this folder structure.
108 |
109 | Next, ⚠️**copy the corresponding yaml file to the root of the dataset folder**⚠️. This yaml files contains the information ClearML will need to properly use the dataset. You can make this yourself too, of course, just follow the structure of the example yamls.
110 |
111 | Basically we need the following keys: `path`, `train`, `test`, `val`, `nc`, `names`.
112 |
113 | ```
114 | ..
115 | |_ yolov5
116 | |_ datasets
117 | |_ coco128
118 | |_ images
119 | |_ labels
120 | |_ coco128.yaml # <---- HERE!
121 | |_ LICENSE
122 | |_ README.txt
123 | ```
124 |
125 | ### Upload Your Dataset
126 |
127 | To get this dataset into ClearML as a versionned dataset, go to the dataset root folder and run the following command:
128 | ```bash
129 | cd coco128
130 | clearml-data sync --project YOLOv5 --name coco128 --folder .
131 | ```
132 |
133 | The command `clearml-data sync` is actually a shorthand command. You could also run these commands one after the other:
134 | ```bash
135 | # Optionally add --parent if you want to base
136 | # this version on another dataset version, so no duplicate files are uploaded!
137 | clearml-data create --name coco128 --project YOLOv5
138 | clearml-data add --files .
139 | clearml-data close
140 | ```
141 |
142 | ### Run Training Using A ClearML Dataset
143 |
144 | Now that you have a ClearML dataset, you can very simply use it to train custom YOLOv5 🚀 models!
145 |
146 | ```bash
147 | python train.py --img 640 --batch 16 --epochs 3 --data clearml:// --weights yolov5s.pt --cache
148 | ```
149 |
150 |
151 |
152 | ## 👀 Hyperparameter Optimization
153 |
154 | Now that we have our experiments and data versioned, it's time to take a look at what we can build on top!
155 |
156 | Using the code information, installed packages and environment details, the experiment itself is now **completely reproducible**. In fact, ClearML allows you to clone an experiment and even change its parameters. We can then just rerun it with these new parameters automatically, this is basically what HPO does!
157 |
158 | To **run hyperparameter optimization locally**, we've included a pre-made script for you. Just make sure a training task has been run at least once, so it is in the ClearML experiment manager, we will essentially clone it and change its hyperparameters.
159 |
160 | You'll need to fill in the ID of this `template task` in the script found at `utils/loggers/clearml/hpo.py` and then just run it :) You can change `task.execute_locally()` to `task.execute()` to put it in a ClearML queue and have a remote agent work on it instead.
161 |
162 | ```bash
163 | # To use optuna, install it first, otherwise you can change the optimizer to just be RandomSearch
164 | pip install optuna
165 | python utils/loggers/clearml/hpo.py
166 | ```
167 |
168 | 
169 |
170 | ## 🤯 Remote Execution (advanced)
171 |
172 | Running HPO locally is really handy, but what if we want to run our experiments on a remote machine instead? Maybe you have access to a very powerful GPU machine on-site or you have some budget to use cloud GPUs.
173 | This is where the ClearML Agent comes into play. Check out what the agent can do here:
174 |
175 | - [YouTube video](https://youtu.be/MX3BrXnaULs)
176 | - [Documentation](https://clear.ml/docs/latest/docs/clearml_agent)
177 |
178 | In short: every experiment tracked by the experiment manager contains enough information to reproduce it on a different machine (installed packages, uncommitted changes etc.). So a ClearML agent does just that: it listens to a queue for incoming tasks and when it finds one, it recreates the environment and runs it while still reporting scalars, plots etc. to the experiment manager.
179 |
180 | You can turn any machine (a cloud VM, a local GPU machine, your own laptop ... ) into a ClearML agent by simply running:
181 | ```bash
182 | clearml-agent daemon --queue [--docker]
183 | ```
184 |
185 | ### Cloning, Editing And Enqueuing
186 |
187 | With our agent running, we can give it some work. Remember from the HPO section that we can clone a task and edit the hyperparameters? We can do that from the interface too!
188 |
189 | 🪄 Clone the experiment by right clicking it
190 |
191 | 🎯 Edit the hyperparameters to what you wish them to be
192 |
193 | ⏳ Enqueue the task to any of the queues by right clicking it
194 |
195 | 
196 |
197 | ### Executing A Task Remotely
198 |
199 | Now you can clone a task like we explained above, or simply mark your current script by adding `task.execute_remotely()` and on execution it will be put into a queue, for the agent to start working on!
200 |
201 | To run the YOLOv5 training script remotely, all you have to do is add this line to the training.py script after the clearml logger has been instatiated:
202 | ```python
203 | # ...
204 | # Loggers
205 | data_dict = None
206 | if RANK in {-1, 0}:
207 | loggers = Loggers(save_dir, weights, opt, hyp, LOGGER) # loggers instance
208 | if loggers.clearml:
209 | loggers.clearml.task.execute_remotely(queue='my_queue') # <------ ADD THIS LINE
210 | # Data_dict is either None is user did not choose for ClearML dataset or is filled in by ClearML
211 | data_dict = loggers.clearml.data_dict
212 | # ...
213 | ```
214 | When running the training script after this change, python will run the script up until that line, after which it will package the code and send it to the queue instead!
215 |
216 | ### Autoscaling workers
217 |
218 | ClearML comes with autoscalers too! This tool will automatically spin up new remote machines in the cloud of your choice (AWS, GCP, Azure) and turn them into ClearML agents for you whenever there are experiments detected in the queue. Once the tasks are processed, the autoscaler will automatically shut down the remote machines and you stop paying!
219 |
220 | Check out the autoscalers getting started video below.
221 |
222 | [](https://youtu.be/j4XVMAaUt3E)
223 |
--------------------------------------------------------------------------------
/utils/loggers/clearml/__init__.py:
--------------------------------------------------------------------------------
1 | # init
--------------------------------------------------------------------------------
/utils/loggers/clearml/clearml_utils.py:
--------------------------------------------------------------------------------
1 | """Main Logger class for ClearML experiment tracking."""
2 | import glob
3 | import re
4 | from pathlib import Path
5 |
6 | import numpy as np
7 | import yaml
8 |
9 | from utils.plots import Annotator, colors
10 |
11 | try:
12 | import clearml
13 | from clearml import Dataset, Task
14 | assert hasattr(clearml, '__version__') # verify package import not local dir
15 | except (ImportError, AssertionError):
16 | clearml = None
17 |
18 |
19 | def construct_dataset(clearml_info_string):
20 | """Load in a clearml dataset and fill the internal data_dict with its contents.
21 | """
22 | dataset_id = clearml_info_string.replace('clearml://', '')
23 | dataset = Dataset.get(dataset_id=dataset_id)
24 | dataset_root_path = Path(dataset.get_local_copy())
25 |
26 | # We'll search for the yaml file definition in the dataset
27 | yaml_filenames = list(glob.glob(str(dataset_root_path / "*.yaml")) + glob.glob(str(dataset_root_path / "*.yml")))
28 | if len(yaml_filenames) > 1:
29 | raise ValueError('More than one yaml file was found in the dataset root, cannot determine which one contains '
30 | 'the dataset definition this way.')
31 | elif len(yaml_filenames) == 0:
32 | raise ValueError('No yaml definition found in dataset root path, check that there is a correct yaml file '
33 | 'inside the dataset root path.')
34 | with open(yaml_filenames[0]) as f:
35 | dataset_definition = yaml.safe_load(f)
36 |
37 | assert set(dataset_definition.keys()).issuperset(
38 | {'train', 'test', 'val', 'nc', 'names'}
39 | ), "The right keys were not found in the yaml file, make sure it at least has the following keys: ('train', 'test', 'val', 'nc', 'names')"
40 |
41 | data_dict = dict()
42 | data_dict['train'] = str(
43 | (dataset_root_path / dataset_definition['train']).resolve()) if dataset_definition['train'] else None
44 | data_dict['test'] = str(
45 | (dataset_root_path / dataset_definition['test']).resolve()) if dataset_definition['test'] else None
46 | data_dict['val'] = str(
47 | (dataset_root_path / dataset_definition['val']).resolve()) if dataset_definition['val'] else None
48 | data_dict['nc'] = dataset_definition['nc']
49 | data_dict['names'] = dataset_definition['names']
50 |
51 | return data_dict
52 |
53 |
54 | class ClearmlLogger:
55 | """Log training runs, datasets, models, and predictions to ClearML.
56 |
57 | This logger sends information to ClearML at app.clear.ml or to your own hosted server. By default,
58 | this information includes hyperparameters, system configuration and metrics, model metrics, code information and
59 | basic data metrics and analyses.
60 |
61 | By providing additional command line arguments to train.py, datasets,
62 | models and predictions can also be logged.
63 | """
64 |
65 | def __init__(self, opt, hyp):
66 | """
67 | - Initialize ClearML Task, this object will capture the experiment
68 | - Upload dataset version to ClearML Data if opt.upload_dataset is True
69 |
70 | arguments:
71 | opt (namespace) -- Commandline arguments for this run
72 | hyp (dict) -- Hyperparameters for this run
73 |
74 | """
75 | self.current_epoch = 0
76 | # Keep tracked of amount of logged images to enforce a limit
77 | self.current_epoch_logged_images = set()
78 | # Maximum number of images to log to clearML per epoch
79 | self.max_imgs_to_log_per_epoch = 16
80 | # Get the interval of epochs when bounding box images should be logged
81 | self.bbox_interval = opt.bbox_interval
82 | self.clearml = clearml
83 | self.task = None
84 | self.data_dict = None
85 | if self.clearml:
86 | self.task = Task.init(
87 | project_name='YOLOv5',
88 | task_name='training',
89 | tags=['YOLOv5'],
90 | output_uri=True,
91 | auto_connect_frameworks={'pytorch': False}
92 | # We disconnect pytorch auto-detection, because we added manual model save points in the code
93 | )
94 | # ClearML's hooks will already grab all general parameters
95 | # Only the hyperparameters coming from the yaml config file
96 | # will have to be added manually!
97 | self.task.connect(hyp, name='Hyperparameters')
98 |
99 | # Get ClearML Dataset Version if requested
100 | if opt.data.startswith('clearml://'):
101 | # data_dict should have the following keys:
102 | # names, nc (number of classes), test, train, val (all three relative paths to ../datasets)
103 | self.data_dict = construct_dataset(opt.data)
104 | # Set data to data_dict because wandb will crash without this information and opt is the best way
105 | # to give it to them
106 | opt.data = self.data_dict
107 |
108 | def log_debug_samples(self, files, title='Debug Samples'):
109 | """
110 | Log files (images) as debug samples in the ClearML task.
111 |
112 | arguments:
113 | files (List(PosixPath)) a list of file paths in PosixPath format
114 | title (str) A title that groups together images with the same values
115 | """
116 | for f in files:
117 | if f.exists():
118 | it = re.search(r'_batch(\d+)', f.name)
119 | iteration = int(it.groups()[0]) if it else 0
120 | self.task.get_logger().report_image(title=title,
121 | series=f.name.replace(it.group(), ''),
122 | local_path=str(f),
123 | iteration=iteration)
124 |
125 | def log_image_with_boxes(self, image_path, boxes, class_names, image, conf_threshold=0.25):
126 | """
127 | Draw the bounding boxes on a single image and report the result as a ClearML debug sample.
128 |
129 | arguments:
130 | image_path (PosixPath) the path the original image file
131 | boxes (list): list of scaled predictions in the format - [xmin, ymin, xmax, ymax, confidence, class]
132 | class_names (dict): dict containing mapping of class int to class name
133 | image (Tensor): A torch tensor containing the actual image data
134 | """
135 | if len(self.current_epoch_logged_images) < self.max_imgs_to_log_per_epoch and self.current_epoch >= 0:
136 | # Log every bbox_interval times and deduplicate for any intermittend extra eval runs
137 | if self.current_epoch % self.bbox_interval == 0 and image_path not in self.current_epoch_logged_images:
138 | im = np.ascontiguousarray(np.moveaxis(image.mul(255).clamp(0, 255).byte().cpu().numpy(), 0, 2))
139 | annotator = Annotator(im=im, pil=True)
140 | for i, (conf, class_nr, box) in enumerate(zip(boxes[:, 4], boxes[:, 5], boxes[:, :4])):
141 | color = colors(i)
142 |
143 | class_name = class_names[int(class_nr)]
144 | confidence_percentage = round(float(conf) * 100, 2)
145 | label = f"{class_name}: {confidence_percentage}%"
146 |
147 | if conf > conf_threshold:
148 | annotator.rectangle(box.cpu().numpy(), outline=color)
149 | annotator.box_label(box.cpu().numpy(), label=label, color=color)
150 |
151 | annotated_image = annotator.result()
152 | self.task.get_logger().report_image(title='Bounding Boxes',
153 | series=image_path.name,
154 | iteration=self.current_epoch,
155 | image=annotated_image)
156 | self.current_epoch_logged_images.add(image_path)
157 |
--------------------------------------------------------------------------------
/utils/loggers/clearml/hpo.py:
--------------------------------------------------------------------------------
1 | from clearml import Task
2 | # Connecting ClearML with the current process,
3 | # from here on everything is logged automatically
4 | from clearml.automation import HyperParameterOptimizer, UniformParameterRange
5 | from clearml.automation.optuna import OptimizerOptuna
6 |
7 | task = Task.init(project_name='Hyper-Parameter Optimization',
8 | task_name='YOLOv5',
9 | task_type=Task.TaskTypes.optimizer,
10 | reuse_last_task_id=False)
11 |
12 | # Example use case:
13 | optimizer = HyperParameterOptimizer(
14 | # This is the experiment we want to optimize
15 | base_task_id='',
16 | # here we define the hyper-parameters to optimize
17 | # Notice: The parameter name should exactly match what you see in the UI: /
18 | # For Example, here we see in the base experiment a section Named: "General"
19 | # under it a parameter named "batch_size", this becomes "General/batch_size"
20 | # If you have `argparse` for example, then arguments will appear under the "Args" section,
21 | # and you should instead pass "Args/batch_size"
22 | hyper_parameters=[
23 | UniformParameterRange('Hyperparameters/lr0', min_value=1e-5, max_value=1e-1),
24 | UniformParameterRange('Hyperparameters/lrf', min_value=0.01, max_value=1.0),
25 | UniformParameterRange('Hyperparameters/momentum', min_value=0.6, max_value=0.98),
26 | UniformParameterRange('Hyperparameters/weight_decay', min_value=0.0, max_value=0.001),
27 | UniformParameterRange('Hyperparameters/warmup_epochs', min_value=0.0, max_value=5.0),
28 | UniformParameterRange('Hyperparameters/warmup_momentum', min_value=0.0, max_value=0.95),
29 | UniformParameterRange('Hyperparameters/warmup_bias_lr', min_value=0.0, max_value=0.2),
30 | UniformParameterRange('Hyperparameters/box', min_value=0.02, max_value=0.2),
31 | UniformParameterRange('Hyperparameters/cls', min_value=0.2, max_value=4.0),
32 | UniformParameterRange('Hyperparameters/cls_pw', min_value=0.5, max_value=2.0),
33 | UniformParameterRange('Hyperparameters/obj', min_value=0.2, max_value=4.0),
34 | UniformParameterRange('Hyperparameters/obj_pw', min_value=0.5, max_value=2.0),
35 | UniformParameterRange('Hyperparameters/iou_t', min_value=0.1, max_value=0.7),
36 | UniformParameterRange('Hyperparameters/anchor_t', min_value=2.0, max_value=8.0),
37 | UniformParameterRange('Hyperparameters/fl_gamma', min_value=0.0, max_value=4.0),
38 | UniformParameterRange('Hyperparameters/hsv_h', min_value=0.0, max_value=0.1),
39 | UniformParameterRange('Hyperparameters/hsv_s', min_value=0.0, max_value=0.9),
40 | UniformParameterRange('Hyperparameters/hsv_v', min_value=0.0, max_value=0.9),
41 | UniformParameterRange('Hyperparameters/degrees', min_value=0.0, max_value=45.0),
42 | UniformParameterRange('Hyperparameters/translate', min_value=0.0, max_value=0.9),
43 | UniformParameterRange('Hyperparameters/scale', min_value=0.0, max_value=0.9),
44 | UniformParameterRange('Hyperparameters/shear', min_value=0.0, max_value=10.0),
45 | UniformParameterRange('Hyperparameters/perspective', min_value=0.0, max_value=0.001),
46 | UniformParameterRange('Hyperparameters/flipud', min_value=0.0, max_value=1.0),
47 | UniformParameterRange('Hyperparameters/fliplr', min_value=0.0, max_value=1.0),
48 | UniformParameterRange('Hyperparameters/mosaic', min_value=0.0, max_value=1.0),
49 | UniformParameterRange('Hyperparameters/mixup', min_value=0.0, max_value=1.0),
50 | UniformParameterRange('Hyperparameters/copy_paste', min_value=0.0, max_value=1.0)],
51 | # this is the objective metric we want to maximize/minimize
52 | objective_metric_title='metrics',
53 | objective_metric_series='mAP_0.5',
54 | # now we decide if we want to maximize it or minimize it (accuracy we maximize)
55 | objective_metric_sign='max',
56 | # let us limit the number of concurrent experiments,
57 | # this in turn will make sure we do dont bombard the scheduler with experiments.
58 | # if we have an auto-scaler connected, this, by proxy, will limit the number of machine
59 | max_number_of_concurrent_tasks=1,
60 | # this is the optimizer class (actually doing the optimization)
61 | # Currently, we can choose from GridSearch, RandomSearch or OptimizerBOHB (Bayesian optimization Hyper-Band)
62 | optimizer_class=OptimizerOptuna,
63 | # If specified only the top K performing Tasks will be kept, the others will be automatically archived
64 | save_top_k_tasks_only=5, # 5,
65 | compute_time_limit=None,
66 | total_max_jobs=20,
67 | min_iteration_per_job=None,
68 | max_iteration_per_job=None,
69 | )
70 |
71 | # report every 10 seconds, this is way too often, but we are testing here
72 | optimizer.set_report_period(10)
73 | # You can also use the line below instead to run all the optimizer tasks locally, without using queues or agent
74 | # an_optimizer.start_locally(job_complete_callback=job_complete_callback)
75 | # set the time limit for the optimization process (2 hours)
76 | optimizer.set_time_limit(in_minutes=120.0)
77 | # Start the optimization process in the local environment
78 | optimizer.start_locally()
79 | # wait until process is done (notice we are controlling the optimization process in the background)
80 | optimizer.wait()
81 | # make sure background optimization stopped
82 | optimizer.stop()
83 |
84 | print('We are done, good bye')
85 |
--------------------------------------------------------------------------------
/utils/loggers/wandb/README.md:
--------------------------------------------------------------------------------
1 | 📚 This guide explains how to use **Weights & Biases** (W&B) with YOLOv5 🚀. UPDATED 29 September 2021.
2 |
3 | - [About Weights & Biases](#about-weights-&-biases)
4 | - [First-Time Setup](#first-time-setup)
5 | - [Viewing runs](#viewing-runs)
6 | - [Disabling wandb](#disabling-wandb)
7 | - [Advanced Usage: Dataset Versioning and Evaluation](#advanced-usage)
8 | - [Reports: Share your work with the world!](#reports)
9 |
10 | ## About Weights & Biases
11 |
12 | Think of [W&B](https://wandb.ai/site?utm_campaign=repo_yolo_wandbtutorial) like GitHub for machine learning models. With a few lines of code, save everything you need to debug, compare and reproduce your models — architecture, hyperparameters, git commits, model weights, GPU usage, and even datasets and predictions.
13 |
14 | Used by top researchers including teams at OpenAI, Lyft, Github, and MILA, W&B is part of the new standard of best practices for machine learning. How W&B can help you optimize your machine learning workflows:
15 |
16 | - [Debug](https://wandb.ai/wandb/getting-started/reports/Visualize-Debug-Machine-Learning-Models--VmlldzoyNzY5MDk#Free-2) model performance in real time
17 | - [GPU usage](https://wandb.ai/wandb/getting-started/reports/Visualize-Debug-Machine-Learning-Models--VmlldzoyNzY5MDk#System-4) visualized automatically
18 | - [Custom charts](https://wandb.ai/wandb/customizable-charts/reports/Powerful-Custom-Charts-To-Debug-Model-Peformance--VmlldzoyNzY4ODI) for powerful, extensible visualization
19 | - [Share insights](https://wandb.ai/wandb/getting-started/reports/Visualize-Debug-Machine-Learning-Models--VmlldzoyNzY5MDk#Share-8) interactively with collaborators
20 | - [Optimize hyperparameters](https://docs.wandb.com/sweeps) efficiently
21 | - [Track](https://docs.wandb.com/artifacts) datasets, pipelines, and production models
22 |
23 | ## First-Time Setup
24 |
25 |
26 | Toggle Details
27 | When you first train, W&B will prompt you to create a new account and will generate an **API key** for you. If you are an existing user you can retrieve your key from https://wandb.ai/authorize. This key is used to tell W&B where to log your data. You only need to supply your key once, and then it is remembered on the same device.
28 |
29 | W&B will create a cloud **project** (default is 'YOLOv5') for your training runs, and each new training run will be provided a unique run **name** within that project as project/name. You can also manually set your project and run name as:
30 |
31 | ```shell
32 | $ python train.py --project ... --name ...
33 | ```
34 |
35 | YOLOv5 notebook example:
36 |
37 |
38 |
39 |
40 | ## Viewing Runs
41 |
42 |
43 | Toggle Details
44 | Run information streams from your environment to the W&B cloud console as you train. This allows you to monitor and even cancel runs in realtime . All important information is logged:
45 |
46 | - Training & Validation losses
47 | - Metrics: Precision, Recall, mAP@0.5, mAP@0.5:0.95
48 | - Learning Rate over time
49 | - A bounding box debugging panel, showing the training progress over time
50 | - GPU: Type, **GPU Utilization**, power, temperature, **CUDA memory usage**
51 | - System: Disk I/0, CPU utilization, RAM memory usage
52 | - Your trained model as W&B Artifact
53 | - Environment: OS and Python types, Git repository and state, **training command**
54 |
55 | 
56 |
57 |
58 | ## Disabling wandb
59 |
60 | - training after running `wandb disabled` inside that directory creates no wandb run
61 | 
62 |
63 | - To enable wandb again, run `wandb online`
64 | 
65 |
66 | ## Advanced Usage
67 |
68 | You can leverage W&B artifacts and Tables integration to easily visualize and manage your datasets, models and training evaluations. Here are some quick examples to get you started.
69 |
70 |
71 | 1: Train and Log Evaluation simultaneousy
72 | This is an extension of the previous section, but it'll also training after uploading the dataset. This also evaluation Table
73 | Evaluation table compares your predictions and ground truths across the validation set for each epoch. It uses the references to the already uploaded datasets,
74 | so no images will be uploaded from your system more than once.
75 |
76 | Usage
77 | Code $ python train.py --upload_data val
78 |
79 | 
80 |
81 |
82 |
83 | 2. Visualize and Version Datasets
84 | Log, visualize, dynamically query, and understand your data with W&B Tables. You can use the following command to log your dataset as a W&B Table. This will generate a {dataset}_wandb.yaml
file which can be used to train from dataset artifact.
85 |
86 | Usage
87 | Code $ python utils/logger/wandb/log_dataset.py --project ... --name ... --data ..
88 |
89 | 
90 |
91 |
92 |
93 | 3: Train using dataset artifact
94 | When you upload a dataset as described in the first section, you get a new config file with an added `_wandb` to its name. This file contains the information that
95 | can be used to train a model directly from the dataset artifact. This also logs evaluation
96 |
97 | Usage
98 | Code $ python train.py --data {data}_wandb.yaml
99 |
100 | 
101 |
102 |
103 |
104 | 4: Save model checkpoints as artifacts
105 | To enable saving and versioning checkpoints of your experiment, pass `--save_period n` with the base cammand, where `n` represents checkpoint interval.
106 | You can also log both the dataset and model checkpoints simultaneously. If not passed, only the final model will be logged
107 |
108 |
109 | Usage
110 | Code $ python train.py --save_period 1
111 |
112 | 
113 |
114 |
115 |
116 |
117 |
118 | 5: Resume runs from checkpoint artifacts.
119 | Any run can be resumed using artifacts if the --resume
argument starts with wandb-artifact://
prefix followed by the run path, i.e, wandb-artifact://username/project/runid
. This doesn't require the model checkpoint to be present on the local system.
120 |
121 |
122 | Usage
123 | Code $ python train.py --resume wandb-artifact://{run_path}
124 |
125 | 
126 |
127 |
128 |
129 | 6: Resume runs from dataset artifact & checkpoint artifacts.
130 | Local dataset or model checkpoints are not required. This can be used to resume runs directly on a different device
131 | The syntax is same as the previous section, but you'll need to lof both the dataset and model checkpoints as artifacts, i.e, set bot --upload_dataset
or
132 | train from _wandb.yaml
file and set --save_period
133 |
134 |
135 | Usage
136 | Code $ python train.py --resume wandb-artifact://{run_path}
137 |
138 | 
139 |
140 |
141 |
142 |
143 |
144 | Reports
145 | W&B Reports can be created from your saved runs for sharing online. Once a report is created you will receive a link you can use to publically share your results. Here is an example report created from the COCO128 tutorial trainings of all four YOLOv5 models ([link](https://wandb.ai/glenn-jocher/yolov5_tutorial/reports/YOLOv5-COCO128-Tutorial-Results--VmlldzozMDI5OTY)).
146 |
147 |
148 |
149 | ## Environments
150 |
151 | YOLOv5 may be run in any of the following up-to-date verified environments (with all dependencies including [CUDA](https://developer.nvidia.com/cuda)/[CUDNN](https://developer.nvidia.com/cudnn), [Python](https://www.python.org/) and [PyTorch](https://pytorch.org/) preinstalled):
152 |
153 | - **Google Colab and Kaggle** notebooks with free GPU:
154 | - **Google Cloud** Deep Learning VM. See [GCP Quickstart Guide](https://github.com/ultralytics/yolov5/wiki/GCP-Quickstart)
155 | - **Amazon** Deep Learning AMI. See [AWS Quickstart Guide](https://github.com/ultralytics/yolov5/wiki/AWS-Quickstart)
156 | - **Docker Image**. See [Docker Quickstart Guide](https://github.com/ultralytics/yolov5/wiki/Docker-Quickstart)
157 |
158 | ## Status
159 |
160 | 
161 |
162 | If this badge is green, all [YOLOv5 GitHub Actions](https://github.com/ultralytics/yolov5/actions) Continuous Integration (CI) tests are currently passing. CI tests verify correct operation of YOLOv5 training ([train.py](https://github.com/ultralytics/yolov5/blob/master/train.py)), validation ([val.py](https://github.com/ultralytics/yolov5/blob/master/val.py)), inference ([detect.py](https://github.com/ultralytics/yolov5/blob/master/detect.py)) and export ([export.py](https://github.com/ultralytics/yolov5/blob/master/export.py)) on macOS, Windows, and Ubuntu every 24 hours and on every commit.
163 |
--------------------------------------------------------------------------------
/utils/loggers/wandb/__init__.py:
--------------------------------------------------------------------------------
1 | # init
--------------------------------------------------------------------------------
/utils/loggers/wandb/log_dataset.py:
--------------------------------------------------------------------------------
1 | import argparse
2 |
3 | from wandb_utils import WandbLogger
4 |
5 | from utils.general import LOGGER
6 |
7 | WANDB_ARTIFACT_PREFIX = 'wandb-artifact://'
8 |
9 |
10 | def create_dataset_artifact(opt):
11 | logger = WandbLogger(opt, None, job_type='Dataset Creation') # TODO: return value unused
12 | if not logger.wandb:
13 | LOGGER.info("install wandb using `pip install wandb` to log the dataset")
14 |
15 |
16 | if __name__ == '__main__':
17 | parser = argparse.ArgumentParser()
18 | parser.add_argument('--data', type=str, default='data/coco128.yaml', help='data.yaml path')
19 | parser.add_argument('--single-cls', action='store_true', help='train as single-class dataset')
20 | parser.add_argument('--project', type=str, default='YOLOv5', help='name of W&B Project')
21 | parser.add_argument('--entity', default=None, help='W&B entity')
22 | parser.add_argument('--name', type=str, default='log dataset', help='name of W&B run')
23 |
24 | opt = parser.parse_args()
25 | opt.resume = False # Explicitly disallow resume check for dataset upload job
26 |
27 | create_dataset_artifact(opt)
28 |
--------------------------------------------------------------------------------
/utils/loggers/wandb/sweep.py:
--------------------------------------------------------------------------------
1 | import sys
2 | from pathlib import Path
3 |
4 | import wandb
5 |
6 | FILE = Path(__file__).resolve()
7 | ROOT = FILE.parents[3] # YOLOv5 root directory
8 | if str(ROOT) not in sys.path:
9 | sys.path.append(str(ROOT)) # add ROOT to PATH
10 |
11 | from train import parse_opt, train
12 | from utils.callbacks import Callbacks
13 | from utils.general import increment_path
14 | from utils.torch_utils import select_device
15 |
16 |
17 | def sweep():
18 | wandb.init()
19 | # Get hyp dict from sweep agent. Copy because train() modifies parameters which confused wandb.
20 | hyp_dict = vars(wandb.config).get("_items").copy()
21 |
22 | # Workaround: get necessary opt args
23 | opt = parse_opt(known=True)
24 | opt.batch_size = hyp_dict.get("batch_size")
25 | opt.save_dir = str(increment_path(Path(opt.project) / opt.name, exist_ok=opt.exist_ok or opt.evolve))
26 | opt.epochs = hyp_dict.get("epochs")
27 | opt.nosave = True
28 | opt.data = hyp_dict.get("data")
29 | opt.weights = str(opt.weights)
30 | opt.cfg = str(opt.cfg)
31 | opt.data = str(opt.data)
32 | opt.hyp = str(opt.hyp)
33 | opt.project = str(opt.project)
34 | device = select_device(opt.device, batch_size=opt.batch_size)
35 |
36 | # train
37 | train(hyp_dict, opt, device, callbacks=Callbacks())
38 |
39 |
40 | if __name__ == "__main__":
41 | sweep()
42 |
--------------------------------------------------------------------------------
/utils/loggers/wandb/sweep.yaml:
--------------------------------------------------------------------------------
1 | # Hyperparameters for training
2 | # To set range-
3 | # Provide min and max values as:
4 | # parameter:
5 | #
6 | # min: scalar
7 | # max: scalar
8 | # OR
9 | #
10 | # Set a specific list of search space-
11 | # parameter:
12 | # values: [scalar1, scalar2, scalar3...]
13 | #
14 | # You can use grid, bayesian and hyperopt search strategy
15 | # For more info on configuring sweeps visit - https://docs.wandb.ai/guides/sweeps/configuration
16 |
17 | program: utils/loggers/wandb/sweep.py
18 | method: random
19 | metric:
20 | name: metrics/mAP_0.5
21 | goal: maximize
22 |
23 | parameters:
24 | # hyperparameters: set either min, max range or values list
25 | data:
26 | value: "data/coco128.yaml"
27 | batch_size:
28 | values: [64]
29 | epochs:
30 | values: [10]
31 |
32 | lr0:
33 | distribution: uniform
34 | min: 1e-5
35 | max: 1e-1
36 | lrf:
37 | distribution: uniform
38 | min: 0.01
39 | max: 1.0
40 | momentum:
41 | distribution: uniform
42 | min: 0.6
43 | max: 0.98
44 | weight_decay:
45 | distribution: uniform
46 | min: 0.0
47 | max: 0.001
48 | warmup_epochs:
49 | distribution: uniform
50 | min: 0.0
51 | max: 5.0
52 | warmup_momentum:
53 | distribution: uniform
54 | min: 0.0
55 | max: 0.95
56 | warmup_bias_lr:
57 | distribution: uniform
58 | min: 0.0
59 | max: 0.2
60 | box:
61 | distribution: uniform
62 | min: 0.02
63 | max: 0.2
64 | cls:
65 | distribution: uniform
66 | min: 0.2
67 | max: 4.0
68 | cls_pw:
69 | distribution: uniform
70 | min: 0.5
71 | max: 2.0
72 | obj:
73 | distribution: uniform
74 | min: 0.2
75 | max: 4.0
76 | obj_pw:
77 | distribution: uniform
78 | min: 0.5
79 | max: 2.0
80 | iou_t:
81 | distribution: uniform
82 | min: 0.1
83 | max: 0.7
84 | anchor_t:
85 | distribution: uniform
86 | min: 2.0
87 | max: 8.0
88 | fl_gamma:
89 | distribution: uniform
90 | min: 0.0
91 | max: 4.0
92 | hsv_h:
93 | distribution: uniform
94 | min: 0.0
95 | max: 0.1
96 | hsv_s:
97 | distribution: uniform
98 | min: 0.0
99 | max: 0.9
100 | hsv_v:
101 | distribution: uniform
102 | min: 0.0
103 | max: 0.9
104 | degrees:
105 | distribution: uniform
106 | min: 0.0
107 | max: 45.0
108 | translate:
109 | distribution: uniform
110 | min: 0.0
111 | max: 0.9
112 | scale:
113 | distribution: uniform
114 | min: 0.0
115 | max: 0.9
116 | shear:
117 | distribution: uniform
118 | min: 0.0
119 | max: 10.0
120 | perspective:
121 | distribution: uniform
122 | min: 0.0
123 | max: 0.001
124 | flipud:
125 | distribution: uniform
126 | min: 0.0
127 | max: 1.0
128 | fliplr:
129 | distribution: uniform
130 | min: 0.0
131 | max: 1.0
132 | mosaic:
133 | distribution: uniform
134 | min: 0.0
135 | max: 1.0
136 | mixup:
137 | distribution: uniform
138 | min: 0.0
139 | max: 1.0
140 | copy_paste:
141 | distribution: uniform
142 | min: 0.0
143 | max: 1.0
144 |
--------------------------------------------------------------------------------
/utils/loss.py:
--------------------------------------------------------------------------------
1 | # YOLOv5 🚀 by Ultralytics, GPL-3.0 license
2 | """
3 | Loss functions
4 | """
5 |
6 | import torch
7 | import torch.nn as nn
8 |
9 | from utils.metrics import bbox_iou
10 | from utils.torch_utils import de_parallel
11 |
12 |
13 | def smooth_BCE(eps=0.1): # https://github.com/ultralytics/yolov3/issues/238#issuecomment-598028441
14 | # return positive, negative label smoothing BCE targets
15 | return 1.0 - 0.5 * eps, 0.5 * eps
16 |
17 |
18 | class BCEBlurWithLogitsLoss(nn.Module):
19 | # BCEwithLogitLoss() with reduced missing label effects.
20 | def __init__(self, alpha=0.05):
21 | super().__init__()
22 | self.loss_fcn = nn.BCEWithLogitsLoss(reduction='none') # must be nn.BCEWithLogitsLoss()
23 | self.alpha = alpha
24 |
25 | def forward(self, pred, true):
26 | loss = self.loss_fcn(pred, true)
27 | pred = torch.sigmoid(pred) # prob from logits
28 | dx = pred - true # reduce only missing label effects
29 | # dx = (pred - true).abs() # reduce missing label and false label effects
30 | alpha_factor = 1 - torch.exp((dx - 1) / (self.alpha + 1e-4))
31 | loss *= alpha_factor
32 | return loss.mean()
33 |
34 |
35 | class FocalLoss(nn.Module):
36 | # Wraps focal loss around existing loss_fcn(), i.e. criteria = FocalLoss(nn.BCEWithLogitsLoss(), gamma=1.5)
37 | def __init__(self, loss_fcn, gamma=1.5, alpha=0.25):
38 | super().__init__()
39 | self.loss_fcn = loss_fcn # must be nn.BCEWithLogitsLoss()
40 | self.gamma = gamma
41 | self.alpha = alpha
42 | self.reduction = loss_fcn.reduction
43 | self.loss_fcn.reduction = 'none' # required to apply FL to each element
44 |
45 | def forward(self, pred, true):
46 | loss = self.loss_fcn(pred, true)
47 | # p_t = torch.exp(-loss)
48 | # loss *= self.alpha * (1.000001 - p_t) ** self.gamma # non-zero power for gradient stability
49 |
50 | # TF implementation https://github.com/tensorflow/addons/blob/v0.7.1/tensorflow_addons/losses/focal_loss.py
51 | pred_prob = torch.sigmoid(pred) # prob from logits
52 | p_t = true * pred_prob + (1 - true) * (1 - pred_prob)
53 | alpha_factor = true * self.alpha + (1 - true) * (1 - self.alpha)
54 | modulating_factor = (1.0 - p_t) ** self.gamma
55 | loss *= alpha_factor * modulating_factor
56 |
57 | if self.reduction == 'mean':
58 | return loss.mean()
59 | elif self.reduction == 'sum':
60 | return loss.sum()
61 | else: # 'none'
62 | return loss
63 |
64 |
65 | class QFocalLoss(nn.Module):
66 | # Wraps Quality focal loss around existing loss_fcn(), i.e. criteria = FocalLoss(nn.BCEWithLogitsLoss(), gamma=1.5)
67 | def __init__(self, loss_fcn, gamma=1.5, alpha=0.25):
68 | super().__init__()
69 | self.loss_fcn = loss_fcn # must be nn.BCEWithLogitsLoss()
70 | self.gamma = gamma
71 | self.alpha = alpha
72 | self.reduction = loss_fcn.reduction
73 | self.loss_fcn.reduction = 'none' # required to apply FL to each element
74 |
75 | def forward(self, pred, true):
76 | loss = self.loss_fcn(pred, true)
77 |
78 | pred_prob = torch.sigmoid(pred) # prob from logits
79 | alpha_factor = true * self.alpha + (1 - true) * (1 - self.alpha)
80 | modulating_factor = torch.abs(true - pred_prob) ** self.gamma
81 | loss *= alpha_factor * modulating_factor
82 |
83 | if self.reduction == 'mean':
84 | return loss.mean()
85 | elif self.reduction == 'sum':
86 | return loss.sum()
87 | else: # 'none'
88 | return loss
89 |
90 |
91 | class ComputeLoss:
92 | sort_obj_iou = False
93 |
94 | # Compute losses
95 | def __init__(self, model, autobalance=False):
96 | device = next(model.parameters()).device # get model device
97 | h = model.hyp # hyperparameters
98 |
99 | # Define criteria
100 | BCEcls = nn.BCEWithLogitsLoss(pos_weight=torch.tensor([h['cls_pw']], device=device))
101 | BCEobj = nn.BCEWithLogitsLoss(pos_weight=torch.tensor([h['obj_pw']], device=device))
102 |
103 | # Class label smoothing https://arxiv.org/pdf/1902.04103.pdf eqn 3
104 | self.cp, self.cn = smooth_BCE(eps=h.get('label_smoothing', 0.0)) # positive, negative BCE targets
105 |
106 | # Focal loss
107 | g = h['fl_gamma'] # focal loss gamma
108 | if g > 0:
109 | BCEcls, BCEobj = FocalLoss(BCEcls, g), FocalLoss(BCEobj, g)
110 |
111 | m = de_parallel(model).model[-1] # Detect() module
112 | self.balance = {3: [4.0, 1.0, 0.4]}.get(m.nl, [4.0, 1.0, 0.25, 0.06, 0.02]) # P3-P7
113 | self.ssi = list(m.stride).index(16) if autobalance else 0 # stride 16 index
114 | self.BCEcls, self.BCEobj, self.gr, self.hyp, self.autobalance = BCEcls, BCEobj, 1.0, h, autobalance
115 | self.na = m.na # number of anchors
116 | self.nc = m.nc # number of classes
117 | self.nl = m.nl # number of layers
118 | self.anchors = m.anchors
119 | self.device = device
120 |
121 | def __call__(self, p, targets): # predictions, targets
122 | lcls = torch.zeros(1, device=self.device) # class loss
123 | lbox = torch.zeros(1, device=self.device) # box loss
124 | lobj = torch.zeros(1, device=self.device) # object loss
125 | tcls, tbox, indices, anchors = self.build_targets(p, targets) # targets
126 |
127 | # Losses
128 | for i, pi in enumerate(p): # layer index, layer predictions
129 | b, a, gj, gi = indices[i] # image, anchor, gridy, gridx
130 | tobj = torch.zeros(pi.shape[:4], dtype=pi.dtype, device=self.device) # target obj
131 |
132 | n = b.shape[0] # number of targets
133 | if n:
134 | # pxy, pwh, _, pcls = pi[b, a, gj, gi].tensor_split((2, 4, 5), dim=1) # faster, requires torch 1.8.0
135 | pxy, pwh, _, pcls = pi[b, a, gj, gi].split((2, 2, 1, self.nc), 1) # target-subset of predictions
136 |
137 | # Regression
138 | pxy = pxy.sigmoid() * 2 - 0.5
139 | pwh = (pwh.sigmoid() * 2) ** 2 * anchors[i]
140 | pbox = torch.cat((pxy, pwh), 1) # predicted box
141 | iou = bbox_iou(pbox, tbox[i], CIoU=True).squeeze() # iou(prediction, target)
142 | lbox += (1.0 - iou).mean() # iou loss
143 |
144 | # Objectness
145 | iou = iou.detach().clamp(0).type(tobj.dtype)
146 | if self.sort_obj_iou:
147 | j = iou.argsort()
148 | b, a, gj, gi, iou = b[j], a[j], gj[j], gi[j], iou[j]
149 | if self.gr < 1:
150 | iou = (1.0 - self.gr) + self.gr * iou
151 | tobj[b, a, gj, gi] = iou # iou ratio
152 |
153 | # Classification
154 | if self.nc > 1: # cls loss (only if multiple classes)
155 | t = torch.full_like(pcls, self.cn, device=self.device) # targets
156 | t[range(n), tcls[i]] = self.cp
157 | lcls += self.BCEcls(pcls, t) # BCE
158 |
159 | # Append targets to text file
160 | # with open('targets.txt', 'a') as file:
161 | # [file.write('%11.5g ' * 4 % tuple(x) + '\n') for x in torch.cat((txy[i], twh[i]), 1)]
162 |
163 | obji = self.BCEobj(pi[..., 4], tobj)
164 | lobj += obji * self.balance[i] # obj loss
165 | if self.autobalance:
166 | self.balance[i] = self.balance[i] * 0.9999 + 0.0001 / obji.detach().item()
167 |
168 | if self.autobalance:
169 | self.balance = [x / self.balance[self.ssi] for x in self.balance]
170 | lbox *= self.hyp['box']
171 | lobj *= self.hyp['obj']
172 | lcls *= self.hyp['cls']
173 | bs = tobj.shape[0] # batch size
174 |
175 | return (lbox + lobj + lcls) * bs, torch.cat((lbox, lobj, lcls)).detach()
176 |
177 | def build_targets(self, p, targets):
178 | # Build targets for compute_loss(), input targets(image,class,x,y,w,h)
179 | na, nt = self.na, targets.shape[0] # number of anchors, targets
180 | tcls, tbox, indices, anch = [], [], [], []
181 | gain = torch.ones(7, device=self.device) # normalized to gridspace gain
182 | ai = torch.arange(na, device=self.device).float().view(na, 1).repeat(1, nt) # same as .repeat_interleave(nt)
183 | targets = torch.cat((targets.repeat(na, 1, 1), ai[..., None]), 2) # append anchor indices
184 |
185 | g = 0.5 # bias
186 | off = torch.tensor(
187 | [
188 | [0, 0],
189 | [1, 0],
190 | [0, 1],
191 | [-1, 0],
192 | [0, -1], # j,k,l,m
193 | # [1, 1], [1, -1], [-1, 1], [-1, -1], # jk,jm,lk,lm
194 | ],
195 | device=self.device).float() * g # offsets
196 |
197 | for i in range(self.nl):
198 | anchors, shape = self.anchors[i], p[i].shape
199 | gain[2:6] = torch.tensor(shape)[[3, 2, 3, 2]] # xyxy gain
200 |
201 | # Match targets to anchors
202 | t = targets * gain # shape(3,n,7)
203 | if nt:
204 | # Matches
205 | r = t[..., 4:6] / anchors[:, None] # wh ratio
206 | j = torch.max(r, 1 / r).max(2)[0] < self.hyp['anchor_t'] # compare
207 | # j = wh_iou(anchors, t[:, 4:6]) > model.hyp['iou_t'] # iou(3,n)=wh_iou(anchors(3,2), gwh(n,2))
208 | t = t[j] # filter
209 |
210 | # Offsets
211 | gxy = t[:, 2:4] # grid xy
212 | gxi = gain[[2, 3]] - gxy # inverse
213 | j, k = ((gxy % 1 < g) & (gxy > 1)).T
214 | l, m = ((gxi % 1 < g) & (gxi > 1)).T
215 | j = torch.stack((torch.ones_like(j), j, k, l, m))
216 | t = t.repeat((5, 1, 1))[j]
217 | offsets = (torch.zeros_like(gxy)[None] + off[:, None])[j]
218 | else:
219 | t = targets[0]
220 | offsets = 0
221 |
222 | # Define
223 | bc, gxy, gwh, a = t.chunk(4, 1) # (image, class), grid xy, grid wh, anchors
224 | a, (b, c) = a.long().view(-1), bc.long().T # anchors, image, class
225 | gij = (gxy - offsets).long()
226 | gi, gj = gij.T # grid indices
227 |
228 | # Append
229 | indices.append((b, a, gj.clamp_(0, shape[2] - 1), gi.clamp_(0, shape[3] - 1))) # image, anchor, grid
230 | tbox.append(torch.cat((gxy - gij, gwh), 1)) # box
231 | anch.append(anchors[a]) # anchors
232 | tcls.append(c) # class
233 |
234 | return tcls, tbox, indices, anch
235 |
--------------------------------------------------------------------------------
/utils/segment/__init__.py:
--------------------------------------------------------------------------------
1 | # init
--------------------------------------------------------------------------------
/utils/segment/__pycache__/__init__.cpython-310.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MuhammadMoinFaisal/yolov7-segmentation-with-DeepSORT-Tracking/989fb3a9655ec5e263da760edc3c033045329fa3/utils/segment/__pycache__/__init__.cpython-310.pyc
--------------------------------------------------------------------------------
/utils/segment/__pycache__/general.cpython-310.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MuhammadMoinFaisal/yolov7-segmentation-with-DeepSORT-Tracking/989fb3a9655ec5e263da760edc3c033045329fa3/utils/segment/__pycache__/general.cpython-310.pyc
--------------------------------------------------------------------------------
/utils/segment/__pycache__/plots.cpython-310.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MuhammadMoinFaisal/yolov7-segmentation-with-DeepSORT-Tracking/989fb3a9655ec5e263da760edc3c033045329fa3/utils/segment/__pycache__/plots.cpython-310.pyc
--------------------------------------------------------------------------------
/utils/segment/augmentations.py:
--------------------------------------------------------------------------------
1 | # YOLOv5 🚀 by Ultralytics, GPL-3.0 license
2 | """
3 | Image augmentation functions
4 | """
5 |
6 | import math
7 | import random
8 |
9 | import cv2
10 | import numpy as np
11 |
12 | from ..augmentations import box_candidates
13 | from ..general import resample_segments, segment2box
14 |
15 |
16 | def mixup(im, labels, segments, im2, labels2, segments2):
17 | # Applies MixUp augmentation https://arxiv.org/pdf/1710.09412.pdf
18 | r = np.random.beta(32.0, 32.0) # mixup ratio, alpha=beta=32.0
19 | im = (im * r + im2 * (1 - r)).astype(np.uint8)
20 | labels = np.concatenate((labels, labels2), 0)
21 | segments = np.concatenate((segments, segments2), 0)
22 | return im, labels, segments
23 |
24 |
25 | def random_perspective(im,
26 | targets=(),
27 | segments=(),
28 | degrees=10,
29 | translate=.1,
30 | scale=.1,
31 | shear=10,
32 | perspective=0.0,
33 | border=(0, 0)):
34 | # torchvision.transforms.RandomAffine(degrees=(-10, 10), translate=(.1, .1), scale=(.9, 1.1), shear=(-10, 10))
35 | # targets = [cls, xyxy]
36 |
37 | height = im.shape[0] + border[0] * 2 # shape(h,w,c)
38 | width = im.shape[1] + border[1] * 2
39 |
40 | # Center
41 | C = np.eye(3)
42 | C[0, 2] = -im.shape[1] / 2 # x translation (pixels)
43 | C[1, 2] = -im.shape[0] / 2 # y translation (pixels)
44 |
45 | # Perspective
46 | P = np.eye(3)
47 | P[2, 0] = random.uniform(-perspective, perspective) # x perspective (about y)
48 | P[2, 1] = random.uniform(-perspective, perspective) # y perspective (about x)
49 |
50 | # Rotation and Scale
51 | R = np.eye(3)
52 | a = random.uniform(-degrees, degrees)
53 | # a += random.choice([-180, -90, 0, 90]) # add 90deg rotations to small rotations
54 | s = random.uniform(1 - scale, 1 + scale)
55 | # s = 2 ** random.uniform(-scale, scale)
56 | R[:2] = cv2.getRotationMatrix2D(angle=a, center=(0, 0), scale=s)
57 |
58 | # Shear
59 | S = np.eye(3)
60 | S[0, 1] = math.tan(random.uniform(-shear, shear) * math.pi / 180) # x shear (deg)
61 | S[1, 0] = math.tan(random.uniform(-shear, shear) * math.pi / 180) # y shear (deg)
62 |
63 | # Translation
64 | T = np.eye(3)
65 | T[0, 2] = (random.uniform(0.5 - translate, 0.5 + translate) * width) # x translation (pixels)
66 | T[1, 2] = (random.uniform(0.5 - translate, 0.5 + translate) * height) # y translation (pixels)
67 |
68 | # Combined rotation matrix
69 | M = T @ S @ R @ P @ C # order of operations (right to left) is IMPORTANT
70 | if (border[0] != 0) or (border[1] != 0) or (M != np.eye(3)).any(): # image changed
71 | if perspective:
72 | im = cv2.warpPerspective(im, M, dsize=(width, height), borderValue=(114, 114, 114))
73 | else: # affine
74 | im = cv2.warpAffine(im, M[:2], dsize=(width, height), borderValue=(114, 114, 114))
75 |
76 | # Visualize
77 | # import matplotlib.pyplot as plt
78 | # ax = plt.subplots(1, 2, figsize=(12, 6))[1].ravel()
79 | # ax[0].imshow(im[:, :, ::-1]) # base
80 | # ax[1].imshow(im2[:, :, ::-1]) # warped
81 |
82 | # Transform label coordinates
83 | n = len(targets)
84 | new_segments = []
85 | if n:
86 | new = np.zeros((n, 4))
87 | segments = resample_segments(segments) # upsample
88 | for i, segment in enumerate(segments):
89 | xy = np.ones((len(segment), 3))
90 | xy[:, :2] = segment
91 | xy = xy @ M.T # transform
92 | xy = (xy[:, :2] / xy[:, 2:3] if perspective else xy[:, :2]) # perspective rescale or affine
93 |
94 | # clip
95 | new[i] = segment2box(xy, width, height)
96 | new_segments.append(xy)
97 |
98 | # filter candidates
99 | i = box_candidates(box1=targets[:, 1:5].T * s, box2=new.T, area_thr=0.01)
100 | targets = targets[i]
101 | targets[:, 1:5] = new[i]
102 | new_segments = np.array(new_segments)[i]
103 |
104 | return im, targets, new_segments
105 |
--------------------------------------------------------------------------------
/utils/segment/general.py:
--------------------------------------------------------------------------------
1 | import cv2
2 | import torch
3 | import torch.nn.functional as F
4 |
5 |
6 | def crop(masks, boxes):
7 | """
8 | "Crop" predicted masks by zeroing out everything not in the predicted bbox.
9 | Vectorized by Chong (thanks Chong).
10 |
11 | Args:
12 | - masks should be a size [h, w, n] tensor of masks
13 | - boxes should be a size [n, 4] tensor of bbox coords in relative point form
14 | """
15 |
16 | n, h, w = masks.shape
17 | x1, y1, x2, y2 = torch.chunk(boxes[:, :, None], 4, 1) # x1 shape(1,1,n)
18 | r = torch.arange(w, device=masks.device, dtype=x1.dtype)[None, None, :] # rows shape(1,w,1)
19 | c = torch.arange(h, device=masks.device, dtype=x1.dtype)[None, :, None] # cols shape(h,1,1)
20 |
21 | return masks * ((r >= x1) * (r < x2) * (c >= y1) * (c < y2))
22 |
23 |
24 | def process_mask_upsample(protos, masks_in, bboxes, shape):
25 | """
26 | Crop after upsample.
27 | proto_out: [mask_dim, mask_h, mask_w]
28 | out_masks: [n, mask_dim], n is number of masks after nms
29 | bboxes: [n, 4], n is number of masks after nms
30 | shape:input_image_size, (h, w)
31 |
32 | return: h, w, n
33 | """
34 |
35 | c, mh, mw = protos.shape # CHW
36 | masks = (masks_in @ protos.float().view(c, -1)).sigmoid().view(-1, mh, mw)
37 | masks = F.interpolate(masks[None], shape, mode='bilinear', align_corners=False)[0] # CHW
38 | masks = crop(masks, bboxes) # CHW
39 | return masks.gt_(0.5)
40 |
41 |
42 | def process_mask(protos, masks_in, bboxes, shape, upsample=False):
43 | """
44 | Crop before upsample.
45 | proto_out: [mask_dim, mask_h, mask_w]
46 | out_masks: [n, mask_dim], n is number of masks after nms
47 | bboxes: [n, 4], n is number of masks after nms
48 | shape:input_image_size, (h, w)
49 |
50 | return: h, w, n
51 | """
52 |
53 | c, mh, mw = protos.shape # CHW
54 | ih, iw = shape
55 | masks = (masks_in @ protos.float().view(c, -1)).sigmoid().view(-1, mh, mw) # CHW
56 |
57 | downsampled_bboxes = bboxes.clone()
58 | downsampled_bboxes[:, 0] *= mw / iw
59 | downsampled_bboxes[:, 2] *= mw / iw
60 | downsampled_bboxes[:, 3] *= mh / ih
61 | downsampled_bboxes[:, 1] *= mh / ih
62 |
63 | masks = crop(masks, downsampled_bboxes) # CHW
64 | if upsample:
65 | masks = F.interpolate(masks[None], shape, mode='bilinear', align_corners=False)[0] # CHW
66 | return masks.gt_(0.5)
67 |
68 |
69 | def scale_masks(img1_shape, masks, img0_shape, ratio_pad=None):
70 | """
71 | img1_shape: model input shape, [h, w]
72 | img0_shape: origin pic shape, [h, w, 3]
73 | masks: [h, w, num]
74 | resize for the most time
75 | """
76 | # Rescale coords (xyxy) from img1_shape to img0_shape
77 | if ratio_pad is None: # calculate from img0_shape
78 | gain = min(img1_shape[0] / img0_shape[0], img1_shape[1] / img0_shape[1]) # gain = old / new
79 | pad = (img1_shape[1] - img0_shape[1] * gain) / 2, (img1_shape[0] - img0_shape[0] * gain) / 2 # wh padding
80 | else:
81 | gain = ratio_pad[0][0]
82 | pad = ratio_pad[1]
83 | tl_pad = int(pad[1]), int(pad[0]) # y, x
84 | br_pad = int(img1_shape[0] - pad[1]), int(img1_shape[1] - pad[0])
85 |
86 | if len(masks.shape) < 2:
87 | raise ValueError(f'"len of masks shape" should be 2 or 3, but got {len(masks.shape)}')
88 | # masks_h, masks_w, n
89 | masks = masks[tl_pad[0]:br_pad[0], tl_pad[1]:br_pad[1]]
90 | # 1, n, masks_h, masks_w
91 | # masks = masks.permute(2, 0, 1).contiguous()[None, :]
92 | # # shape = [1, n, masks_h, masks_w] after F.interpolate, so take first element
93 | # masks = F.interpolate(masks, img0_shape[:2], mode='bilinear', align_corners=False)[0]
94 | # masks = masks.permute(1, 2, 0).contiguous()
95 | # masks_h, masks_w, n
96 | masks = cv2.resize(masks, (img0_shape[1], img0_shape[0]))
97 |
98 | # keepdim
99 | if len(masks.shape) == 2:
100 | masks = masks[:, :, None]
101 |
102 | return masks
103 |
104 |
105 | def mask_iou(mask1, mask2, eps=1e-7):
106 | """
107 | mask1: [N, n] m1 means number of predicted objects
108 | mask2: [M, n] m2 means number of gt objects
109 | Note: n means image_w x image_h
110 |
111 | return: masks iou, [N, M]
112 | """
113 | intersection = torch.matmul(mask1, mask2.t()).clamp(0)
114 | union = (mask1.sum(1)[:, None] + mask2.sum(1)[None]) - intersection # (area1 + area2) - intersection
115 | return intersection / (union + eps)
116 |
117 |
118 | def masks_iou(mask1, mask2, eps=1e-7):
119 | """
120 | mask1: [N, n] m1 means number of predicted objects
121 | mask2: [N, n] m2 means number of gt objects
122 | Note: n means image_w x image_h
123 |
124 | return: masks iou, (N, )
125 | """
126 | intersection = (mask1 * mask2).sum(1).clamp(0) # (N, )
127 | union = (mask1.sum(1) + mask2.sum(1))[None] - intersection # (area1 + area2) - intersection
128 | return intersection / (union + eps)
129 |
--------------------------------------------------------------------------------
/utils/segment/loss.py:
--------------------------------------------------------------------------------
1 | import torch
2 | import torch.nn as nn
3 | import torch.nn.functional as F
4 |
5 | from ..general import xywh2xyxy
6 | from ..loss import FocalLoss, smooth_BCE
7 | from ..metrics import bbox_iou
8 | from ..torch_utils import de_parallel
9 | from .general import crop
10 |
11 |
12 | class ComputeLoss:
13 | # Compute losses
14 | def __init__(self, model, autobalance=False, overlap=False):
15 | self.sort_obj_iou = False
16 | self.overlap = overlap
17 | device = next(model.parameters()).device # get model device
18 | h = model.hyp # hyperparameters
19 | self.device = device
20 |
21 | # Define criteria
22 | BCEcls = nn.BCEWithLogitsLoss(pos_weight=torch.tensor([h['cls_pw']], device=device))
23 | BCEobj = nn.BCEWithLogitsLoss(pos_weight=torch.tensor([h['obj_pw']], device=device))
24 |
25 | # Class label smoothing https://arxiv.org/pdf/1902.04103.pdf eqn 3
26 | self.cp, self.cn = smooth_BCE(eps=h.get('label_smoothing', 0.0)) # positive, negative BCE targets
27 |
28 | # Focal loss
29 | g = h['fl_gamma'] # focal loss gamma
30 | if g > 0:
31 | BCEcls, BCEobj = FocalLoss(BCEcls, g), FocalLoss(BCEobj, g)
32 |
33 | m = de_parallel(model).model[-1] # Detect() module
34 | self.balance = {3: [4.0, 1.0, 0.4]}.get(m.nl, [4.0, 1.0, 0.25, 0.06, 0.02]) # P3-P7
35 | self.ssi = list(m.stride).index(16) if autobalance else 0 # stride 16 index
36 | self.BCEcls, self.BCEobj, self.gr, self.hyp, self.autobalance = BCEcls, BCEobj, 1.0, h, autobalance
37 | self.na = m.na # number of anchors
38 | self.nc = m.nc # number of classes
39 | self.nl = m.nl # number of layers
40 | self.nm = m.nm # number of masks
41 | self.anchors = m.anchors
42 | self.device = device
43 |
44 | def __call__(self, preds, targets, masks): # predictions, targets, model
45 | p, proto = preds
46 | bs, nm, mask_h, mask_w = proto.shape # batch size, number of masks, mask height, mask width
47 | lcls = torch.zeros(1, device=self.device)
48 | lbox = torch.zeros(1, device=self.device)
49 | lobj = torch.zeros(1, device=self.device)
50 | lseg = torch.zeros(1, device=self.device)
51 | tcls, tbox, indices, anchors, tidxs, xywhn = self.build_targets(p, targets) # targets
52 |
53 | # Losses
54 | for i, pi in enumerate(p): # layer index, layer predictions
55 | b, a, gj, gi = indices[i] # image, anchor, gridy, gridx
56 | tobj = torch.zeros(pi.shape[:4], dtype=pi.dtype, device=self.device) # target obj
57 |
58 | n = b.shape[0] # number of targets
59 | if n:
60 | pxy, pwh, _, pcls, pmask = pi[b, a, gj, gi].split((2, 2, 1, self.nc, nm), 1) # subset of predictions
61 |
62 | # Box regression
63 | pxy = pxy.sigmoid() * 2 - 0.5
64 | pwh = (pwh.sigmoid() * 2) ** 2 * anchors[i]
65 | pbox = torch.cat((pxy, pwh), 1) # predicted box
66 | iou = bbox_iou(pbox, tbox[i], CIoU=True).squeeze() # iou(prediction, target)
67 | lbox += (1.0 - iou).mean() # iou loss
68 |
69 | # Objectness
70 | iou = iou.detach().clamp(0).type(tobj.dtype)
71 | if self.sort_obj_iou:
72 | j = iou.argsort()
73 | b, a, gj, gi, iou = b[j], a[j], gj[j], gi[j], iou[j]
74 | if self.gr < 1:
75 | iou = (1.0 - self.gr) + self.gr * iou
76 | tobj[b, a, gj, gi] = iou # iou ratio
77 |
78 | # Classification
79 | if self.nc > 1: # cls loss (only if multiple classes)
80 | t = torch.full_like(pcls, self.cn, device=self.device) # targets
81 | t[range(n), tcls[i]] = self.cp
82 | lcls += self.BCEcls(pcls, t) # BCE
83 |
84 | # Mask regression
85 | if tuple(masks.shape[-2:]) != (mask_h, mask_w): # downsample
86 | masks = F.interpolate(masks[None], (mask_h, mask_w), mode="bilinear", align_corners=False)[0]
87 | marea = xywhn[i][:, 2:].prod(1) # mask width, height normalized
88 | mxyxy = xywh2xyxy(xywhn[i] * torch.tensor([mask_w, mask_h, mask_w, mask_h], device=self.device))
89 | for bi in b.unique():
90 | j = b == bi # matching index
91 | if self.overlap:
92 | mask_gti = torch.where(masks[bi][None] == tidxs[i][j].view(-1, 1, 1), 1.0, 0.0)
93 | else:
94 | mask_gti = masks[tidxs[i]][j]
95 | lseg += self.single_mask_loss(mask_gti, pmask[j], proto[bi], mxyxy[j], marea[j])
96 |
97 | obji = self.BCEobj(pi[..., 4], tobj)
98 | lobj += obji * self.balance[i] # obj loss
99 | if self.autobalance:
100 | self.balance[i] = self.balance[i] * 0.9999 + 0.0001 / obji.detach().item()
101 |
102 | if self.autobalance:
103 | self.balance = [x / self.balance[self.ssi] for x in self.balance]
104 | lbox *= self.hyp["box"]
105 | lobj *= self.hyp["obj"]
106 | lcls *= self.hyp["cls"]
107 | lseg *= self.hyp["box"] / bs
108 |
109 | loss = lbox + lobj + lcls + lseg
110 | return loss * bs, torch.cat((lbox, lseg, lobj, lcls)).detach()
111 |
112 | def single_mask_loss(self, gt_mask, pred, proto, xyxy, area):
113 | # Mask loss for one image
114 | pred_mask = (pred @ proto.view(self.nm, -1)).view(-1, *proto.shape[1:]) # (n,32) @ (32,80,80) -> (n,80,80)
115 | loss = F.binary_cross_entropy_with_logits(pred_mask, gt_mask, reduction="none")
116 | return (crop(loss, xyxy).mean(dim=(1, 2)) / area).mean()
117 |
118 | def build_targets(self, p, targets):
119 | # Build targets for compute_loss(), input targets(image,class,x,y,w,h)
120 | na, nt = self.na, targets.shape[0] # number of anchors, targets
121 | tcls, tbox, indices, anch, tidxs, xywhn = [], [], [], [], [], []
122 | gain = torch.ones(8, device=self.device) # normalized to gridspace gain
123 | ai = torch.arange(na, device=self.device).float().view(na, 1).repeat(1, nt) # same as .repeat_interleave(nt)
124 | if self.overlap:
125 | batch = p[0].shape[0]
126 | ti = []
127 | for i in range(batch):
128 | num = (targets[:, 0] == i).sum() # find number of targets of each image
129 | ti.append(torch.arange(num, device=self.device).float().view(1, num).repeat(na, 1) + 1) # (na, num)
130 | ti = torch.cat(ti, 1) # (na, nt)
131 | else:
132 | ti = torch.arange(nt, device=self.device).float().view(1, nt).repeat(na, 1)
133 | targets = torch.cat((targets.repeat(na, 1, 1), ai[..., None], ti[..., None]), 2) # append anchor indices
134 |
135 | g = 0.5 # bias
136 | off = torch.tensor(
137 | [
138 | [0, 0],
139 | [1, 0],
140 | [0, 1],
141 | [-1, 0],
142 | [0, -1], # j,k,l,m
143 | # [1, 1], [1, -1], [-1, 1], [-1, -1], # jk,jm,lk,lm
144 | ],
145 | device=self.device).float() * g # offsets
146 |
147 | for i in range(self.nl):
148 | anchors, shape = self.anchors[i], p[i].shape
149 | gain[2:6] = torch.tensor(shape)[[3, 2, 3, 2]] # xyxy gain
150 |
151 | # Match targets to anchors
152 | t = targets * gain # shape(3,n,7)
153 | if nt:
154 | # Matches
155 | r = t[..., 4:6] / anchors[:, None] # wh ratio
156 | j = torch.max(r, 1 / r).max(2)[0] < self.hyp['anchor_t'] # compare
157 | # j = wh_iou(anchors, t[:, 4:6]) > model.hyp['iou_t'] # iou(3,n)=wh_iou(anchors(3,2), gwh(n,2))
158 | t = t[j] # filter
159 |
160 | # Offsets
161 | gxy = t[:, 2:4] # grid xy
162 | gxi = gain[[2, 3]] - gxy # inverse
163 | j, k = ((gxy % 1 < g) & (gxy > 1)).T
164 | l, m = ((gxi % 1 < g) & (gxi > 1)).T
165 | j = torch.stack((torch.ones_like(j), j, k, l, m))
166 | t = t.repeat((5, 1, 1))[j]
167 | offsets = (torch.zeros_like(gxy)[None] + off[:, None])[j]
168 | else:
169 | t = targets[0]
170 | offsets = 0
171 |
172 | # Define
173 | bc, gxy, gwh, at = t.chunk(4, 1) # (image, class), grid xy, grid wh, anchors
174 | (a, tidx), (b, c) = at.long().T, bc.long().T # anchors, image, class
175 | gij = (gxy - offsets).long()
176 | gi, gj = gij.T # grid indices
177 |
178 | # Append
179 | indices.append((b, a, gj.clamp_(0, shape[2] - 1), gi.clamp_(0, shape[3] - 1))) # image, anchor, grid
180 | tbox.append(torch.cat((gxy - gij, gwh), 1)) # box
181 | anch.append(anchors[a]) # anchors
182 | tcls.append(c) # class
183 | tidxs.append(tidx)
184 | xywhn.append(torch.cat((gxy, gwh), 1) / gain[2:6]) # xywh normalized
185 |
186 | return tcls, tbox, indices, anch, tidxs, xywhn
187 |
--------------------------------------------------------------------------------
/utils/segment/metrics.py:
--------------------------------------------------------------------------------
1 | # YOLOv5 🚀 by Ultralytics, GPL-3.0 license
2 | """
3 | Model validation metrics
4 | """
5 |
6 | import numpy as np
7 |
8 | from ..metrics import ap_per_class
9 |
10 |
11 | def fitness(x):
12 | # Model fitness as a weighted combination of metrics
13 | w = [0.0, 0.0, 0.1, 0.9, 0.0, 0.0, 0.1, 0.9]
14 | return (x[:, :8] * w).sum(1)
15 |
16 |
17 | def ap_per_class_box_and_mask(
18 | tp_m,
19 | tp_b,
20 | conf,
21 | pred_cls,
22 | target_cls,
23 | plot=False,
24 | save_dir=".",
25 | names=(),
26 | ):
27 | """
28 | Args:
29 | tp_b: tp of boxes.
30 | tp_m: tp of masks.
31 | other arguments see `func: ap_per_class`.
32 | """
33 | results_boxes = ap_per_class(tp_b,
34 | conf,
35 | pred_cls,
36 | target_cls,
37 | plot=plot,
38 | save_dir=save_dir,
39 | names=names,
40 | prefix="Box")[2:]
41 | results_masks = ap_per_class(tp_m,
42 | conf,
43 | pred_cls,
44 | target_cls,
45 | plot=plot,
46 | save_dir=save_dir,
47 | names=names,
48 | prefix="Mask")[2:]
49 |
50 | results = {
51 | "boxes": {
52 | "p": results_boxes[0],
53 | "r": results_boxes[1],
54 | "ap": results_boxes[3],
55 | "f1": results_boxes[2],
56 | "ap_class": results_boxes[4]},
57 | "masks": {
58 | "p": results_masks[0],
59 | "r": results_masks[1],
60 | "ap": results_masks[3],
61 | "f1": results_masks[2],
62 | "ap_class": results_masks[4]}}
63 | return results
64 |
65 |
66 | class Metric:
67 |
68 | def __init__(self) -> None:
69 | self.p = [] # (nc, )
70 | self.r = [] # (nc, )
71 | self.f1 = [] # (nc, )
72 | self.all_ap = [] # (nc, 10)
73 | self.ap_class_index = [] # (nc, )
74 |
75 | @property
76 | def ap50(self):
77 | """AP@0.5 of all classes.
78 | Return:
79 | (nc, ) or [].
80 | """
81 | return self.all_ap[:, 0] if len(self.all_ap) else []
82 |
83 | @property
84 | def ap(self):
85 | """AP@0.5:0.95
86 | Return:
87 | (nc, ) or [].
88 | """
89 | return self.all_ap.mean(1) if len(self.all_ap) else []
90 |
91 | @property
92 | def mp(self):
93 | """mean precision of all classes.
94 | Return:
95 | float.
96 | """
97 | return self.p.mean() if len(self.p) else 0.0
98 |
99 | @property
100 | def mr(self):
101 | """mean recall of all classes.
102 | Return:
103 | float.
104 | """
105 | return self.r.mean() if len(self.r) else 0.0
106 |
107 | @property
108 | def map50(self):
109 | """Mean AP@0.5 of all classes.
110 | Return:
111 | float.
112 | """
113 | return self.all_ap[:, 0].mean() if len(self.all_ap) else 0.0
114 |
115 | @property
116 | def map(self):
117 | """Mean AP@0.5:0.95 of all classes.
118 | Return:
119 | float.
120 | """
121 | return self.all_ap.mean() if len(self.all_ap) else 0.0
122 |
123 | def mean_results(self):
124 | """Mean of results, return mp, mr, map50, map"""
125 | return (self.mp, self.mr, self.map50, self.map)
126 |
127 | def class_result(self, i):
128 | """class-aware result, return p[i], r[i], ap50[i], ap[i]"""
129 | return (self.p[i], self.r[i], self.ap50[i], self.ap[i])
130 |
131 | def get_maps(self, nc):
132 | maps = np.zeros(nc) + self.map
133 | for i, c in enumerate(self.ap_class_index):
134 | maps[c] = self.ap[i]
135 | return maps
136 |
137 | def update(self, results):
138 | """
139 | Args:
140 | results: tuple(p, r, ap, f1, ap_class)
141 | """
142 | p, r, all_ap, f1, ap_class_index = results
143 | self.p = p
144 | self.r = r
145 | self.all_ap = all_ap
146 | self.f1 = f1
147 | self.ap_class_index = ap_class_index
148 |
149 |
150 | class Metrics:
151 | """Metric for boxes and masks."""
152 |
153 | def __init__(self) -> None:
154 | self.metric_box = Metric()
155 | self.metric_mask = Metric()
156 |
157 | def update(self, results):
158 | """
159 | Args:
160 | results: Dict{'boxes': Dict{}, 'masks': Dict{}}
161 | """
162 | self.metric_box.update(list(results["boxes"].values()))
163 | self.metric_mask.update(list(results["masks"].values()))
164 |
165 | def mean_results(self):
166 | return self.metric_box.mean_results() + self.metric_mask.mean_results()
167 |
168 | def class_result(self, i):
169 | return self.metric_box.class_result(i) + self.metric_mask.class_result(i)
170 |
171 | def get_maps(self, nc):
172 | return self.metric_box.get_maps(nc) + self.metric_mask.get_maps(nc)
173 |
174 | @property
175 | def ap_class_index(self):
176 | # boxes and masks have the same ap_class_index
177 | return self.metric_box.ap_class_index
178 |
179 |
180 | KEYS = [
181 | "train/box_loss",
182 | "train/seg_loss", # train loss
183 | "train/obj_loss",
184 | "train/cls_loss",
185 | "metrics/precision(B)",
186 | "metrics/recall(B)",
187 | "metrics/mAP_0.5(B)",
188 | "metrics/mAP_0.5:0.95(B)", # metrics
189 | "metrics/precision(M)",
190 | "metrics/recall(M)",
191 | "metrics/mAP_0.5(M)",
192 | "metrics/mAP_0.5:0.95(M)", # metrics
193 | "val/box_loss",
194 | "val/seg_loss", # val loss
195 | "val/obj_loss",
196 | "val/cls_loss",
197 | "x/lr0",
198 | "x/lr1",
199 | "x/lr2",]
200 |
201 | BEST_KEYS = [
202 | "best/epoch",
203 | "best/precision(B)",
204 | "best/recall(B)",
205 | "best/mAP_0.5(B)",
206 | "best/mAP_0.5:0.95(B)",
207 | "best/precision(M)",
208 | "best/recall(M)",
209 | "best/mAP_0.5(M)",
210 | "best/mAP_0.5:0.95(M)",]
211 |
--------------------------------------------------------------------------------
/utils/segment/plots.py:
--------------------------------------------------------------------------------
1 | import contextlib
2 | import math
3 | from pathlib import Path
4 |
5 | import cv2
6 | import matplotlib.pyplot as plt
7 | import numpy as np
8 | import pandas as pd
9 | import torch
10 |
11 | from .. import threaded
12 | from ..general import xywh2xyxy
13 | from ..plots import Annotator, colors
14 |
15 |
16 | def plot_masks(img, masks, colors, alpha=0.5):
17 | """
18 | Args:
19 | img (tensor): img is in cuda, shape: [3, h, w], range: [0, 1]
20 | masks (tensor): predicted masks on cuda, shape: [n, h, w]
21 | colors (List[List[Int]]): colors for predicted masks, [[r, g, b] * n]
22 | Return:
23 | ndarray: img after draw masks, shape: [h, w, 3]
24 |
25 | transform colors and send img_gpu to cpu for the most time.
26 | """
27 | img_gpu = img.clone()
28 | num_masks = len(masks)
29 | if num_masks == 0:
30 | return img.permute(1, 2, 0).contiguous().cpu().numpy() * 255
31 |
32 | # [n, 1, 1, 3]
33 | # faster this way to transform colors
34 | colors = torch.tensor(colors, device=img.device).float() / 255.0
35 | colors = colors[:, None, None, :]
36 | # [n, h, w, 1]
37 | masks = masks[:, :, :, None]
38 | masks_color = masks.repeat(1, 1, 1, 3) * colors * alpha
39 | inv_alph_masks = masks * (-alpha) + 1
40 | masks_color_summand = masks_color[0]
41 | if num_masks > 1:
42 | inv_alph_cumul = inv_alph_masks[:(num_masks - 1)].cumprod(dim=0)
43 | masks_color_cumul = masks_color[1:] * inv_alph_cumul
44 | masks_color_summand += masks_color_cumul.sum(dim=0)
45 |
46 | # print(inv_alph_masks.prod(dim=0).shape) # [h, w, 1]
47 | img_gpu = img_gpu.flip(dims=[0]) # filp channel for opencv
48 | img_gpu = img_gpu.permute(1, 2, 0).contiguous()
49 | # [h, w, 3]
50 | img_gpu = img_gpu * inv_alph_masks.prod(dim=0) + masks_color_summand
51 | return (img_gpu * 255).byte().cpu().numpy()
52 |
53 |
54 | @threaded
55 | def plot_images_and_masks(images, targets, masks, paths=None, fname='images.jpg', names=None):
56 | # Plot image grid with labels
57 | if isinstance(images, torch.Tensor):
58 | images = images.cpu().float().numpy()
59 | if isinstance(targets, torch.Tensor):
60 | targets = targets.cpu().numpy()
61 | if isinstance(masks, torch.Tensor):
62 | masks = masks.cpu().numpy().astype(int)
63 |
64 | max_size = 1920 # max image size
65 | max_subplots = 16 # max image subplots, i.e. 4x4
66 | bs, _, h, w = images.shape # batch size, _, height, width
67 | bs = min(bs, max_subplots) # limit plot images
68 | ns = np.ceil(bs ** 0.5) # number of subplots (square)
69 | if np.max(images[0]) <= 1:
70 | images *= 255 # de-normalise (optional)
71 |
72 | # Build Image
73 | mosaic = np.full((int(ns * h), int(ns * w), 3), 255, dtype=np.uint8) # init
74 | for i, im in enumerate(images):
75 | if i == max_subplots: # if last batch has fewer images than we expect
76 | break
77 | x, y = int(w * (i // ns)), int(h * (i % ns)) # block origin
78 | im = im.transpose(1, 2, 0)
79 | mosaic[y:y + h, x:x + w, :] = im
80 |
81 | # Resize (optional)
82 | scale = max_size / ns / max(h, w)
83 | if scale < 1:
84 | h = math.ceil(scale * h)
85 | w = math.ceil(scale * w)
86 | mosaic = cv2.resize(mosaic, tuple(int(x * ns) for x in (w, h)))
87 |
88 | # Annotate
89 | fs = int((h + w) * ns * 0.01) # font size
90 | annotator = Annotator(mosaic, line_width=round(fs / 10), font_size=fs, pil=True, example=names)
91 | for i in range(i + 1):
92 | x, y = int(w * (i // ns)), int(h * (i % ns)) # block origin
93 | annotator.rectangle([x, y, x + w, y + h], None, (255, 255, 255), width=2) # borders
94 | if paths:
95 | annotator.text((x + 5, y + 5 + h), text=Path(paths[i]).name[:40], txt_color=(220, 220, 220)) # filenames
96 | if len(targets) > 0:
97 | idx = targets[:, 0] == i
98 | ti = targets[idx] # image targets
99 |
100 | boxes = xywh2xyxy(ti[:, 2:6]).T
101 | classes = ti[:, 1].astype('int')
102 | labels = ti.shape[1] == 6 # labels if no conf column
103 | conf = None if labels else ti[:, 6] # check for confidence presence (label vs pred)
104 |
105 | if boxes.shape[1]:
106 | if boxes.max() <= 1.01: # if normalized with tolerance 0.01
107 | boxes[[0, 2]] *= w # scale to pixels
108 | boxes[[1, 3]] *= h
109 | elif scale < 1: # absolute coords need scale if image scales
110 | boxes *= scale
111 | boxes[[0, 2]] += x
112 | boxes[[1, 3]] += y
113 | for j, box in enumerate(boxes.T.tolist()):
114 | cls = classes[j]
115 | color = colors(cls)
116 | cls = names[cls] if names else cls
117 | if labels or conf[j] > 0.25: # 0.25 conf thresh
118 | label = f'{cls}' if labels else f'{cls} {conf[j]:.1f}'
119 | annotator.box_label(box, label, color=color)
120 |
121 | # Plot masks
122 | if len(masks):
123 | if masks.max() > 1.0: # mean that masks are overlap
124 | image_masks = masks[[i]] # (1, 640, 640)
125 | nl = len(ti)
126 | index = np.arange(nl).reshape(nl, 1, 1) + 1
127 | image_masks = np.repeat(image_masks, nl, axis=0)
128 | image_masks = np.where(image_masks == index, 1.0, 0.0)
129 | else:
130 | image_masks = masks[idx]
131 |
132 | im = np.asarray(annotator.im).copy()
133 | for j, box in enumerate(boxes.T.tolist()):
134 | if labels or conf[j] > 0.25: # 0.25 conf thresh
135 | color = colors(classes[j])
136 | mh, mw = image_masks[j].shape
137 | if mh != h or mw != w:
138 | mask = image_masks[j].astype(np.uint8)
139 | mask = cv2.resize(mask, (w, h))
140 | mask = mask.astype(np.bool)
141 | else:
142 | mask = image_masks[j].astype(np.bool)
143 | with contextlib.suppress(Exception):
144 | im[y:y + h, x:x + w, :][mask] = im[y:y + h, x:x + w, :][mask] * 0.4 + np.array(color) * 0.6
145 | annotator.fromarray(im)
146 | annotator.im.save(fname) # save
147 |
148 |
149 | def plot_results_with_masks(file="path/to/results.csv", dir="", best=True):
150 | # Plot training results.csv. Usage: from utils.plots import *; plot_results('path/to/results.csv')
151 | save_dir = Path(file).parent if file else Path(dir)
152 | fig, ax = plt.subplots(2, 8, figsize=(18, 6), tight_layout=True)
153 | ax = ax.ravel()
154 | files = list(save_dir.glob("results*.csv"))
155 | assert len(files), f"No results.csv files found in {save_dir.resolve()}, nothing to plot."
156 | for f in files:
157 | try:
158 | data = pd.read_csv(f)
159 | index = np.argmax(
160 | 0.9 * data.values[:, 8] + 0.1 * data.values[:, 7] + 0.9 * data.values[:, 12] +
161 | 0.1 * data.values[:, 11],)
162 | s = [x.strip() for x in data.columns]
163 | x = data.values[:, 0]
164 | for i, j in enumerate([1, 2, 3, 4, 5, 6, 9, 10, 13, 14, 15, 16, 7, 8, 11, 12]):
165 | y = data.values[:, j]
166 | # y[y == 0] = np.nan # don't show zero values
167 | ax[i].plot(x, y, marker=".", label=f.stem, linewidth=2, markersize=2)
168 | if best:
169 | # best
170 | ax[i].scatter(index, y[index], color="r", label=f"best:{index}", marker="*", linewidth=3)
171 | ax[i].set_title(s[j] + f"\n{round(y[index], 5)}")
172 | else:
173 | # last
174 | ax[i].scatter(x[-1], y[-1], color="r", label="last", marker="*", linewidth=3)
175 | ax[i].set_title(s[j] + f"\n{round(y[-1], 5)}")
176 | # if j in [8, 9, 10]: # share train and val loss y axes
177 | # ax[i].get_shared_y_axes().join(ax[i], ax[i - 5])
178 | except Exception as e:
179 | print(f"Warning: Plotting error for {f}: {e}")
180 | ax[1].legend()
181 | fig.savefig(save_dir / "results.png", dpi=200)
182 | plt.close()
183 |
--------------------------------------------------------------------------------